Search Unity

Certain Logic's Navigation Opensource Framework

Discussion in 'Made With Unity' started by DavidB, Nov 19, 2010.

  1. DavidB

    DavidB

    Joined:
    Dec 13, 2009
    Posts:
    530
    Link to the package: here

    Hello everyone.

    Certain Logic Studios has been working on an Open-Sourced Navigation framework. The package allows users to:
    • Generate and edit navigation grids on arbitrary geometry
    • Save generated navigation grids to a file
    • Load these saved grids to a PathMaster and allow Path Finding Game Agents to pathfind across the generated grids

    We were going to roll our own locomotion engine for this... but I took a second look at UnitySteer 2.0 and to be honest this system is far more robust than anything that we could have come up with in the short term. Arges has outdone himself and darn near perfected the system for Unity users (a huge thanks to him for that of course!... if you haven't seen this project before please do check it out -- http://forum.unity3d.com/threads/64292-UnitySteer-2.0-released?highlight=unitysteer+2.0)

    I have only just scratched the surface of what UnitySteer can do, but I've managed to pull together an extremely crude demo of the framework in it's current state. Figured I'd post a video to let people see.

    http://www.youtube.com/watch?v=dxuZI3LqpvA

    Check it out, this framework is available... but there are still many changes to do. Expect the system to change quite a bit in the near future... and the documentation will also be evolving. I'm releasing it early in case anyone wanted a peek at the code and wanted to tinker with it.

    We'll be offering updates as they arrive through our twitter if you wish to keep an eye on the progress of the package. The link is in my signature. We will also post updates here.

    Cheers!
     
    Last edited: Nov 20, 2010
  2. KITT

    KITT

    Joined:
    Jul 17, 2009
    Posts:
    221
    Sweeet!! Thanks guys.
     
  3. Neodrop

    Neodrop

    Joined:
    Oct 24, 2008
    Posts:
    1,359
    The link to UnitySteer is broken in the first post.
     
  4. DavidB

    DavidB

    Joined:
    Dec 13, 2009
    Posts:
    530
    Wow wierd, not sure how that happened. Thanks for the heads up! Should be fixed now.
     
  5. MrRudak

    MrRudak

    Joined:
    Oct 17, 2010
    Posts:
    159
    Cool
    thNks
     
  6. erudisill

    erudisill

    Joined:
    Oct 4, 2010
    Posts:
    4
    This looks very promising since I'm currently searching for a pathfinding solution to work with UnitySteer. Seems you've done the work for me!

    In my application, I'm developing level geometry procedurally; how easy is it to generate the navmeshes at runtime, and do you have any examples of this in practice.

    Great work, and thanks!

    -Eric
     
  7. cemC

    cemC

    Joined:
    Dec 23, 2010
    Posts:
    214
    i try to make Tower Defence enemy AI . Enemy behave like RTS games. It decide how target closest me and change the target. Also it is my graduation project from university. Please tell me any options or suggestions...

    I use A* pathfinding system and try to modify the AIFollow.cs but i did not sucessful.There are two functions. GetEnemies() create an array which includes "Target" tag of GameObjects. But it is not working.

    Here is my code:

    Code (csharp):
    1.  
    2.  
    3. using UnityEngine;
    4. using System.Collections;
    5.  
    6.  
    7. public class AIFollow : MonoBehaviour {
    8.     //[RequireComponent (typeof(CharacterController))]
    9.     public float speed = 3.0F;
    10.     public float rotationSpeed = 5.0F;
    11.     public float pickNextWaypointDistance = 3.0F;
    12.     public float SearchWaypointFrequency = 0.2F;
    13.     public float maxStop = 3;
    14.    
    15.     public bool continousTargetSearch = false;
    16.     public float targetSearchFrequency = 1.0F;
    17.     private bool canSearchAgain = true;
    18.     public Command command = Command.Stay;
    19.    
    20.     public Transform target;
    21.     private CharacterController controller;
    22.     private AIAnimation animator;
    23.     private Seeker seeker;
    24.    
    25.     public Vector3 myPosition;
    26.     public Transform[] enemies;
    27.     public float distance;
    28.                    
    29.    
    30.     // Make sure there is always a character controller
    31.    
    32.     public enum Command {
    33.         Stay,
    34.         Walk
    35.     }
    36.    
    37.    
    38.    
    39.     public IEnumerator Start () { //public IEnumerator Start ()
    40.        
    41.         waypointPosition = transform.position;
    42.         command = Command.Stay;
    43.         controller = GetComponent (typeof(CharacterController)) as CharacterController;
    44.         Object anim = GetComponent (typeof(AIAnimation));
    45.         animator = anim != null ? anim as AIAnimation : null;
    46.         seeker = GetComponent (typeof(Seeker)) as Seeker;
    47.        
    48.         StartCoroutine (Patrol());
    49.         yield return new WaitForSeconds (Random.value*0.5F);
    50.        
    51.         if (continousTargetSearch) {
    52.             StartCoroutine (SearchPlayer());
    53.         }
    54.        
    55.         [COLOR="red"]//here is the start array operations[/COLOR]
    56.         GetEnemies();    
    57.         myPosition = transform.position;    
    58.         target = FindClosest(enemies);
    59.         distance=Vector3.Distance(target.position,transform.position);
    60.        
    61.         while (true) {
    62.             FindPoint (curpoint);
    63.             yield return new WaitForSeconds (SearchWaypointFrequency);
    64.         }
    65.     }
    66.    
    67.     private Vector3 waypointPosition;
    68.     //private bool continuous = false;
    69.     private Vector3[] points;
    70.     private int curpoint = 0;
    71.    
    72.     public void Update () {
    73.         //Debug.color = Color.blue;
    74.         Debug.DrawLine (transform.position, waypointPosition, Color.blue);
    75.        
    76.         //Stop();
    77.         Start();
    78.         /*GetEnemies();    
    79.         myPosition = transform.position;    
    80.         target = FindClosest(enemies);
    81.         distance=Vector3.Distance(target.position,transform.position);*/
    82.     }
    83.    
    84.     public IEnumerator SearchPlayer () {
    85.         yield return 0;
    86.         while (true) {
    87.             yield return 0;
    88.             while (!canSearchAgain) {
    89.                 yield return 0;
    90.             }
    91.             if (continousTargetSearch) {
    92.                 canSearchAgain = false;
    93.                 seeker.StartPath (transform.position,target.position);
    94.             }
    95.             yield return new WaitForSeconds (targetSearchFrequency);
    96.         }
    97.        
    98.     }
    99.    
    100.     public void PathComplete (Vector3[] newPoints) {
    101.         canSearchAgain = true;
    102.         points = newPoints;
    103.         FindPoint (0);
    104.         command = Command.Walk;
    105.     }
    106.    
    107.     public void PathError () {
    108.         canSearchAgain = true;
    109.     }
    110.    
    111.     public bool HasReachedTarget () {
    112.         return curpoint >= points.Length;
    113.     }
    114.    
    115.     public void FindPoint (int cpoint) {
    116.         curpoint = cpoint;
    117.         if (points == null || points.Length == 0 || curpoint >= points.Length) {   
    118.             waypointPosition = transform.position;
    119.             Stop ();
    120.             return;
    121.         }
    122.        
    123.         if (points.Length == 1) {
    124.             waypointPosition = points[0];
    125.             command = Command.Walk;
    126.             return;
    127.         }
    128.        
    129.         command = Command.Walk;
    130.        
    131.         waypointPosition = points[curpoint];
    132.         Vector3 p = waypointPosition;
    133.         p.y = transform.position.y;
    134.        
    135.         if (curpoint < points.Length - 1) {
    136.             if ((transform.position-p).sqrMagnitude < pickNextWaypointDistance*pickNextWaypointDistance) {
    137.                 curpoint++;
    138.                 FindPoint (curpoint);
    139.             }
    140.            
    141.         } else {
    142.             if ((transform.position-p).sqrMagnitude < maxStop*maxStop) {
    143.                 curpoint++;
    144.                 FindPoint (curpoint);
    145.             }
    146.         }
    147.     }
    148.    
    149.     public IEnumerator Patrol () {
    150.         while (true) {
    151.             if (command == Command.Walk) {
    152.                 MoveTowards(waypointPosition);
    153.             }
    154.            
    155.             yield return 0;
    156.         }
    157.     }
    158.    
    159.     public void Stop () {
    160.         command = Command.Stay;
    161.         if (animator != null) {
    162.             animator.SetSpeed (0.0F);
    163.         }
    164.     }
    165.    
    166.     public void RotateTowards (Vector3 position) {
    167.         if (animator != null) {
    168.             animator.SetSpeed (0.0F);
    169.         }
    170.        
    171.         Vector3 direction = position - transform.position;
    172.         direction.y = 0;
    173.        
    174.         if (curpoint == points.Length - 1  direction.sqrMagnitude < maxStop*maxStop) {
    175.             FindPoint (curpoint);
    176.             return;
    177.         }
    178.        
    179.         if (direction.sqrMagnitude < 0.1F*0.1F) {
    180.             return;
    181.         }
    182.        
    183.         // Rotate towards the target
    184.         transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation(direction), rotationSpeed * Time.deltaTime);
    185.         transform.eulerAngles = new Vector3(0, transform.eulerAngles.y, 0);
    186.     }
    187.    
    188.     public void MoveTowards (Vector3 position) {
    189.         Vector3 direction = position - transform.position;
    190.         direction.y = 0;
    191.        
    192.         if (direction.sqrMagnitude < 0.2F*0.2F) {
    193.             Stop ();
    194.             return;
    195.         }
    196.        
    197.         // Rotate towards the target
    198.         transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation(direction), rotationSpeed * Time.deltaTime);
    199.         transform.eulerAngles = new Vector3(0, transform.eulerAngles.y, 0);
    200.    
    201.         // Modify speed so we slow down when we are not facing the target
    202.         Vector3 forward = transform.TransformDirection(Vector3.forward);
    203.         float speedModifier = Vector3.Dot(forward, direction.normalized);
    204.         speedModifier = Mathf.Clamp01(speedModifier);
    205.        
    206.         // Move the character
    207.         if (controller) {
    208.             direction = forward * speed * speedModifier*speedModifier;
    209.             controller.SimpleMove(direction);
    210.         } else {
    211.             direction = forward * speed * speedModifier*speedModifier;
    212.             transform.Translate (direction*Time.deltaTime,Space.World);
    213.         }
    214.        
    215.         if (animator != null) {
    216.             animator.SetSpeed (speed * speedModifier);
    217.         }
    218.     }
    219.    
    220.     public void GetEnemies(){ [COLOR="red"]// Get enemies from the Scene [/COLOR]
    221.        
    222.         GameObject[] enemyObjects = GameObject.FindGameObjectsWithTag("Target");
    223.        
    224.         Transform[]  enemies = new Transform[enemyObjects.Length];  
    225.        
    226.         for (int i = 0; i < enemyObjects.Length; i++)
    227.         {          
    228.                 enemies[i] = enemyObjects[i].transform;
    229.             Debug.Log("GetEnemies() : count = " + i );
    230.         }
    231.        
    232.         Debug.Log("GetEnemies() : enemy count = " + enemies.Length);
    233.        
    234.     }  
    235.    
    236.     public Transform FindClosest(Transform[] targets) [COLOR="red"]// Find Closest enemy[/COLOR]
    237.         {
    238.             Debug.Log("FindClosest() : ---------------> " +targets.Length);
    239.            
    240.             GameObject[] enemyObjects = GameObject.FindGameObjectsWithTag("Target");
    241.        
    242.             float closestDistance = (enemies[0].position-myPosition).sqrMagnitude;  
    243.            
    244.             int targetNumber=0;
    245.            
    246.             for(int i=1; i<targets.Length ;i++)
    247.             {
    248.                
    249.                 float thisDisatance = (enemies[i].position-myPosition).sqrMagnitude;
    250.                
    251.                     if(thisDisatance<closestDistance)
    252.                     {
    253.                        
    254.                         closestDistance=thisDisatance;
    255.                         targetNumber=i;
    256.                        
    257.                     }  
    258.             }      
    259.                    
    260.             return enemies[targetNumber];
    261.            
    262.         }      
    263.    
    264.     }
    265.  
    266.  
    Shortly, i try to collect the "Targets"(Transform) in array and Enemy must find to closest "Target" which destroyed by enemies. Enemy behave like RTS games. Also it is my graduation project in university :mad: . Please tell me any options or suggestions...
     
  8. DavidB

    DavidB

    Joined:
    Dec 13, 2009
    Posts:
    530
    Odd... this thread didn't highlight for me! My apologies on missing this post. To get the mesh loading at run time is extremely easy... just look into how we currently "load" the meshes. And simply execute the "GenerateMesh()" function in a Start() function. This is a good idea for a feature I think.... to allow the user to select if they want to precalculate the mesh, or generate at runtime. I hadn't considered procedural geometry for some reason! Thanks for the heads up.
     
  9. DavidB

    DavidB

    Joined:
    Dec 13, 2009
    Posts:
    530

    Hello, I'd like to help but I don't really understand what the issue is at the moment. Maybe I can get at the issue if you can answer a few questions for me....

    1) Are you using the CertainLogic Opensource Navigation Framework?
    2) When you say "it doesn't work", what do you mean? What specifically is not working?


    Cheers
     
  10. cemC

    cemC

    Joined:
    Dec 23, 2010
    Posts:
    214
    i am not using CertainLogic. I am using a* pathfinding Arongranberg. And it does not work. Because i do not get "Targets" from the scene in my array...
     
    Last edited: Dec 23, 2010
  11. DavidB

    DavidB

    Joined:
    Dec 13, 2009
    Posts:
    530
    Ah my apologies, I'm not familiar enough with that system to comment. You may want to try asking your question on UnityAnswers, or perhaps in the thread for Aron's pathfinding (http://forum.unity3d.com/threads/67...-Released-(Unity-3-Compatible)?highlight=aron).

    Edit: I see you've already posted for help in that thread, hopefully someone who is familiar with the system can help you out. Good luck!
     
  12. cemC

    cemC

    Joined:
    Dec 23, 2010
    Posts:
    214
    I try to use navmesh generate and i designed this Scene attachment 1 , i applied all the steps of tutorial in Youtube.

    Although i save ***.map file , i can not load this file by using Pathmaster in scene.( Also i load UnitySteer2.0 to my

    project as a package.)

    And when press the play button , unity give me an Error:
    Code (csharp):
    1.  
    2. -->KeyNotFoundException: The given key was not present in the dictionary.
    3. System.Collections.Generic.Dictionary`2[System.String,INavigationMesh].get_Item (System.String key)
    4. PathMaster.GetPath (IPathFinder pathFinder, Vector3 destination) (at Assets/CertainLogic Opensource/Pathfinding/Scripts/Core/PathMaster.cs:26)
    5. PathFinder.FindPath (Vector3 destination) (at Assets/CertainLogic Opensource/Pathfinding/Scripts/Core/PathFinder.cs:16)
    6. PathFinder.Update () (at Assets/CertainLogic Opensource/Pathfinding/Scripts/Core/PathFinder.cs:36)
    7.  
    8.  
    How i should solve this problem? :confused:

    And also here is the second attachment when unity give me an error. There is highlighting row that i click to the error.
     

    Attached Files:

  13. DavidB

    DavidB

    Joined:
    Dec 13, 2009
    Posts:
    530
    From the error it sounds like no navigation map is actually being loaded and registered. When you generated your navigation map... did you actually see the green grid form properly? If so did you save it at this point? I'm wondering if the error is arising form a null map being saved/loaded. Also in your PathMaster Inpsector did you add your map file to the registered list so that it loads?
     
  14. cemC

    cemC

    Joined:
    Dec 23, 2010
    Posts:
    214
    i loaded the map from the file which saved in your example path in project. When i press the play button and click to Pathmaster in hierarchy , there is no mesh in pathmaster. ı do not understant, i saved it and loaded it. But it did not work.In addition there is no green nodes or lines when playing. I did everything in your youtube tutorial.I saved it before clear the mesh.

    Are there any folder preparation in project for navmes?
     
    Last edited: Dec 29, 2010
  15. DavidB

    DavidB

    Joined:
    Dec 13, 2009
    Posts:
    530
    Sorry I think I'm misunderstanding... did you load a pre-existing map? Or did you first generate the map file based on your arbitrary geometry (level) and then load that? I'll get to the bottom of this lol, I'm just trying to figure out at what part something isn't working.
     
  16. cemC

    cemC

    Joined:
    Dec 23, 2010
    Posts:
    214
    i loaded it by using Pathmaster. Especially i generated my own mesh, then i save it. However , i clear the mesh before saving umm i am not sure , maybe i am the source of this problem :) anyway, i will check my steps in 30 minutes and i will write here again :D
     
  17. DavidB

    DavidB

    Joined:
    Dec 13, 2009
    Posts:
    530
    Did you have any luck? Also did you actually see a generated mesh before you saved and cleared it?

    Cheers and good luck!
     
  18. llavigne

    llavigne

    Joined:
    Dec 27, 2007
    Posts:
    977
    Hi David,

    Good to see another pathfinder.
    My game world is represented by a grid, objects are added removed dynamically.
    Would your pather work for such case ?
     
  19. DavidB

    DavidB

    Joined:
    Dec 13, 2009
    Posts:
    530
    The shape doesn't matter for our system. Currently our grid system is generated statically.... but if you retooled your own mechanism to add/remove nodes as you wish, that's certainly possible and the pathing will certainly work on a dynamic field as at any given search call the grid will be "static".

    So in short, yes the system will certainly handle what you need, but not out of the box, you'll need to of course code something to manage the added/removed nodes from the BaseNavMesh.
     
  20. llavigne

    llavigne

    Joined:
    Dec 27, 2007
    Posts:
    977
  21. DavidB

    DavidB

    Joined:
    Dec 13, 2009
    Posts:
    530
    I actually haven't read this blog in some time, I see it's got a lot of new goodies in there :D

    Thanks for the reminder. As for dynamic meshes, that's definitely something we'd love to add to the system as it develops, I'll have to give this concept some thought to keep it robust enough for many game-type implementations.
     
  22. llavigne

    llavigne

    Joined:
    Dec 27, 2007
    Posts:
    977
    General is tricky, what's nice about your lib so far is it's small. Will you strive to keep it this way.
     
  23. DavidB

    DavidB

    Joined:
    Dec 13, 2009
    Posts:
    530
    Our current design principle is we want it small, we want it open and we want it free for everyone to use (hoping for some sorta collaboration with others of likemind so that this can really be the community's pathfinding tool of choice).

    We do plan on including advanced features, but we will likely offer them as "packs" that you can addon to the system rather than bloating the basic core. With each game implementation theoretically requiring something "completely different" we want to give people a chance to home brew their own solutions, without having to struggle. Again, long way to go, but it's a start :p
     
  24. Robbilie2

    Robbilie2

    Joined:
    Aug 4, 2010
    Posts:
    262
    hey guys

    can u upgrade the project?
    maybe that will fix my errors:

    i get many keynotfound exeptions...

    DirectoryNotFoundException: Could not find a part of the path "C:\Documents and Settings\David\My Documents\Certain Logic\Projects\OpenSource\NavigationMesh Opensource\Assets\CertainLogic Opensource\Saved Meshes\DemoMesh.map".
    System.IO.FileStream..ctor (System.String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, Boolean anonymous, FileOptions options)
    System.IO.FileStream..ctor (System.String path, FileMode mode, FileAccess access, FileShare share)
    (wrapper remoting-invoke-with-check) System.IO.FileStream:.ctor (string,System.IO.FileMode,System.IO.FileAccess,System.IO.FileShare)
    System.IO.File.Open (System.String path, FileMode mode)
    SaveEngine.LoadData (System.String path) (at Assets/CertainLogic Opensource/Navigation Mesh/Scripts/Core/SaveSystem.cs:29)
    BaseNavMesh.Load (System.String path) (at Assets/CertainLogic Opensource/Navigation Mesh/Scripts/Core/BaseNavMesh.cs:130)
    PathMaster.Start () (at Assets/CertainLogic Opensource/Pathfinding/Scripts/Core/PathMaster.cs:39)



    KeyNotFoundException: The given key was not present in the dictionary.
    System.Collections.Generic.Dictionary`2[System.String,INavigationMesh].get_Item (System.String key)
    PathMaster.GetPath (IPathFinder pathFinder, Vector3 destination) (at Assets/CertainLogic Opensource/Pathfinding/Scripts/Core/PathMaster.cs:26)
    PathFinder.FindPath (Vector3 destination) (at Assets/CertainLogic Opensource/Pathfinding/Scripts/Core/PathFinder.cs:16)
    PathFinder.MoveToPoint (Vector3 point) (at Assets/CertainLogic Opensource/Pathfinding/Scripts/Core/PathFinder.cs:71)
    UnityEngine.Component:BroadcastMessage(String, Object)
    ClickMove:Update() (at Assets/Other Code/ClickMove.cs:14)


    thanks ;)
     
  25. DavidB

    DavidB

    Joined:
    Dec 13, 2009
    Posts:
    530
    There will be some upgrades coming in the future (we're currently using it in a few game products so we can see where the downfalls are), but from the error posted it seems like you are trying to use the DemoMesh.map and it simply isn't being found? Try following the wiki steps to create your own map file (only takes a few moments) and play with that, it will at least let you see the system in action. In the test scene remove the DemoMesh.map from the PathMaster game object, it should remove that error for you.

    Thanks for the heads up on the error though!
     
  26. tintin

    tintin

    Joined:
    Feb 3, 2009
    Posts:
    35
    Hi, any update plan?
     
  27. DavidB

    DavidB

    Joined:
    Dec 13, 2009
    Posts:
    530
    With some of the new systems popping up (such as that really cool navmesh generator) we want to make our NavMesh implementation more robust and easier for users to use their own desired navigation mesh systems in conjunction with this framework.

    The framework will also be re-assessed and boiled down to it's essentials in an attempt to keep the framework really small and lightweight.

    Was there something you had in mind in particular?
     
  28. PrimeDerektive

    PrimeDerektive

    Joined:
    Dec 13, 2009
    Posts:
    3,090
    Which one?
     
  29. DavidB

    DavidB

    Joined:
    Dec 13, 2009
    Posts:
    530
    The cool packages that I'm aware of popping up lately in the field of game agent navigation would be....

    http://forum.unity3d.com/threads/78037-AI-Pathfinding-in-Unity-Path?highlight=path (Path)
    http://forum.unity3d.com/threads/52326-A*-Pathfinding-Project-2.8-beta-is-live!?highlight=grandberg (Aron Granberg's A*)
    http://forum.unity3d.com/threads/89712-SimplePath-Advanced-Pathfinding-for-any-Game-Genre-RELEASED (SimplePath)
    http://forum.unity3d.com/threads/85348-WIP-My-first-unity-project-navmesh-generation (ChrisPaulson's NavMesh Generator)

    There have definitely been some huge leaps forward on this front in Unity... which is fantastic. Many of these are quality packages and they certainly deliver above and beyond what they are asking. We just want to provide a basic package for the Unity community to introduce them to game agent navigation. (My team also uses it and experiments with it to learn about game agent navigation).

    I highly recommend everyone to check all of these packages out though... some great stuff. Also using UnitySteer in conjunction with them is fantastic (especially after UnitySteer's code reformation).
     
  30. pegorari

    pegorari

    Joined:
    Nov 19, 2009
    Posts:
    60
    Hello!
    I´m getting an error "KeyNotFoundException: The given key was not present in the dictionary" when the scene is more complex.

    Looking forward to see new updates!

    Thanks