Advertisement
Guest User

Untitled

a guest
Apr 2nd, 2015
670
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 7.87 KB | None | 0 0
  1. //#define ASTARDEBUG
  2. using UnityEngine;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using Pathfinding;
  6. using Pathfinding.RVO;
  7.  
  8. /** AI for 2D top down games.
  9.  * This is one of the default movement scripts which comes with the A* Pathfinding Project.
  10.  * It is in no way required by the rest of the system, so feel free to write your own. But I hope this script will make it easier
  11.  * to set up movement for the characters in your game.
  12.  * \n
  13.  * This script will try to follow a target transform, and at regular intervals the path to that target will be recalculated.
  14.  *
  15.  * \section variables Quick overview of the variables
  16.  * In the inspector in Unity, you will see a bunch of variables. You can view detailed information further down, but here's a quick overview.\n
  17.  * The #repathRate determines how often it will search for new paths, if you have fast moving targets, you might want to set it to a lower value.\n
  18.  * The #target variable is where the AI will try to move, it can be a point on the ground where the player has clicked in an RTS for example.
  19.  * Or it can be the player object in a zombie game.\n
  20.  * The speed is self-explanatory, so is turningSpeed, however #slowdownDistance might require some explanation.
  21.  * It is the approximate distance from the target where the AI will start to slow down. Note that this doesn't only affect the end point of the path
  22.  * but also any intermediate points, so be sure to set #forwardLook and #pickNextWaypointDist to a higher value than this.\n
  23.  * #pickNextWaypointDist is simply determines within what range it will switch to target the next waypoint in the path.\n
  24.  * #forwardLook will try to calculate an interpolated target point on the current segment in the path so that it has a distance of #forwardLook from the AI\n
  25.  * Below is an image illustrating several variables as well as some internal ones, but which are relevant for understanding how it works.
  26.  * Note that the #forwardLook range will not match up exactly with the target point practically, even though that's the goal.
  27.  * \shadowimage{aipath_variables.png}
  28.  * This script can use a Rigidbody2D for movement or it can simply use transform.position.
  29.  * If it finds a Rigidbody2D attached to the same GameObject, it will start to use it automatically.
  30.  *
  31.  * \ingroup movementscripts
  32.  */
  33. [RequireComponent(typeof(Seeker))]
  34. [AddComponentMenu("Pathfinding/AI/AIPath (2D top down)")]
  35. public class AIPath2DTopDown : AIPathBase {
  36.    
  37.     /** Cached Rigidbody component */
  38.     protected Rigidbody2D rigid;
  39.    
  40.     /** Initializes reference variables.
  41.      * If you override this function you should in most cases call base.Awake () at the start of it.
  42.       * */
  43.     protected override void Awake () {
  44.         base.Awake ();
  45.        
  46.         //Cache some other components (not all are necessarily there)
  47.         rigid = GetComponent<Rigidbody2D>();
  48.     }
  49.    
  50.     public override Vector3 GetFeetPosition () {
  51.         return tr.position;
  52.     }
  53.    
  54.     public virtual void Update () {
  55.        
  56.         if (!canMove) { return; }
  57.        
  58.         Vector2 dir = CalculateVelocity (GetFeetPosition());
  59.        
  60.         //Rotate towards targetDirection (filled in by CalculateVelocity)
  61.         RotateTowards (targetDirection);
  62.    
  63.         if (rigid != null) {
  64.             //rigid.AddForce (dir, ForceMode2D.Impulse);
  65.             rigid.MovePosition (rigid.position + dir*Time.deltaTime);
  66.         } else {
  67.             transform.Translate (dir*Time.deltaTime, Space.World);
  68.         }
  69.     }
  70.    
  71.     /** Point to where the AI is heading.
  72.       * Filled in by #CalculateVelocity */
  73.     protected Vector2 targetPoint;
  74.     /** Relative direction to where the AI is heading.
  75.      * Filled in by #CalculateVelocity */
  76.     protected Vector2 targetDirection;
  77.    
  78.     /** Calculates desired velocity.
  79.      * Finds the target path segment and returns the forward direction, scaled with speed.
  80.      * A whole bunch of restrictions on the velocity is applied to make sure it doesn't overshoot, does not look too far ahead,
  81.      * and slows down when close to the target.
  82.      * /see speed
  83.      * /see endReachedDistance
  84.      * /see slowdownDistance
  85.      * /see CalculateTargetPoint
  86.      * /see targetPoint
  87.      * /see targetDirection
  88.      * /see currentWaypointIndex
  89.      */
  90.     protected Vector2 CalculateVelocity (Vector2 currentPosition) {
  91.         if (path == null || path.vectorPath == null || path.vectorPath.Count == 0) return Vector3.zero;
  92.        
  93.         List<Vector3> vPath = path.vectorPath;
  94.  
  95.         // Just for the rest of the code to work, if there is only one waypoint in the path
  96.         // add another one
  97.         if (vPath.Count == 1) {
  98.             vPath.Insert (0,currentPosition);
  99.         }
  100.  
  101.         // Make sure we stay inside valid ranges
  102.         currentWaypointIndex = Mathf.Clamp (currentWaypointIndex, 1, vPath.Count - 1);
  103.  
  104.         // Possibly pick the next segment
  105.         while (true) {
  106.             if (currentWaypointIndex < vPath.Count-1) {
  107.                 //There is a "next path segment"
  108.                 Vector2 nextWaypointDir = (Vector2)vPath[currentWaypointIndex] - currentPosition;
  109.                 float dist = nextWaypointDir.sqrMagnitude;
  110.                     //Mathfx.DistancePointSegmentStrict (vPath[currentWaypointIndex+1],vPath[currentWaypointIndex+2],currentPosition);
  111.                 if (dist < pickNextWaypointDist*pickNextWaypointDist) {
  112.                     lastFoundWaypointPosition = currentPosition;
  113.                     lastFoundWaypointTime = Time.time;
  114.                     currentWaypointIndex++;
  115.                 } else {
  116.                     break;
  117.                 }
  118.             } else {
  119.                 break;
  120.             }
  121.         }
  122.  
  123.         // Calculate the point we should move towards
  124.         Vector2 targetPosition = CalculateTargetPoint (currentPosition,vPath[currentWaypointIndex-1] , vPath[currentWaypointIndex]);
  125.  
  126.         // Vector to the target position
  127.         Vector2 dir = targetPosition-currentPosition;
  128.         float targetDist = dir.magnitude;
  129.        
  130.         float slowdown = Mathf.Clamp01 (targetDist / slowdownDistance);
  131.        
  132.         this.targetDirection = dir;
  133.         this.targetPoint = targetPosition;
  134.        
  135.         if (currentWaypointIndex == vPath.Count-1 && targetDist <= endReachedDistance) {
  136.             if (!targetReached) { targetReached = true; OnTargetReached (); }
  137.            
  138.             //Send a move request, this ensures gravity is applied
  139.             return Vector3.zero;
  140.         }
  141.  
  142.         // The Y axis is forward in 2D space
  143.         Vector2 forward = -tr.up;
  144.         float dot = Vector2.Dot (dir.normalized,forward);
  145.         float sp = speed * Mathf.Max (dot,minMoveScale) * slowdown;
  146.        
  147. #if ASTARDEBUG
  148.         Debug.DrawLine (vPath[currentWaypointIndex-1] , vPath[currentWaypointIndex],Color.black);
  149.         Debug.DrawLine (GetFeetPosition(),targetPosition,Color.red);
  150.         Debug.DrawRay (targetPosition,Vector3.up, Color.red);
  151.         Debug.DrawRay (GetFeetPosition(),dir,Color.yellow);
  152.         Debug.DrawRay (GetFeetPosition(),forward*sp,Color.cyan);
  153. #endif
  154.  
  155.         // Make sure we don't overshoot the target
  156.         // when the framerate is low
  157.         if (Time.deltaTime  > 0) {
  158.             sp = Mathf.Clamp (sp,0,targetDist/(Time.deltaTime*2));
  159.         }
  160.         return forward*sp;
  161.     }
  162.    
  163.     /** Rotates in the specified direction.
  164.      * Rotates around the Y-axis.
  165.      * \see turningSpeed
  166.      */
  167.     protected void RotateTowards (Vector2 dir) {
  168.        
  169.         if (dir == Vector2.zero) return;
  170.  
  171.         // Figure out the angle so that the Y axis faces dir
  172.         float angle = Mathf.Atan2 (dir.x, -dir.y)*Mathf.Rad2Deg;
  173.  
  174.         Vector3 rot = tr.eulerAngles;
  175.         rot.z = Mathf.LerpAngle (rot.z, angle, turningSpeed * Time.deltaTime);
  176.         tr.eulerAngles = rot;
  177.     }
  178.    
  179.     /** Calculates target point from the current line segment.
  180.      * \param p Current position
  181.      * \param a Line segment start
  182.      * \param b Line segment end
  183.      * The returned point will lie somewhere on the line segment.
  184.      * \see #forwardLook
  185.      * \todo This function uses .magnitude quite a lot, can it be optimized?
  186.      */
  187.     protected Vector2 CalculateTargetPoint (Vector2 p, Vector2 a, Vector2 b) {
  188.        
  189.         float magn = (a-b).magnitude;
  190.         if (magn == 0) return a;
  191.        
  192.         float closest = AstarMath.Clamp01 (AstarMath.NearestPointFactor (a, b, p));
  193.         Vector2 point = (b-a)*closest + a;
  194.         float distance = (point-p).magnitude;
  195.        
  196.         float lookAhead = Mathf.Clamp (forwardLook - distance, 0.0F, forwardLook);
  197.        
  198.         float offset = lookAhead / magn;
  199.         offset = Mathf.Clamp (offset+closest,0.0F,1.0F);
  200.         return (b-a)*offset + a;
  201.     }
  202. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement