ProjectCreep/Assets/TBTK/Scripts/AStar.cs

226 lines
6.3 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace TBTK{
public class AStar{
public enum _BypassUnit{ No, FriendlyOnly, All }
public static int BypassUnitCode(Unit unit){
if(unit.canMovePastUnit==_BypassUnit.No) return -1;
else if(unit.canMovePastUnit==_BypassUnit.All) return -2;
else return unit.facID;
}
public static int BypassUnitCode(bool bypassUnit){
return bypassUnit ? -2 : -1 ;
}
public static bool IgnoreAllUnit(int flag){ return flag==-2; }
public static bool CantBypassUnit(int flag){ return flag==-1; }
public static bool BypassFriendlyUnit(int flag){ return flag>=0; }
//search for a path, through walkable tile only
//for normal movement, return the path in a list of hexTile
//public static List<Node> SearchWalkableNode(Node originNode, Node destNode, bool returnNearest=true){
//~ public static List<Node> SearchWalkableNode(Node originNode, Node destNode, bool bypassUnit=true, bool bypassObs=true, bool returnNearest=true){
//~ return SearchWalkableNode(originNode, destNode, BypassUnitCode(bypassUnit), bypassObs, returnNearest);
//~ }
public static List<Node> SearchWalkableNode(Node originNode, Node destNode, int bypassUnit=-1, bool bypassObs=true, bool returnNearest=true){
GridManager.ResetGrid();
List<Node> closeList=new List<Node>();
List<Node> openList=new List<Node>();
Node currentNode=originNode;
float currentLowestF=Mathf.Infinity;
int id=0;
int i=0;
while(true){
//if we have reach the destination
if(currentNode==destNode) break;
//move currentNode to closeList;
closeList.Add(currentNode);
currentNode.listState=Node._ListState.Close;
//loop through the neighbour of current loop, calculate score and stuff
currentNode.ProcessNeighbour(destNode.GetPos(), bypassUnit, bypassObs);
//put all neighbour in openlist
foreach(Node neighbour in currentNode.GetNeighbourList(true, bypassUnit, bypassObs)){
if(neighbour.IsBlocked(currentNode, bypassUnit, bypassObs)) continue;
if(neighbour.listState==Node._ListState.Unassigned || neighbour==destNode){
//~ //set the node state to open
neighbour.listState=Node._ListState.Open;
openList.Add(neighbour);
}
}
//clear the current node, before getting a new one, so we know if there isnt any suitable next node
currentNode=null;
currentLowestF=Mathf.Infinity;
id=0;
for(i=0; i<openList.Count; i++){
if(openList[i]==destNode){
currentNode=openList[i];
id=i; break;
}
if(openList[i].scoreF<currentLowestF){
currentLowestF=openList[i].scoreF;
currentNode=openList[i];
id=i;
}
}
//if there's no node left in openlist, path doesnt exist
if(currentNode==null){
if(!returnNearest) return new List<Node>();
break;
}
openList.RemoveAt(id);
}
if(currentNode==null){
float tileSize=GridManager.GetNodeSize();//*GridManager.GetGridToTileSizeRatio();
currentLowestF=Mathf.Infinity;
for(i=0; i<closeList.Count; i++){
float dist=Vector3.Distance(destNode.GetPos(), closeList[i].GetPos());
if(dist<currentLowestF){
currentLowestF=dist;
currentNode=closeList[i];
if(dist<tileSize*1.5f) break;
}
}
}
List<Node> path=new List<Node>();
while(currentNode!=null){
if(currentNode==originNode || currentNode==currentNode.parent) break;
path.Add(currentNode);
currentNode=currentNode.parent;
}
path=InvertNodeArray(path);
ResetGraph(destNode, openList, closeList);
return path;
}
/*
//search the shortest path through all tile reagardless of status
//this is used to accurately calculate the distance between 2 tiles in term of tile
//distance calculated applies for line traverse thru walkable tiles only, otherwise it can be calculated using the coordinate
public static int GetDistance(Tile srcTile, Tile targetTile){
List<Tile> closeList=new List<Tile>();
List<Tile> openList=new List<Tile>();
Tile currentTile=srcTile;
if(srcTile==null) Debug.Log("src tile is null!!!");
float currentLowestF=Mathf.Infinity;
int id=0;
int i=0;
while(true){
//if we have reach the destination
if(currentTile==targetTile) break;
//move currentNode to closeList;
closeList.Add(currentTile);
currentTile.aStar.listState=Node._ListState.Close;
//loop through all neighbours, regardless of status
//currentTile.ProcessAllNeighbours(targetTile);
currentTile.aStar.ProcessWalkableNeighbour(targetTile);
//put all neighbour in openlist
foreach(Tile neighbour in currentTile.aStar.GetNeighbourList()){
if(neighbour.unit!=null && neighbour!=targetTile) continue;
if(neighbour.aStar.listState==Node._ListState.Unassigned) {
//set the node state to open
neighbour.aStar.listState=Node._ListState.Open;
openList.Add(neighbour);
}
}
currentTile=null;
currentLowestF=Mathf.Infinity;
id=0;
for(i=0; i<openList.Count; i++){
if(openList[i].aStar.scoreF<currentLowestF){
currentLowestF=openList[i].aStar.scoreF;
currentTile=openList[i];
id=i;
}
}
if(currentTile==null) return -1;
openList.RemoveAt(id);
}
int counter=0;
while(currentTile!=null){
counter+=1;
currentTile=currentTile.aStar.parent;
}
ResetGraph(targetTile, openList, closeList);
return counter-1;
}
*/
private static List<Vector3> InvertArray(List<Vector3> p){
List<Vector3> pInverted=new List<Vector3>();
for(int i=0; i<p.Count; i++){
pInverted.Add(p[p.Count-(i+1)]);
}
return pInverted;
}
private static List<Node> InvertNodeArray(List<Node> p){
List<Node> pInverted=new List<Node>();
for(int i=0; i<p.Count; i++){
pInverted.Add(p[p.Count-(i+1)]);
}
return pInverted;
}
//reset all the tile, called after a search is complete
private static void ResetGraph(Node hNode, List<Node> oList, List<Node> cList){
hNode.ResetListState();
hNode.parent=null;
foreach(Node node in oList){
node.ResetListState();
node.parent=null;
}
foreach(Node node in cList){
node.ResetListState();
node.parent=null;
}
}
}
}