Search Unity

navmesh and raycast obstacle avoidance

Discussion in 'Works In Progress - Archive' started by galent, May 7, 2012.

  1. galent

    galent

    Joined:
    Jan 7, 2008
    Posts:
    1,078
    Hi all,

    Ok so I ran up against this one and couldn't find any good/quick answers, so I cobbled something together. Figured I'd share (if for no better reason, than if I lose this, I can Google it again :D)

    Basically, when you set the target (manually or through another script), Unity NavMeshAgent takes care of the usual navigation. If something gets hit by the raycast, a simple obstacle avoidance takes over. Once the obstacle is behind the character, the Unity NavMesh is switched back on.

    Hope this helps someone else:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5.  
    6. /*
    7.  * This script will use the Unity navmesh tools in combination with a simple
    8.  * obstacle avoidance to navigate a map.  There is a lot of room for improvement,
    9.  * but this does work.
    10.  */
    11. public class BaseCharacterwNav : MonoBehaviour {
    12.     public Transform target; // where we're going
    13.     private NavMeshAgent nma; // Unity nav agent
    14.     public float probeRange = 1.0f; // how far the character can "see"
    15.     private bool obstacleAvoid = false; // internal var
    16.     public float turnSpeed = 50f; // how fast to turn
    17.    
    18.     // create empty game objects and place them appropriately infront, to the left and right of our object
    19.     // This creates a little buffer around the character, and I had some trouble with never raycasting
    20.     // outside the character rigidbody/collider
    21.     public Transform probePoint; // forward probe point
    22.     public Transform leftR; // left probe point
    23.     public Transform rightR; // right probe point
    24.    
    25.     private Transform obstacleInPath; // we found something!  
    26.    
    27.     // Use this for initialization
    28.     void Start () {
    29.         nma = this.GetComponent<NavMeshAgent>();
    30.         nma.SetDestination(target.position);
    31.         if(probePoint == null)
    32.             probePoint = transform;
    33.         if(leftR == null) {
    34.             leftR = transform;         
    35.         }
    36.         if(rightR == null)
    37.             rightR = transform;        
    38.     }
    39.    
    40.  
    41.     void Update () {
    42.        
    43.         RaycastHit hit;
    44.         Vector3 dir = (target.position - transform.position).normalized;
    45. //     
    46.         bool previousCastMissed = true; // no need to keep testing if something already hit
    47.         // this is the main forward raycast
    48.         if(Physics.Raycast(probePoint.position, transform.forward, out hit, probeRange)){
    49.             if(obstacleInPath != target.transform) { // ignore our target
    50.                 Debug.Log("Found an object in path! - " + gameObject.name);
    51.                 Debug.DrawLine(transform.position, hit.point, Color.green);
    52.                 previousCastMissed = false;
    53.                 obstacleAvoid = true;
    54.                 nma.Stop(true);
    55.                 nma.ResetPath();
    56.                 if(hit.transform != transform) {                 
    57.                     obstacleInPath = hit.transform;
    58.                     Debug.Log("I hit: " + hit.transform.gameObject.name);              
    59.                     dir += hit.normal * turnSpeed;
    60.                    
    61.                     Debug.Log("moving around an object - " + gameObject.name);
    62.                    
    63.                 }
    64.             }
    65.         }
    66.         // if we did see something before, but now the forward raycast is turned out of range, check the sides
    67.         // without this, the character bumps into the object and sort of bounces (usually) until it gets
    68.         // past.  This is a better approach :)
    69.         if(obstacleAvoid  previousCastMissed  Physics.Raycast(leftR.position, transform.forward,out hit, probeRange)) {
    70.             if(obstacleInPath != target.transform) { // ignore our target
    71.                 Debug.DrawLine(leftR.position, hit.point, Color.red);
    72.                 obstacleAvoid = true;
    73.                 nma.Stop();
    74.                 if(hit.transform != transform) {
    75.                     obstacleInPath = hit.transform;
    76.                     previousCastMissed = false;
    77.                     //Debug.Log("moving around an object");
    78.                     dir += hit.normal * turnSpeed;             
    79.                 }
    80.             }
    81.         }
    82.         // check the other side :)
    83.         if(obstacleAvoid  previousCastMissed  Physics.Raycast(rightR.position, transform.forward,out hit, probeRange)) {
    84.             if(obstacleInPath != target.transform) { // ignore our target
    85.                 Debug.DrawLine(rightR.position, hit.point, Color.green);
    86.                 obstacleAvoid = true;
    87.                 nma.Stop();
    88.                 if(hit.transform != transform) {
    89.                     obstacleInPath = hit.transform;
    90.                     dir += hit.normal * turnSpeed;
    91.                 }
    92.             }
    93.         }
    94.        
    95.         // turn Nav back on when obstacle is behind the character!!
    96.          if (obstacleInPath != null) {
    97.             Vector3 forward = transform.TransformDirection(Vector3.forward);
    98.             Vector3 toOther = obstacleInPath.position - transform.position;
    99.             if (Vector3.Dot(forward, toOther) < 0) {
    100.                 //print("The other transform is behind me!");
    101.                 Debug.Log("Back on Navigation! unit - " + gameObject.name);
    102.                 obstacleAvoid = false; // don't let Unity nav and our avoidance nav fight, character does odd things
    103.                 obstacleInPath = null; // Hakuna Matata
    104.                 nma.ResetPath();
    105.                 nma.SetDestination(target.position);
    106.                 nma.Resume(); // Unity nav can resume movement control
    107.             }
    108.            
    109.         }
    110. //     
    111.         // this is what actually moves the character when under avoidance control
    112.         if(obstacleAvoid) {
    113.             Quaternion rot = Quaternion.LookRotation(dir);
    114.             transform.rotation = Quaternion.Slerp(transform.rotation, rot, Time.deltaTime);
    115.             transform.position += transform.forward * nma.speed * Time.deltaTime;
    116.         }      
    117.     }
    118.    
    119.     public void SetTarget(Transform tIn) {
    120.         target = tIn;  
    121.     }    
    122. }
    123.  
    Cheers,

    Galen
     
  2. yahodahan

    yahodahan

    Joined:
    Apr 26, 2009
    Posts:
    1,380
    This sounds great, thanks for sharing!
     
    IndieFist likes this.
  3. davyj1221

    davyj1221

    Joined:
    May 16, 2017
    Posts:
    5
    Thanks, A lot, I know It's been 8 years still... you saved me from a great deal of frustration + time.
     
    IndieFist likes this.
  4. IndieFist

    IndieFist

    Joined:
    Jul 18, 2013
    Posts:
    520
    i got error in this line
    if (obstacleAvoid previousCastMissed Physics.Raycast(leftR.position, transform.forward, out hit, probeRange)) {
     
  5. andychy

    andychy

    Joined:
    Oct 21, 2018
    Posts:
    1
    place && between like:
    obstacleAvoid && previousCastMissed && Physics.Raycast