| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- public class Pathfinding {
- private const int MOVE_STRAIGHT_COST = 10;
- private const int MOVE_DIAGONAL_COST = 14;
- public static Pathfinding instance { get; private set; }
- private GridXZ<PathNode> grid;
- private List<PathNode> openList;
- private List<PathNode> closedList;
- public Pathfinding(int widht, int height) {
- instance = this;
- grid = new GridXZ<PathNode>(widht, height, 10f, Vector3.zero, (GridXZ<PathNode> g, int x, int y) => new PathNode(g, x, y));
- }
- public GridXZ<PathNode> GetGrid() {
- return grid;
- }
- public List<Vector3> FindPath(Vector3 startWorldPosition, Vector3 enWorldPosition) {
- grid.GetXZ(startWorldPosition, out int startX, out int startZ);
- grid.GetXZ(enWorldPosition, out int endX, out int endZ);
- List<PathNode> path = FindPath(startX, startZ, endX, endZ);
- if (path == null) {
- return null;
- } else {
- List<Vector3> vectorPath = new List<Vector3>();
- foreach (PathNode pathNode in path) {
- vectorPath.Add(new Vector3(pathNode.x, pathNode.z) * grid.GetCellSize() + Vector3.one * grid.GetCellSize() * .5f);
- }
- return vectorPath;
- }
- }
- public List<PathNode> FindPath(int startX, int startZ, int endX, int endZ) {
- PathNode startNode = grid.GetGridObject(startX, startZ);
- PathNode endNode = grid.GetGridObject(endX, endZ);
- if (endNode == null || startNode == null) {
- return null;
- }
- openList = new List<PathNode> { startNode };
- closedList = new List<PathNode>();
- for (int x = 0; x < grid.GetWidth(); x++) {
- for (int z = 0; z < grid.GetHeight(); z++) {
- PathNode pathNode = grid.GetGridObject(x, z);
- pathNode.gCost = int.MaxValue;
- pathNode.CalculateFCost();
- pathNode.cameFromNode = null;
- }
- }
- startNode.gCost = 0;
- Debug.Log("endX: " + endX + " endY: " + endZ);
- startNode.hCost = CalculateDistanceCost(startNode, endNode);
- startNode.CalculateFCost();
- while (openList.Count > 0) {
- PathNode currentNode = GetLowestFCostNode(openList);
- if (currentNode == endNode) {
- // Reached final node
- // PathfindingDebugStepVisual.Instance.TakeSnapshot(grid, currentNode, openList, closedList);
- // PathfindingDebugStepVisual.Instance.TakeSnapshotFinalPath(grid, CalculatePath(endNode));
- return CalculatePath(endNode);
- }
- openList.Remove(currentNode);
- closedList.Add(currentNode);
- foreach (PathNode neighbourNode in GetNeighbourList(currentNode)) {
- if (closedList.Contains(neighbourNode)) continue;
- if (!neighbourNode.isWalkable) {
- closedList.Add(neighbourNode);
- continue;
- }
- int tentativeGCost = currentNode.gCost + CalculateDistanceCost(currentNode, neighbourNode);
- if (tentativeGCost < neighbourNode.gCost) {
- neighbourNode.cameFromNode = currentNode;
- neighbourNode.gCost = tentativeGCost;
- neighbourNode.hCost = CalculateDistanceCost(neighbourNode, endNode);
- neighbourNode.CalculateFCost();
- if (!openList.Contains(neighbourNode)) {
- openList.Add(neighbourNode);
- }
- }
- // PathfindingDebugStepVisual.Instance.TakeSnapshot(grid, currentNode, openList, closedList);
- }
- }
- // Out of nodes on the open list
- return null;
- }
- public PathNode GetNode(int x, int z) {
- return grid.GetGridObject(x, z);
- }
- private List<PathNode> GetNeighbourList(PathNode currentNode) {
- List<PathNode> neighbourList = new List<PathNode>();
- if (currentNode.x - 1 >= 0) {
- // Left
- neighbourList.Add(GetNode(currentNode.x - 1, currentNode.z));
- // Left Down
- if (currentNode.z - 1 >= 0) neighbourList.Add(GetNode(currentNode.x - 1, currentNode.z - 1));
- // Left Up
- if (currentNode.z + 1 < grid.GetHeight()) neighbourList.Add(GetNode(currentNode.x - 1, currentNode.z + 1));
- }
- if (currentNode.x + 1 < grid.GetWidth()) {
- // Right
- neighbourList.Add(GetNode(currentNode.x + 1, currentNode.z));
- // Right Down
- if (currentNode.z - 1 >= 0) neighbourList.Add(GetNode(currentNode.x + 1, currentNode.z - 1));
- // Right Up
- if (currentNode.z + 1 < grid.GetHeight()) neighbourList.Add(GetNode(currentNode.x + 1, currentNode.z + 1));
- }
- // Down
- if (currentNode.z - 1 >= 0) neighbourList.Add(GetNode(currentNode.x, currentNode.z - 1));
- // Up
- if (currentNode.z + 1 < grid.GetHeight()) neighbourList.Add(GetNode(currentNode.x, currentNode.z + 1));
- return neighbourList;
- }
- private List<PathNode> CalculatePath(PathNode endNode) {
- List<PathNode> path = new List<PathNode>();
- path.Add(endNode);
- PathNode currentNode = endNode;
- while (currentNode.cameFromNode != null) {
- path.Add(currentNode.cameFromNode);
- currentNode = currentNode.cameFromNode;
- }
- path.Reverse();
- return path;
- }
- private int CalculateDistanceCost(PathNode a, PathNode b) {
- int xDistance = Mathf.Abs(a.x - b.x);
- int yDistance = Mathf.Abs(a.z - b.z);
- int remaining = Mathf.Abs(xDistance - yDistance);
- return MOVE_DIAGONAL_COST * Mathf.Min(xDistance, yDistance) + MOVE_STRAIGHT_COST * remaining;
- }
- private PathNode GetLowestFCostNode(List<PathNode> pathNodeList) {
- PathNode lowestFCostNode = pathNodeList[0];
- for (int i = 1; i < pathNodeList.Count; i++) {
- if (pathNodeList[i].fCost < lowestFCostNode.fCost) {
- lowestFCostNode = pathNodeList[i];
- }
- }
- return lowestFCostNode;
- }
- }
|