A-STAR HEXAGONAL GRID
Description
I have created a simple implementation of the a-star and breadth-first algorithm in unity as an exercise. Tiles have a different movement cost. Walls are immovable, water costs 3 points to move on and mountains cost 5 points.
Tech
Work
Team
Programming
Code Snippets
using System.Collections; using System.Collections.Generic; using UnityEngine; static public class AStarAlgorithms { static public HaxNode[] GetPath(HaxNode start, HaxNode destination) { List<HaxNode> open = new List<HaxNode>(); List<HaxNode> closed = new List<HaxNode>(); start.AstarProperties.GCost = 0; start.AstarProperties.GCost = Grid.instance.GetDistanceHax(start, destination); open.Add(start); do { int currentNodeIndex = 0; int lowestFCost = int.MaxValue; HaxNode currentNode = null; for (int i = 0; i < open.Count; i++) { if (open[i].AstarProperties.FCost < lowestFCost) { lowestFCost = open[i].AstarProperties.FCost; currentNodeIndex = i; currentNode = open[i]; } } open.RemoveAt(currentNodeIndex); closed.Add(currentNode); foreach (HaxNode neighbor in Grid.instance.GetNeighborsHax(currentNode).ToArray()) { if (!neighbor.IsWalkable || closed.Contains(neighbor)) continue; neighbor.AstarProperties.HCost = Grid.instance.GetDistanceHax(neighbor, destination); int newCostToNeighbour = currentNode.AstarProperties.GCost + neighbor.MoveCost; if (newCostToNeighbour < neighbor.AstarProperties.GCost || !open.Contains(neighbor) /*|| currentNode.AstarProperties.GCost + neighbor.MoveCost < neighbor.AstarProperties.GCost*/) { neighbor.AstarProperties.Parent = currentNode; neighbor.AstarProperties.GCost = currentNode.AstarProperties.GCost + neighbor.MoveCost; if (!open.Contains(neighbor)) open.Add(neighbor); } } if (currentNode == destination) { List<HaxNode> path = new List<HaxNode>(); path.Add(currentNode); CreatPath(path, currentNode); ClearNodes(); return path.ToArray(); } } while (open.Count > 0); ClearNodes(); return new HaxNode[0]; } static private void CreatPath(List<HaxNode> path, HaxNode nodetogetparant) { if (nodetogetparant.AstarProperties.Parent == null) return; else path.Add(nodetogetparant.AstarProperties.Parent); CreatPath(path, nodetogetparant.AstarProperties.Parent); } static private void ClearNodes() { for (int x = 0; x < Grid.instance.m_Nodes.GetLength(0); x++) { for (int y = 0; y < Grid.instance.m_Nodes.GetLength(1); y++) { Grid.instance.m_Nodes[x, y].AstarProperties.Clear(); } } } static public HaxNode[] GetPatsh(HaxNode start, HaxNode destination) { //G = is the movement cost from the start point A to the current square. //H = is the estimated movement cost from the current square to the destination point (heuristic) //F = G+H List<HaxNode> open = new List<HaxNode>(); List<HaxNode> closed = new List<HaxNode>(); open.Add(start); while (open.Count > 0) { HaxNode currentNode = open[0]; for (int i = 1; i < open.Count; i++) { if (open[i].AstarProperties.FCost < currentNode.AstarProperties.FCost || open[i].AstarProperties.FCost == currentNode.AstarProperties.FCost) { if (open[i].AstarProperties.HCost < currentNode.AstarProperties.HCost) currentNode = open[i]; } } open.Remove(currentNode); closed.Add(currentNode); if (currentNode == destination) { return RetracePath(start, destination); } foreach (HaxNode neighbour in Grid.instance.GetNeighborsHax(currentNode)) { if (closed.Contains(neighbour) || !neighbour.IsWalkable) { continue; } int newCostToNeighbour = currentNode.AstarProperties.GCost + Grid.instance.GetDistanceHax(currentNode, neighbour); if (newCostToNeighbour >= neighbour.AstarProperties.GCost && open.Contains(neighbour)) continue; neighbour.AstarProperties.GCost = newCostToNeighbour; neighbour.AstarProperties.HCost = Grid.instance.GetDistanceHax(neighbour, destination); neighbour.AstarProperties.Parent = currentNode; if (!open.Contains(neighbour)) open.Add(neighbour); } } return null; } static private HaxNode[] RetracePath(HaxNode start, HaxNode destination) { List<HaxNode> path = new List<HaxNode>(); HaxNode currentNode = destination; while (currentNode != start) { path.Add(currentNode); currentNode = currentNode.AstarProperties.Parent; } path.Reverse(); return path.ToArray(); } } public class AStarProperties { public int GCost = 99999; public int HCost; public int FCost => GCost + HCost; public HaxNode Parent = null; public void Clear() { GCost = int.MaxValue; HCost = 0; Parent = null; } }
using System.Collections; using System.Collections.Generic; using UnityEngine; internal static class BreadthFirstAlgorithms { static public HaxNode[] FindReachable(HaxNode start, int maxMovement) { List<HaxNode> open = new List<HaxNode>(); List<HaxNode> visited = new List<HaxNode>(); open.Add(start); visited.Add(start); start.BreadthFirstProperties.DistanceMoved = 0; int SavetyLoopCount = 0; while (open.Count > 0) { HaxNode[] neighbors = Grid.instance.GetNeighborsHax(open[0]).ToArray(); for (int i = 0; i < neighbors.Length; i++) { if (open[0].BreadthFirstProperties.DistanceMoved + neighbors[i].MoveCost >= neighbors[i].BreadthFirstProperties.DistanceMoved || open[0].BreadthFirstProperties.DistanceMoved + neighbors[i].MoveCost > maxMovement) continue; neighbors[i].BreadthFirstProperties.DistanceMoved = open[0].BreadthFirstProperties.DistanceMoved + neighbors[i].MoveCost; neighbors[i].BreadthFirstProperties.Parant = open[0]; if (neighbors[i].IsWalkable) { if (!visited.Contains(neighbors[i])) visited.Add(neighbors[i]); if (!open.Contains(neighbors[i])) open.Add(neighbors[i]); } } open.RemoveAt(0); SavetyLoopCount++; if (SavetyLoopCount > 1000) break; } HexNodeCleanUp(visited); return visited.ToArray(); } static void HexNodeCleanUp(List<HaxNode> nodes) { for (int i = 0; i < nodes.Count; i++) { nodes[i].BreadthFirstProperties.DistanceMoved = int.MaxValue; nodes[i].BreadthFirstProperties.Parant = null; } } } public class BreadthFirstProperties { public int DistanceMoved = int.MaxValue; public HaxNode Parant; }
Links