Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using UnityEngine;
- // A* needs only a WeightedGraph and a Vector3 type L, and does *not*
- // have to be a grid. However, in the example code I am using a grid.
- public class SquareGrid
- {
- // Implementation notes: I made the fields public for convenience,
- // but in a real project you'll probably want to follow standard
- // style and make them private.
- public static readonly Vector3[] DIRS = new[]
- {
- new Vector3(1,0, 0),
- new Vector3(1,0, 1),
- new Vector3(1,0, -1),
- new Vector3(-1,0, 1),
- new Vector3(-1,0, -1),
- new Vector3(0,0, -1),
- new Vector3(-1,0, 0),
- new Vector3(0,0, 1)
- };
- public int width, height;
- //public HashSet<NodeElement> walls = new HashSet<NodeElement>();
- //public HashSet<NodeElement> forests = new HashSet<NodeElement>();
- public NodeElement[,] nodes;
- public SquareGrid(int width, int height)
- {
- nodes = new NodeElement[width, height];
- for (int x = 0; x < width; x++)
- {
- for (int y = 0; y < height; y++)
- {
- //nodes[x, y].item1 = new Vector3(x, 0, y);
- //nodes[x, y].item2 = 1;
- //nodes[x, y].passable = true;
- nodes[x, y] = new NodeElement(new Vector3(x, 0, y), 1, true);
- }
- }
- this.width = width;
- this.height = height;
- }
- public NodeElement FindNode(int x, int y)
- {
- if (InBounds(x, y))
- return nodes[x, y];
- return null;
- }
- public bool InBounds(NodeElement id)
- {
- return 0 <= id.item1.x && id.item1.x < width
- && 0 <= id.item1.z && id.item1.z < height;
- }
- public bool InBounds(int x, int y)
- {
- return 0 < x && x < width
- && 0 <= y && y < height;
- }
- public bool Passable(NodeElement id)
- {
- return id.passable && id.occupied == false;//!walls.Contains(id);
- }
- public double Cost(NodeElement b)
- {
- return b.item2;//forests.Contains(b) ? 5 : 1;
- }
- public IEnumerable<NodeElement> Neighbors(NodeElement id)
- {
- foreach (var dir in DIRS)
- {
- int x = (int)(id.item1.x + dir.x);
- int y = (int)(id.item1.z + dir.z);
- if (InBounds(x, y))
- {
- NodeElement next = FindNode(x, y);
- if (Passable(next))
- {
- yield return next;
- }
- }
- }
- }
- }
- public class NodeElement
- {
- public Vector3 item1;
- public double item2;
- public bool passable;
- public Seeker occupied;
- public NodeElement(Vector3 _node, double _double, bool _passable)
- {
- item1 = _node;
- item2 = _double;
- passable = _passable;
- occupied = null;
- }
- public NodeElement()
- {
- item1 = Vector3.zero;
- item2 = 0;
- passable = false;
- occupied = null;
- }
- }
- public class PriorityQueue
- {
- // I'm using an unsorted array for this example, but ideally this
- // would be a binary heap. Find a binary heap class:
- // * https://bitbucket.org/BlueRaja/high-speed-priority-queue-for-c/wiki/Home
- // * http://visualstudiomagazine.com/articles/2012/11/01/priority-queues-with-c.aspx
- // * http://xfleury.github.io/graphsearch.html
- // * http://stackoverflow.com/questions/102398/priority-queue-in-net
- private List<NodeElement> elements = new List<NodeElement>();
- public int Count
- {
- get { return elements.Count; }
- }
- public void Enqueue(Vector3 item, double priority, bool passable)
- {
- elements.Add(new NodeElement(item, priority, passable));
- }
- public void Enqueue(NodeElement next)
- {
- elements.Add(next);
- }
- public NodeElement Dequeue()
- {
- int bestIndex = 0;
- for (int i = 0; i < elements.Count; i++)
- {
- if (elements[i].item2 < elements[bestIndex].item2)
- {
- bestIndex = i;
- }
- }
- NodeElement bestItem = elements[bestIndex];
- elements.RemoveAt(bestIndex);
- return bestItem;
- }
- }
- /* NOTE about types: in the main article, in the Python code I just
- * use numbers for costs, heuristics, and priorities. In the C++ code
- * I use a typedef for this, because you might want int or double or
- * another type. In this C# code I use double for costs, heuristics,
- * and priorities. You can use an int if you know your values are
- * always integers, and you can use a smaller size number if you know
- * the values are always small. */
- public class AStarSearch
- {
- public Dictionary<NodeElement, NodeElement> cameFrom
- = new Dictionary<NodeElement, NodeElement>();
- public Dictionary<NodeElement, double> costSoFar
- = new Dictionary<NodeElement, double>();
- // Note: a generic version of A* would abstract over Vector3 and
- // also Heuristic
- static public double Heuristic(Vector3 a, Vector3 b)
- {
- return Math.Abs(a.x - b.x) + Math.Abs(a.y - b.y);
- }
- NodeElement _start, _goal;
- public AStarSearch(SquareGrid graph, NodeElement start, NodeElement goal)
- {
- var frontier = new PriorityQueue();
- frontier.Enqueue(start);
- _start = start;
- _goal = goal;
- cameFrom[start] = start;
- costSoFar[start] = 0;
- while (frontier.Count > 0)
- {
- NodeElement current = frontier.Dequeue();
- if (current.Equals(goal))
- {
- break;
- }
- foreach (var next in graph.Neighbors(current))
- {
- double newCost = costSoFar[current]
- + graph.Cost(next);
- if (!costSoFar.ContainsKey(next)
- || newCost < costSoFar[next])
- {
- costSoFar[next] = newCost;
- double priority = newCost + Heuristic(next.item1, goal.item1);
- frontier.Enqueue(next);
- cameFrom[next] = current;
- }
- }
- }
- }
- public List<NodeElement> FindShortestPath()
- {
- NodeElement next = _goal;
- List<NodeElement> path = new List<NodeElement>();
- path.Add(next);
- if (cameFrom.ContainsKey(next))
- {
- for (int i = 0; i < cameFrom.Count; ++i)
- {
- next = cameFrom[next];
- path.Add(next);
- if (next == _start)
- {
- path.Reverse();
- break;
- }
- }
- }
- return path;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement