Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using UnityEngine;
- using System.Collections;
- using System.Collections.Generic;
- public struct Point<T>
- {
- public T x, y;
- public Point(T x, T y)
- {
- this.x = x;
- this.y = y;
- }
- }
- public class AStar : MonoBehaviour
- {
- private class Node
- {
- public enum State
- {
- NONE,
- CLOSED,
- OPEN
- }
- public uint x, y;
- public State state;
- public bool walkable;
- private Node _parent = null;
- public Node parent
- {
- get { return _parent; }
- set
- {
- _parent = value;
- G = value.G + calculateCostGBetween(value.x, value.y, x, y);
- }
- }
- public uint G { get; private set; }
- public uint H { get; private set; }
- public uint F { get { return G + H; } }
- public Node(uint x, uint y, uint xGoal, uint yGoal, bool walkable)
- {
- // Set the position.
- this.x = x;
- this.y = y;
- // Whether walkable.
- this.walkable = walkable;
- // Default state.
- this.state = State.NONE;
- // Calculate cost to goal heuristic.
- H = calculateCostHBetween(x, y, xGoal, yGoal);
- }
- }
- private const uint costStraight = 10u;
- private const uint costDiagonal = 14u;
- Node[,] nodes;
- uint xGoal, yGoal;
- Node nodeGoal;
- public Point<uint>[] calculatePath(uint xStart, uint yStart, uint xGoal, uint yGoal, int[,] map)
- {
- // If already at the target, do nothing.
- if (xStart == xGoal && yStart == yGoal)
- return null;
- // If the points are not walkable, do nothing.
- if (!isWalkable(map[xStart, yStart]) || !isWalkable(map[xGoal, yGoal]))
- return null;
- // Store goal before resetting nodes; new nodes need to access it.
- this.xGoal = xGoal;
- this.yGoal = yGoal;
- // Clear nodes.
- resetNodes(map);
- // Set end node.
- nodeGoal = nodes[xGoal, yGoal];
- // Create the first node. It it sure to be walkable by now.
- var nodeCurr = nodes[xStart, yStart];
- nodeCurr.walkable = true;
- // Always open first node right away.
- nodeCurr.state = Node.State.OPEN;
- // Will store final path.
- var path = new List<Point<uint>>();
- // Recurse through and then check for success.
- if (walk(nodeCurr) && nodeGoal != null)
- {
- // Trace backwards from final node.
- Node n = nodeGoal;
- while (n.parent != null)
- {
- path.Add(new Point<uint>(n.x, n.y));
- n = n.parent;
- }
- }
- // Reverse it to get a forward path.
- path.Reverse();
- // Return the result.
- return path.ToArray();
- }
- private bool walk(Node node)
- {
- // Close the node to prevent traversing it more than once.
- node.state = Node.State.CLOSED;
- // Check adjacent nodes.
- var adjacent = new List<Node>();
- for (uint y = (uint)Mathf.Max(0, (int)node.y - 1); y <= (uint)Mathf.Min(nodes.GetLength(1) - 1, node.y + 1); ++ y)
- {
- for (uint x = (uint)Mathf.Max(0, (int)node.x - 1); x <= (uint)Mathf.Min(nodes.GetLength(0) - 1, node.x + 1); ++ x)
- {
- var n = nodes[x, y];
- // Avoid the node itself.
- if (node.x == x && node.y == y)
- continue;
- // Avoid unwalkable nodes.
- if (!n.walkable)
- continue;
- // Avoid closed nodes.
- if (n.state == Node.State.CLOSED)
- continue;
- // If the node was already opened, check if this route is faster.
- if (n.state == Node.State.OPEN)
- {
- // Get the new cost.
- uint cost = node.G + calculateCostGBetween(n.x, n.y, n.parent.x, n.parent.y);
- // Check if cheaper than old cost set by previous parent.
- if (cost < n.G)
- // Change parent.
- n.parent = node;
- }
- // Otherwise, open it.
- else
- {
- n.parent = node;
- n.state = Node.State.OPEN;
- }
- // Add it to the list and move on.
- adjacent.Add(nodes[x, y]);
- }
- }
- // If no adjacent nodes were found, we are done.
- if (adjacent.Count == 0)
- return false;
- // Otherwise, find the cheapest one. Start by sorting for cost.
- adjacent.Sort((a, b) => a.F.CompareTo(b.F));
- foreach (var n in adjacent)
- // End node or another successful walk returns true.
- if ((n.x == xGoal && n.y == yGoal) || walk(n))
- return true;
- // Dead end.
- return false;
- }
- private void resetNodes(int[,] map)
- {
- uint w = (uint)map.GetLength(0), h = (uint)map.GetLength(1);
- nodes = null;
- nodes = new Node[w, h];
- nodeGoal = null;
- for (uint y = 0; y < h; ++ y)
- for (uint x = 0; x < w; ++ x)
- nodes[x, y] = new Node(x, y, xGoal, yGoal, isWalkable(map[x, y]));
- }
- private static uint calculateCostHBetween(uint x1, uint y1, uint x2, uint y2)
- {
- return (uint)(Mathf.Max(x1, x2) - Mathf.Min(x1, x2) + Mathf.Max(y1, y2) - Mathf.Min(y1, y2)) * costStraight;
- }
- private static uint calculateCostGBetween(uint x1, uint y1, uint x2, uint y2)
- {
- return (x1 != x2 && y1 != y2) ? costDiagonal : costStraight;
- }
- private bool isWalkable(int valueInMap)
- {
- return (valueInMap == 0);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement