Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

2D A* Pathfinding Enemy AI

Discussion in 'Navigation' started by LongformStudios, Oct 29, 2015.

  1. LongformStudios

    LongformStudios

    Joined:
    Nov 27, 2014
    Posts:
    6
    So I'm making a top down zombie game in Unity using the A* navigation tools. I'm trying to get my zombies to look at the direction in which they are going. I got something that sort of works, but it won't turn a certain way whenever it gets closer to the target, and on top of that when it's moving it sort of "twitches".

    Here's the code

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using Pathfinding;
    4.  
    5. [RequireComponent (typeof (Rigidbody2D))]
    6. [RequireComponent (typeof (Seeker))]
    7. public class EnemyAI : MonoBehaviour {
    8.  
    9.     // What to chase?
    10.     public Transform target;
    11.    
    12.     // How many times each second we will update our path
    13.     public float updateRate = 2f;
    14.    
    15.     // Caching
    16.     private Seeker seeker;
    17.     private Rigidbody2D rb;
    18.    
    19.     //The calculated path
    20.     public Path path;
    21.    
    22.     //The AI's speed per second
    23.     public float speed = 300f;
    24.     public ForceMode2D fMode;
    25.    
    26.     [HideInInspector]
    27.     public bool pathIsEnded = false;
    28.    
    29.     // The max distance from the AI to a waypoint for it to continue to the next waypoint
    30.     public float nextWaypointDistance = 3;
    31.    
    32.     // The waypoint we are currently moving towards
    33.     private int currentWaypoint = 0;
    34.  
    35.     private bool searchingForPlayer = false;
    36.    
    37.     void Start () {
    38.         seeker = GetComponent<Seeker>();
    39.         rb = GetComponent<Rigidbody2D>();
    40.        
    41.         if (target == null) {
    42.             if (!searchingForPlayer) {
    43.                 searchingForPlayer = true;
    44.                 StartCoroutine(SearchForPlayer());
    45.             }
    46.         }
    47.        
    48.         // Start a new path to the target position, return the result to the OnPathComplete method
    49.         seeker.StartPath (transform.position, target.position, OnPathComplete);
    50.        
    51.         StartCoroutine (UpdatePath ());
    52.     }
    53.  
    54.     IEnumerator SearchForPlayer()
    55.     {
    56.         GameObject sResult = GameObject.FindGameObjectWithTag("Player");
    57.         if (sResult == null)
    58.         {
    59.             yield return new WaitForSeconds(0.5f);
    60.             StartCoroutine(SearchForPlayer());
    61.         }
    62.         else {
    63.             searchingForPlayer = false;
    64.             target = sResult.transform;
    65.  
    66.             return false;
    67.         }
    68.  
    69.     }
    70.    
    71.     IEnumerator UpdatePath () {
    72.         if (target == null) {
    73.             //TODO: Insert a player search here.
    74.             return false;
    75.         }
    76.        
    77.         // Start a new path to the target position, return the result to the OnPathComplete method
    78.         seeker.StartPath (transform.position, target.position, OnPathComplete);
    79.        
    80.         yield return new WaitForSeconds ( 1f/updateRate );
    81.         StartCoroutine (UpdatePath());
    82.     }
    83.    
    84.     public void OnPathComplete (Path p) {
    85.         Debug.Log ("Path found. Error?" + p.error);
    86.         if (!p.error) {
    87.             path = p;
    88.             currentWaypoint = 0;
    89.         }
    90.     }
    91.    
    92.     void FixedUpdate () {
    93.         if (target == null) {
    94.             //TODO: Insert a player search here.
    95.             return;
    96.         }
    97.        
    98.         //TODO: Always look at player?
    99.        
    100.         if (path == null)
    101.             return;
    102.        
    103.         if (currentWaypoint >= path.vectorPath.Count) {
    104.             if (pathIsEnded)
    105.                 return;
    106.            
    107.             Debug.Log ("End of path reached.");
    108.             pathIsEnded = true;
    109.             return;
    110.         }
    111.         pathIsEnded = false;
    112.    
    113.         //Direction to the next waypoint
    114.         Vector3 dir = ( path.vectorPath[currentWaypoint] - transform.position ).normalized;
    115.         dir *= speed * Time.fixedDeltaTime;
    116.        
    117.         //Move the AI
    118.         rb.AddForce (dir, fMode);
    119.  
    120.         if (target != null) {
    121.             Vector2 dir = WorldPos - transform.position;
    122.             float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
    123.             transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);
    124.         }
    125.  
    126.         float dist = Vector3.Distance (transform.position, path.vectorPath[currentWaypoint]);
    127.         if (dist < nextWaypointDistance) {
    128.             currentWaypoint++;
    129.             return;
    130.         }      
    131.     }
    132. }
    133.  
    Can somebody tell me why this is? Or better yet a more effective / better way to make this happen?

    Thanks,
    James