Advertisement
Guest User

Untitled

a guest
Feb 14th, 2017
105
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 8.41 KB | None | 0 0
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Threading;
  5.  
  6. public class Seeker : Actor
  7. {
  8.     //is the pathfinding thread running
  9.     bool searchingPath = false;
  10.     //the path
  11.     public List<NodeElement> path = new List<NodeElement>();
  12.     //the node we're currently standing on
  13.     public NodeElement curNode;
  14.     //the last node we were trying to reach
  15.     public NodeElement LastDestination;
  16.     public NodeElement LastPathElement()
  17.     {
  18.         return path[path.Count - 1];
  19.     }
  20.  
  21.     public Animator anim;
  22.     public float Speed = 4;
  23.  
  24.     public Quaternion DesiredRotation;
  25.     protected virtual void Rotate()
  26.     {
  27.         if (path.Count > 1)
  28.         {
  29.             DesiredRotation = Quaternion.LookRotation(path[1].pos() - curNode.pos());
  30.             transform.rotation = Quaternion.Slerp(transform.rotation, DesiredRotation, Time.deltaTime * 4);
  31.  
  32.         }
  33.     }
  34.     public bool StoppedMoving()
  35.     {
  36.         return path.Count <= 1;
  37.     }
  38.     float recalculateCooldown = 0;
  39.     //gets called every frame
  40.     protected void RecalculatePath()
  41.     {
  42.         //recalculate path if someone is infront of us
  43.         if (path.Count > 1)
  44.         {
  45.             if (path[1].occupied != null && recalculateCooldown > 1)
  46.             {
  47.                 recalculateCooldown = 0;
  48.                 SetDestination(LastDestination, true);
  49.             }
  50.             else
  51.             {
  52.                 recalculateCooldown += Time.deltaTime;
  53.             }
  54.         }
  55.         //or recalculate the path if we somehow ended up standing on someone else's node, no clue how to avoid having to do this
  56.         else
  57.         {
  58.             if (curNode.occupied != this && recalculateCooldown > 1)
  59.             {
  60.                 recalculateCooldown = 0;
  61.                 SetDestination(curNode, true);
  62.             }
  63.             else
  64.             {
  65.                 recalculateCooldown += Time.deltaTime;
  66.             }
  67.         }
  68.         //redo the path if it was initially too short
  69.         if (recalculating)
  70.         {
  71.             recalculateTimer += Time.deltaTime;
  72.             if (recalculateTimer > 0.5f)
  73.             {
  74.                 recalculateTimer = 0;
  75.                 recalculating = false;
  76.                 SetDestination(LastDestination, true);
  77.             }
  78.         }
  79.     }
  80.     public override void LateUpdate()
  81.     {
  82.         base.LateUpdate();
  83.         //draw the path in the editor
  84.         if (path.Count > 1)
  85.         {
  86.             for (int i = 0; i < path.Count - 1; i++)
  87.             {
  88.                 Debug.DrawLine(path[i].pos(), path[i + 1].pos(), Color.blue);
  89.             }
  90.         }
  91.         //check for path reculculation needs
  92.         RecalculatePath();
  93.  
  94.         // Rotate();
  95.         //if we're not currently remaking the path,  we can use it
  96.         if (!searchingPath)
  97.         {
  98.             //if it's more than the current node, move to the next one
  99.             if (path.Count > 1)
  100.             {
  101.                 Vector3 pos = path[1].pos();
  102.                 transform.position = Vector3.Slerp(transform.position, pos, 0.04f * Speed);
  103.                 if (Vector3.Distance(transform.position, pos) < 0.1f)
  104.                 {
  105.                     path[0].occupied = null;
  106.                     path.RemoveAt(0);
  107.                     path[0].occupied = this;
  108.                     curNode = path[0];
  109.                 }
  110.                 //  anim.SetFloat("Speed", 1);
  111.             }
  112.         }
  113.     }
  114.  
  115.     public void SetDestination(Vector3 _pos, bool recalculatingp = false)
  116.     {
  117.  
  118.         int x = Mathf.RoundToInt(_pos.x);
  119.         int y = Mathf.RoundToInt(_pos.z);
  120.         SetDestination(PathfindingMap.VecToNode(x, y), recalculatingp);
  121.     }
  122.     Thread PathFinder;
  123.     public void SetDestination(NodeElement goal, bool recalculatingp = false)
  124.     {
  125.         if (goal != null)
  126.             if (SquareGrid.InBounds(goal))
  127.             {
  128.                 //if we're not doing the same pathfinding check as before, or if we're recalculating it
  129.                 if ((goal != curNode && goal != LastDestination) || recalculatingp == true)
  130.                 {
  131.                     LastDestination = goal;
  132.                     goal = SquareGrid.FindNearestReachable(this, goal, recalculatingp);
  133.                     searchingPath = true;
  134.                     if (PathFinder != null)
  135.                         PathFinder.Abort();
  136.                     PathFinder = new Thread(() => MultiThreadAStar(goal));
  137.                     PathFinder.Start();
  138.                 }
  139.             }
  140.     }
  141.  
  142.     static public double Heuristic(NodeElement a, NodeElement b)
  143.     {
  144.         float x = Mathf.Abs(a.x - b.x);
  145.         float y = Mathf.Abs(a.y - b.y);
  146.         //add 0.1f to make diagonal paths less likely
  147.         return x + y + (x == y ? 0.1f : 0);
  148.     }
  149.     public NodeElement _start, _goal, closestPossible;
  150.     PriorityQueue frontier;
  151.     //which node came from which node
  152.     public Dictionary<NodeElement, NodeElement> camefrom = new Dictionary<NodeElement, NodeElement>();
  153.     //how much it cost to reach the given node starting from the current node
  154.     public Dictionary<NodeElement, double> costsofar = new Dictionary<NodeElement, double>();
  155.     protected bool unreachableTarget = false;
  156.     //gets called as a new thread
  157.     public void MultiThreadAStar(NodeElement goal)
  158.     {
  159.         path.Clear();
  160.         //reference to the map
  161.         SquareGrid graph = PathfindingMap.grid();
  162.         //frontier/priority que
  163.         frontier = new PriorityQueue();
  164.         //add the current node as the start of the frontier
  165.         frontier.Enqueue(curNode, 0);
  166.         _start = curNode;
  167.         _goal = goal;
  168.         camefrom.Clear();
  169.         costsofar.Clear();
  170.         //first node came from itself, cost 0
  171.         camefrom[_start] = _start;
  172.         costsofar[_start] = 0;
  173.         closestPossible = _start;
  174.         //do this until the frontier becomes empty (or we reach the goal)
  175.         while (frontier.Count > 0)
  176.         {
  177.             //current node is the one closest to the goal
  178.             NodeElement current = frontier.Dequeue();
  179.             if (current.Equals(goal))
  180.             {
  181.                 break;
  182.             }
  183.             //regular A* neighbors, in other words everyone surrounding the current node
  184.             foreach (var next in SquareGrid.Neighbors(current, this))
  185.             {
  186.                 //ignore it if it's occupied by another unit
  187.                 if (next.occupied == null)
  188.                 {
  189.                     //add it to the optimal paths if it isn't in the frontier, or it's cost is lower than the current one
  190.                     double newCost = costsofar[current] + graph.Cost(current, next);
  191.                     if (!costsofar.ContainsKey(next)
  192.                       || newCost < costsofar[next])
  193.                     {
  194.                         double h = Heuristic(next, goal);
  195.                         double h2 = Heuristic(closestPossible, goal);
  196.                         double priority = newCost + Heuristic(next, goal);
  197.                         frontier.Enqueue(next, priority);
  198.                         camefrom[next] = current;
  199.                         costsofar[next] = newCost;
  200.                         //save the closest node to the goal, in case we can't reach the goal
  201.                         if (h2 > h)
  202.                         {
  203.                             closestPossible = next;
  204.                         }
  205.                     }
  206.                 }
  207.             }
  208.         }
  209.         //reconstruct the path  
  210.         NodeElement _next = _goal;
  211.         //end of the path is the closest node to the goal
  212.         if (!camefrom.ContainsKey(_next))
  213.         {
  214.             _next = closestPossible;
  215.         }
  216.         if (camefrom[_next] == _start)
  217.         {
  218.             path.Add(_next);
  219.         }
  220.         for (int i = 0; i < camefrom.Count; i++)
  221.         {
  222.             _next = camefrom[_next];
  223.             path.Add(_next);
  224.             if (_next == _start)
  225.             {
  226.                 path.Reverse();
  227.                 break;
  228.             }
  229.         }
  230.         //if the path is too short, the unit was probably surrounded and couldn't move, restart the path in a second or so
  231.         if (path.Count <= 2 && Vector3.Distance(curNode.pos(), LastDestination.pos()) > 2.5f)
  232.         {
  233.             recalculating = true;
  234.             recalculateTimer = 0;
  235.         }
  236.         searchingPath = false;
  237.     }
  238.     bool recalculating = false;
  239.     float recalculateTimer = 0;
  240. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement