Search Unity

SimplePath - Advanced Pathfinding for any Game Genre - RELEASED

Discussion in 'Assets and Asset Store' started by alexkring, May 18, 2011.

  1. diablo

    diablo

    Joined:
    Jan 3, 2011
    Posts:
    736
    Thanks for the feedback Alex, I appreciate it!

    On a side-note, I think I remember seeing a video on your website (I think it was you) demonstrating a prototype of agents performing sophisticated collision avoidance HRVO style, but your website is down (are you going to bring it back up at some point?). Am I correct that this was something you posted and were working on, and if so, whatever happened to it?

    El Diablo
     
  2. limdorn

    limdorn

    Joined:
    Jan 5, 2012
    Posts:
    56
    Hi, everybody.
    First I want to tell that simplepath is fantastic : I bought several pathfinding systems (a pathfinding project, pathfinder...) and , for me, the best is simplepath.:D

    SimplePath works perfect with the same kind of units (for example ground units) but how can I do to use with different kind of units ( ground , water and sky) ?

    Thanks.
    Sorry to my english but I´m spanish.
     
  3. alexkring

    alexkring

    Joined:
    May 5, 2011
    Posts:
    368
    I had posted a few videos about avoidance, though none of them were on HRVO techniques. Mikko Monnen's blog is a good place to look at at HRVO stuff, and navigation coding in general, if you are interested
     
  4. alexkring

    alexkring

    Joined:
    May 5, 2011
    Posts:
    368
    I had posted a few videos about avoidance, though none of them were on HRVO techniques. Mikko Monnen's blog is a good place to look at at HRVO stuff, and navigation coding in general, if you are interested
     
  5. Eiznek

    Eiznek

    Joined:
    Jun 9, 2011
    Posts:
    374
    Bought this a few days ago. Enjoying the simple use of it.
     
  6. GC1983

    GC1983

    Joined:
    Jan 23, 2012
    Posts:
    22
    Hey Alex, hows it going?

    Im confused on what I may be doing wrong. My NPCs are getting caught up on random corners. I have their capsule colliders set at .025 radius with the cell size at .5. How small do the colliders to fit within each cell for them to properly corner the avoidance objects?
     
  7. TorontoJoe

    TorontoJoe

    Joined:
    Mar 25, 2012
    Posts:
    32
    Amazing looking extension! Will make a purchase soon. I haven't gone through all 31 pages so I'm sorry if this has already been mentioned but are there any Playmaker custom actions available for this?
     
  8. alexkring

    alexkring

    Joined:
    May 5, 2011
    Posts:
    368
    I haven't integrated this with Playmaker before, but maybe someone else here has?
     
  9. alexkring

    alexkring

    Joined:
    May 5, 2011
    Posts:
    368
    Play with the "Scale" value on the footprint component, and the "Look Ahead Distance" value on the steering agent component. You probably need to decrease the "Look Ahead Distance," and increase the scale of the footprints.
     
  10. GC1983

    GC1983

    Joined:
    Jan 23, 2012
    Posts:
    22
    Thank you sir, I will test that.
     
  11. duncanwilson

    duncanwilson

    Joined:
    Apr 1, 2012
    Posts:
    2
    Hi, has anyone managed to implement simple path with unity steer to get dynamic agent collision avoidance?

    I've tried to combine simple path with the SteerForNeighborAvoidance but I get some strange behaviours once a collision has been avoided:-

    For example, using Interaction_patrol, once a collision has been avoided an agent will very slowly move towards the original patrol point, before resuming normal speed. journeys back to the original patrol point continue at very low speed.

    any help would be greatly appreciated
    thanks
     
  12. alexkring

    alexkring

    Joined:
    May 5, 2011
    Posts:
    368
    Look at the SteeringAgentComponent.cs. This is the only file you should have to change, to modify the steering of the agents. Here is a basic overview of this file.

    - SteerAlongPath gets called when a new path is solved, and the agent is ready to steer along the path. This is the entry point for steering.
    - StopSteering is called when the agent should stop steering, and sit still.
    - SteeringAgentComponent is responsible for calling OnArrived itself, in order to tell the other navigation components that the agent has reached its destination.
    - SteeringAgentComponent is responsible for setting the velocity of the agent ( rigidbody.velocity )

    In other words, you need to hook in your steering code when SteerAlongPath is called, make sure to stop your steering code when StopSteering is called, make sure you call OnArrived when your steering code has detected the agent has arrived at his final destination, and make sure you turn your steering calculations into some sort of final velocity that gets set on the rigidbody. You could completely delete all the code in this file, so long as you follow these 4 criteria.
     
  13. funasylum

    funasylum

    Joined:
    Feb 5, 2011
    Posts:
    48
    Hi Alex! Looks like a great product. I especially appreciate the care you obviously put into the documentation which makes sense even to a semi beginner like myself.

    I think this could work great for me-- but before I purchased I wanted to run something by you. I think SimplePath is a nobrainer for the npcs/non-user controlled agents I have in my grid based game. But I was wondering if you had suggestions about using SimplePath to help me control the user controlled player?

    It would be awesome if I could somehow tap into SimplePath so that user input could move the player to the next north/south/west/east node. I could use some sort of 'grid move' script on my player and then try to align that grid with the SimplePath grid. But figure it'd be so much more accurate if I could take input from player, and then move the player to spot x,y on the SimplePath grid, for instance.

    Do I have access to those SimplePath node coordinates from outside scripts?

    Or possibly could I set it up so my player is actually an agent in the SimplePath system and user input makes the player advance a single node in a single direction?

    Thank you very much!
    Sebastian
     
  14. helios

    helios

    Joined:
    Oct 5, 2009
    Posts:
    308
    How is performance on iOS devices? I see in some older posts in the thread there were serious performance issues. Have these been resolved?
     
  15. duncanwilson

    duncanwilson

    Joined:
    Apr 1, 2012
    Posts:
    2
    okay, thanks for the pointers. i'll give it a go!
     
  16. alexkring

    alexkring

    Joined:
    May 5, 2011
    Posts:
    368
    Yes, you could do this, you would setup the player just like any other agent in SimplePath. You just need to create an interaction script that will take in the mouse input, and feed in the destination to SimplePath
     
  17. alexkring

    alexkring

    Joined:
    May 5, 2011
    Posts:
    368
    Performance was fine on iOS for me. I used SimplePath for several profesional iOS games with many agents. I'd be quite surprised if there was an existing pathfinding package out there that is faster :] The main performance problems are with the grid rasterization, which is not expected to happen every frame. If you do use the grid rasterization features ( basically it is an update to tell the agents where the obstacles are rasterized into the map ), it is up to you to determine when to call the Rasterize function. Right now it just calls it every frame, because the right time to Rasterize is dependent upon the game you are making. For most games, you won't have to worry about this. If that is something you plan on using heavily, I can give you more specific details for your game :]
     
  18. helios

    helios

    Joined:
    Oct 5, 2009
    Posts:
    308
    SimplePath is pretty great. Easy to set up and get started. I have a question about "chase" style agents. Is there a method or variable that can temporarily disable/enable chasing? I couldn't find one, but I imagine there has to already be a simple built-in way. Thanks.
     
  19. alexkring

    alexkring

    Joined:
    May 5, 2011
    Posts:
    368
    You could disable the Interaction_Chase script.
     
  20. pudd1nG

    pudd1nG

    Joined:
    Feb 21, 2012
    Posts:
    36
    Hey there Alex, I've bought SimplePath yesterday and am slowing coming to terms with it. Few questions though.

    -Is it possible for me to change something like the patrol waypoint array via javascript? All my GUI is in javascript.

    -I'm really struggling to get a direction to get a right click movement working (without being hacky about it), od you have an example or simple solution?

    Thanks, already in love with this amazing asset!
     
  21. AntFitch

    AntFitch

    Joined:
    Jan 31, 2012
    Posts:
    243
    Also purchased and have a question. My game is a 2D platformer on XY axis and I need to use pathfinding on creatures flying through the air from one place to another. Is there a way to disable gravity with SimplePath so that I can do this? Thanks!
     
  22. pudd1nG

    pudd1nG

    Joined:
    Feb 21, 2012
    Posts:
    36
    Why not disable gravity on the object rigidbody?
     
  23. Lord_Pall

    Lord_Pall

    Joined:
    Sep 25, 2009
    Posts:
    52
    Does this compile to flash?
     
  24. alexkring

    alexkring

    Joined:
    May 5, 2011
    Posts:
    368
    I think your best option is to remove the Interaction_Patrol component from the agent, and then attach your own Interaction_Something javascript component to the agent. You can look at the Interaction_Patrol script for reference, and then try to make something similiar, with your own modifications, in javascript. Here is a a basic outline for the code you would need to put in the script to do point and click. When the mouse is clicked, do something like the following.

    Code (csharp):
    1.  
    2. Vector3 mousePositionInScreenSpace = Input.mousePosition;
    3. Vector3 mousePositionInWorldSpace = ScreenToWorldSpace( mousePositionInScreenSpace );
    4. m_navigationAgent.MoveToPosition( mousePositionInWorldSpace, m_replanInterval );
    5.  
    This will cause the agent to move to the clicked position. When the agent has reached his destination, OnNavigationRequestSucceeded() will be called in your script. If the request fails, OnNavigationRequestFailed() will be called (both functions are messages sent by SimplePath).

    In other words, I would create a new Interaction_PointAndClick script that replaces the Interaction_Patrol script, and the script has nothing except for the code I illustrated above. My guess is that if you are having difficulty, you may not be passing a position in the right coordinate space. Input.mousePosition returns a position in screenspace, and you need to be sure to convert that to world space, because SimplePath expects you to pass it positions in world space. You can verify that you are generating the right world space position, by drawing some sort of debug line at the position you are generating. This line should appear at the position, in the world, where the agent is supposed to travel to.
     
  25. alexkring

    alexkring

    Joined:
    May 5, 2011
    Posts:
    368
    You can disable gravity on the rigidbody as pudding said. Also, there is a "Gravitational Acceleration Rate" variable on the SteeringAgentComponent that allows you to control the upward or downard force applied to the agent each frame. When I used SimplePath for fish and flying creatures before, I just turned off the gravity on rigidbody and set "Gravitational Acceleration Rate" to 0.
     
  26. pudd1nG

    pudd1nG

    Joined:
    Feb 21, 2012
    Posts:
    36
    Thanks for the info Alex.

    One more thing, I'm Instantiating agents and am assigning their pathmanager via the code below, however they don't seem to want to move. Adding them to the scene manually works and the inspector shows the correct component being added.

    if ( m_pathManager == null )
    {
    GameObject pathy = GameObject.Find("PathManager");
    Component pathx = pathy.GetComponent<PathManagerComponent>();
    m_pathManager = (PathManagerComponent)pathx;

    }
     
  27. alexkring

    alexkring

    Joined:
    May 5, 2011
    Posts:
    368
    I am guessing that a navigation request is being made before the pathmanager is assigned. To test this theory, you could put an assertion inside the MoveToPosition and MoveToGameObject functions in NavigationAgentComponent, and assert of the pathmanager is not yet set. So if the pathmanager is being assigned dynamically, just make sure you dont make any path requests until this is assigned. You could also try the code below and see if it fixes your problem.

    Code (csharp):
    1.  
    2. if ( m_pathManager == null )
    3. {
    4. m_navigationAgent.CancelActiveRequest()
    5. GameObject pathy = GameObject.Find("PathManager");
    6. Component pathx = pathy.GetComponent<PathManagerComponent>();
    7. m_pathManager = (PathManagerComponent)pathx;
    8. }
    9.  
     
  28. pudd1nG

    pudd1nG

    Joined:
    Feb 21, 2012
    Posts:
    36
    I've tried your suggestion (I had to reference the navigationAgent) but still nothing. I've added in checks to the navigation script with still nothing happening. I really didn't think it would be this trivial to add an agent at runtime. I'll keep trying.

    edit: fixed by manning up and creating a proper object cache for my project with values predefined. Things should be better from here on out :) Thanks for all your help Alex :D Great system!
     
    Last edited: Apr 18, 2012
  29. liquid405

    liquid405

    Joined:
    Apr 19, 2012
    Posts:
    3
    Hey Alex, LOVE your path agent. I am trying to get a squad of units to stay in rough cohesion together. In order to implement this, I am trying to generate a "squad" path, and then have the individual units path to each node in the squad path. Where in the code could I access the Node list?

    Thanks!

    -Ian
     
  30. alexkring

    alexkring

    Joined:
    May 5, 2011
    Posts:
    368
    The nodes for the solution path are stored in the PathRequestQuery in PathAgentComponent.cs. This stores the path solution that the planner has created. The individual points that the agents actually follow, are stored in the m_path variable in SteeringAgentComponent.cs. This may seem a bit confusing that there are two lists, but I will try to explain. The PathAgentComponent is responsible for planning the path, and it creates a solution in nodes. It then passes this solution to the SteeringAgentComponent. The SteeringAgentComponent then consumes this path as the list of actual points the agents follow, after a process called "path smoothing" is performed. Path smoothing just takes the list of nodes in the solution list (stored in PathRequestQuery), and smooths is out a bit so that the agents follow a more natural looking path. In other words, some of the nodes in the list are unnecessary, and path smoothing removes those nodes. This also create the geometrically shortest path. Path smoothing starts when PathSmoother.Smooth is called. The smooth path gets passed to the steering agent when SteerAlongPath is called. Depending on your needs, you may want to use the node list in PathRequestQuery, or the point list in m_path. The debug lines that are drawn represent the points in m_path. If you want to see what the list of nodes looks like, just untick the "use path smoothing" check box on the NavigationAgentComponent.

    This also may be useful: the m_seekPos variable represents the position that the agent is following at any point in time, and it is always a position on the path. Every frame I project the agent's position onto the path, and then extend that position further along the path, so that the agent is always moving toward a position ahead of himself and along the path. There is also an option to view the m_seekPos as a debug circle.
     
    Last edited: Apr 19, 2012
  31. Sinperhezine

    Sinperhezine

    Joined:
    Mar 14, 2012
    Posts:
    10
    I have been playing around with the simple path and have run into 2 problems. the first is getting the AI both to prioritize targets and chase after the target after it comes in ranges, the second is getting the AI to move to the next node thought a teleporter. can you help me?
     
  32. alexkring

    alexkring

    Joined:
    May 5, 2011
    Posts:
    368
    Problem 1: Take a look at the Interaction_Chase script. Here is some pseudocode for solving problem. The code below would make the agent only chase after objects that are within 5 meters, and the agent would prefer to chase objects that are closer.

    Code (csharp):
    1.  
    2. private class PrioritizedChaseObject
    3.     {
    4.         public GameObject ChaseObject;
    5.         public float Priority;
    6.     }
    7.    
    8.     public virtual void Update ()
    9.     {
    10.         if ( m_bNavRequestCompleted )
    11.         {
    12.             GameObject[] chaseObjectArray = GameObject.FindGameObjectsWithTag("ChaseObject");
    13.             List<PrioritizedChaseObject> prioritizedChaseObjectList = new List<PrioritizedChaseObject>();
    14.            
    15.             // Determine the best object to chase after
    16.             foreach ( GameObject chaseObject in chaseObjectArray )
    17.             {
    18.                 float distToChaseObject = (chaseObject.transform.position - transform.position).magnitude;
    19.                
    20.                 const float kChaseRange = 5.0f;
    21.                
    22.                 if ( distToChaseObject > kChaseRange )
    23.                 {
    24.                     continue;
    25.                 }
    26.                
    27.                 PrioritizedChaseObject pChaseObj = new PrioritizedChaseObject();
    28.                 pChaseObj.ChaseObject = chaseObject;
    29.                 pChaseObj.Priority = ScoreChaseObjectPriority( chaseObject );
    30.             }
    31.            
    32.             // Start chasing
    33.             if ( prioritizedChaseObjectList.Count > 0 )
    34.             {
    35.                 prioritizedChaseObjectList.Sort( CompareChaseObjectsByPriority );
    36.                
    37.                 GameObject bestChaseObject = prioritizedChaseObjectList[0];
    38.                
    39.                 if ( m_navigationAgent.MoveToGameObject(m_chaseObject, m_replanInterval) )
    40.                 {
    41.                     m_bNavRequestCompleted = false;
    42.                 }
    43.             }
    44.         }
    45.     }
    46.    
    47.     private float ScoreChaseObjectPriority(GameObject chaseObject)
    48.     {
    49.         float score = 0.0f;
    50.        
    51.         // TODO: Score the priority of this chaseobject. Here is an example of how they could be scored
    52.        
    53.         float distToChaseObject = (chaseObject.transform.position - transform.position).magnitude;
    54.         if ( distToChaseObject == 0.0f )
    55.         {
    56.             score = float.MaxValue;
    57.         }
    58.         else
    59.         {
    60.             score = 1.0f / distToChaseObject;
    61.         }
    62.        
    63.         return score;
    64.     }
    65.    
    66.     private static int CompareChaseObjectsByPriority(PrioritizedChaseObject x, PrioritizedChaseObject y)
    67.     {
    68.         if ( x.Priority > y.Priority )
    69.         {
    70.             return 1;
    71.         }
    72.         else if ( x.Priority < y.Priority )
    73.         {
    74.             return -1;
    75.         }
    76.         else
    77.         {
    78.             return 0;
    79.         }
    80.     }
    81.  
    Problem 2: What is a teleporter?
     
  33. Sinperhezine

    Sinperhezine

    Joined:
    Mar 14, 2012
    Posts:
    10
    teleporter: a device in which the user is transported from one locations to another. star trek would have the most famous example of it.
     
  34. alexkring

    alexkring

    Joined:
    May 5, 2011
    Posts:
    368
    What problems are you seeing with trying to move the agent through a teleporter?
     
  35. Sinperhezine

    Sinperhezine

    Joined:
    Mar 14, 2012
    Posts:
    10
    i have the teleporter set as the patrol node but it doesn't registered as reached when the mob goes thought
     
  36. alexkring

    alexkring

    Joined:
    May 5, 2011
    Posts:
    368
    My guess is that the teleporter teleports the agent before he reaches the patrol node. When the agent teleports, you should call a function or send a message to the Interaction_Patrol script, and then write some code to ensure that the agent stops navigating toward the old patrol node, and starts navigating toward the next patrol node. In other words, create an OnTeleported() function on the Interaction_Patrol script, and handle all of the logic in there. You will need to do the following:

    1. Stop navigation by calling CancelActiveRequest on the navigation agent component.
    2. Determine the next patrol node the agent should move toward, Call MoveToPosition toward that patrol node, and make sure that m_currentPatrolNodeGoalIndex and m_bNavRequestCompleted are set to the correct values.

    Additionally, ensure that the agent is not trying to navigate while he is in the process of teleporting, in case teleporting is not an instant process and takes multiple frames.
     
  37. Sinperhezine

    Sinperhezine

    Joined:
    Mar 14, 2012
    Posts:
    10
    ok one last thing i need it to switch in between chasing moving along with patrol route. any suggestion to have this happen more smoothly?
     
  38. alexkring

    alexkring

    Joined:
    May 5, 2011
    Posts:
    368
    You should create a higher level decision making system for the agent. Think of this as the brain of the agent. The system should determine which interactions the agent should run. Whenever an interaction is complete, the interaction should report this information back to the decision making system, so that it can then determine which interaction to run next. Think of each interaction as a behavior. Examples of interactions could be patrol, chase, flee, take cover, die, etc.
     
  39. liquid405

    liquid405

    Joined:
    Apr 19, 2012
    Posts:
    3
    Seem to be having problems here. I finally implemented the squad pathing stuff alright, but the agents are not behaving correctly.
    Essentially no matter where I click, the agents wander off in the wrong direction (it is the same direction every time.








    ....and off into the sunset he goes.

    Here are my settings, and the code I use.





    Any idea what I am doing wrong?
     
  40. alexkring

    alexkring

    Joined:
    May 5, 2011
    Posts:
    368
    The path looks correct, maybe it is something related to his steering? Have you made any modifications to his steering code? Are there any other forces acting on him? Drawing his SeekPosition every frame might help too. The SeekPosition is the the position he is always moving toward, determined by the SteeringAgentComponent. If the SeekPosition is not on his path, then something is wrong with this steering. If his SeekPosition and his path both look right, but he is still moving in the wrong direction, then there is likely some external force pushing him to the wrong position. Theres only one place where SimplePath modified the position of the agent, and that is by modifying his velocity in the SteeringAgentComponent on the line with:

    rigidbody.velocity = newVelocity;

    So you could also look at how the velocity is being computed to see all the things that can possible effect his position
     
  41. Meltdown

    Meltdown

    Joined:
    Oct 13, 2010
    Posts:
    5,822
    How do you Destroy a spawned gameobject gracefully with Interaction_Patrol, Interaction_Chase, NavigationComponent and PathAgentComponent components attached?

    Whenever I try to destroy one of my spawned creatures that were on SimplePath I get..

    "The object of type PathAgentComponent has been destroyed but you are still trying to access it"

    I've tried adding null checks into your libraries but something from SimplePath still seems to want to refer to the components on my destroyed game object.

    Thanks
     
  42. liquid405

    liquid405

    Joined:
    Apr 19, 2012
    Posts:
    3
    Looks like the velocity is pointed almost straight down all the time. Most curious.

    It may be my teams legacy code affecting it. If not, its time to get down and dirty in the code.
     
    Last edited: Apr 24, 2012
  43. alexkring

    alexkring

    Joined:
    May 5, 2011
    Posts:
    368
    Ah. Try changing the "Gravitational Acceleration Rate" to 0 on the SteeringAgentComponent. This is the downward force acting on the agent each frame.
     
  44. alexkring

    alexkring

    Joined:
    May 5, 2011
    Posts:
    368
    My guess is that the Interaction_Patrol and Interaction_Chase scripts are still making navigation requests. The NavigationAgentComponent clears out all data in the system from that agent in its OnDestroy function. Maybe you want to prevent requests from being made in those scripts by adding some code in the OnDestroy call of those interactions?

    But basically the graceful way to do it is to call CancelActiveRequest() on the NavigationAgentComponent, and that will completely remove the agent from SimplePath. I think you should add a function called "Stop()" to each of the Interaction scripts. Just before you destroy the agent, you should call that on all the active interactions. That function should call CancelActiveRequest() on the navigation component, and it should disable itself so that path requests are not made in the future.
     
  45. Meltdown

    Meltdown

    Joined:
    Oct 13, 2010
    Posts:
    5,822
    Thanks for the reply. That seems to work better now. Thanks.

    Although how would I get my enemy to reactivate the pathfinding?

    Whats happening is my enemy picks something up (which I make as a chase target), I then need to call CancelActiveRequest to remove that object from any NavigationRequests.

    But after that I set my enemy to go back to patrolling but he does not walk. Its almost as if calling CancelActiveRequest on any picked up object stops the enemy from doing pathfinding.

    I've also tried moving my enemy to the position of the pickup using MoveToGameObject.
    But as soon as I destroy the pickup, I get the errors again.

    How do I 're-initialise' the pathfinding? So the enemy goes back to normal?
     
    Last edited: Apr 25, 2012
  46. alexkring

    alexkring

    Joined:
    May 5, 2011
    Posts:
    368
    So it sounds like you disabled the Interaction script, right? If that's the case, you will need to enable the script to resume pathfinding.
     
  47. Meltdown

    Meltdown

    Joined:
    Oct 13, 2010
    Posts:
    5,822
    I've tried that, there is no difference. The state of my enemy is put to exactly back to what it was before the pickup is destroyed, yet he does not move.

    When I use MoveToGameObject and set the pickup as the target, I call CancelActiveRequest on my enemy to avoid any errors when I call Destroy on the pickup.This is the only way to avoid all the errors coming up.

    So I'm stuck between a rock and a hard place here. Calling CancelActiveRequest prevents the errors from showing, but no matter what I do once I've called it, I can't seem to add the agent back to the navigation.

    Do you have any other suggestions? This is getting really frustrating now. I was hoping if I just disabled the Chase script it would stop with navigation requests.. yet this is not the case. This CancelActiveRequest seems like a strange way to handle things, if there is no method to resume a Request.

    Is there another way to reset or restart the navigation on an agent?
     
  48. msc4tech

    msc4tech

    Joined:
    Sep 8, 2011
    Posts:
    17
    I've this problem:
    i've more agents on the map with path.
    I need that every agent is an obstacle for the other agents on the map
    What is the solution?
     
  49. alexkring

    alexkring

    Joined:
    May 5, 2011
    Posts:
    368
    CancelActiveRequest stops the agent's current navigation request. MoveToGameObject and MoveToPosition start a new request. If you cancel the active request, you need to make a new request to get the agent moving again.
     
  50. alexkring

    alexkring

    Joined:
    May 5, 2011
    Posts:
    368
    You can improve the steering by modifying SteeringAgentComponent.cs, or you can handle this will collision response. When two agents collide, apply forces to make them slide off one another, and push one another. I prefer the collision response solution.