public bool TryMoveInPath(CollisionCheckEnum colCheck) //try to move in previous path { if (path == null) { return(false); } pathIndex++; if (pathIndex >= path.Count) //if stepsId larger than list, it means previous path has done { path = null; return(false); } Tile nextInPath = path[pathIndex]; if (!GameMaster.instance.IsTileOccupied(nextInPath, colCheck)) //if not occupied, move { StartCoroutine(MovingDirectlyTo(nextInPath)); return(true); } else { return(false); } }
public bool IsTileOccupied(Tile tile, CollisionCheckEnum cce) { if (cce == CollisionCheckEnum.Character || cce == CollisionCheckEnum.All) { foreach (CharacterComponent ch in charsList) { if (tile.Equals(ch.currentTile)) { return(true); } } } if (cce == CollisionCheckEnum.Enemy || cce == CollisionCheckEnum.All) { foreach (EnemyComponent en in enemiesList) { if (tile.Equals(en.currentTile)) { return(true); } } } return(false); }
public bool TryMoveInsideRange(Tile goal, CollisionCheckEnum colCheck) //shortcut for creating path and move in one call { if (TryMakePathInsideRange(goal) && TryMoveInPath(colCheck)) //if path successfully created and successfully moved { return(true); } else { return(false); } }
public bool TryMoveDirectlyTo(Tile target, CollisionCheckEnum colCheck) { if (!GameMaster.instance.IsTileOccupied(target, colCheck)) { StartCoroutine(MovingDirectlyTo(target)); return(true); } else { return(false); } }
public void GenerateMovementRange(MovementType at, CollisionCheckEnum colCheck) { movementRange = TileRange.instance.SetMovementTileRange(at, thisUnit.currentTile, colCheck); }
public Dictionary <Tile, Tile> SetMovementTileRange(MovementType moveType, Tile center, CollisionCheckEnum colCheck) { ActionData ad = ActionDatabase.GetMovementData(moveType); Dictionary <Tile, Tile> rangeTile = new Dictionary <Tile, Tile>(); int maxCost = ad.maxDist / 2; //should be square so maxCost will always same rangeTile = Pathfinding.DijkstraPathfinding(center, maxCost, colCheck); return(rangeTile); }
/// <summary> /// Dijkstras pathfinding for searching area from start tile within maxSteps, including where coming /// </summary> public static Dictionary <Tile, Tile> DijkstraPathfinding(Tile startTile, int maxCost, CollisionCheckEnum colCheck) { //info of where this tile comes from other tile Dictionary <Tile, Tile> cameFrom = new Dictionary <Tile, Tile>(); //info of total cost in certain tile Dictionary <Tile, float> totalCost = new Dictionary <Tile, float>(); //list all the target tile that will be explored PriorityQueue <Tile> targets = new PriorityQueue <Tile>(); targets.Enqueue(0, startTile); totalCost.Add(startTile, 0); while (targets.Count > 0) { Tile current = targets.Dequeue(); //get the best tile foreach (Tile neighbour in current.neighbours) { if (GameMaster.instance.IsTileOccupied(neighbour, colCheck)) { continue; } //add the total cost with next tile cost float newCost = totalCost[current] + neighbour.cost; //if the newCost is greater than maxCost, skip it if (newCost > maxCost) { continue; } //if the neighbour is unexplored OR(then) if the new cost is cheaper than other path if (!totalCost.ContainsKey(neighbour) || newCost < totalCost[neighbour]) { //replace it totalCost[neighbour] = newCost; //priority based on cost of movement and total distance float priority = newCost + current.DistanceToTile(neighbour); //register the next tile based on the priority targets.Enqueue(priority, neighbour); //register current tile as previous tile before next tile if (cameFrom.ContainsKey(neighbour)) { cameFrom[neighbour] = current; } else { cameFrom.Add(neighbour, current); } } } } return(cameFrom); }
/// <summary> /// A star pathfinding to determine shortest path from start to goal /// </summary> public static List <Tile> AStarPathfinding(Tile startTile, Tile goal, CollisionCheckEnum colCheck) { //info of where this tile comes from other tile Dictionary <Tile, Tile> cameFrom = new Dictionary <Tile, Tile>(); //info of total cost in certain tile Dictionary <Tile, float> totalCost = new Dictionary <Tile, float>(); //list all the target tile that will be explored PriorityQueue <Tile> targets = new PriorityQueue <Tile>(); targets.Enqueue(0, startTile); cameFrom.Add(startTile, null); totalCost.Add(startTile, 0); while (targets.Count > 0) { Tile current = targets.Dequeue(); //get the best tile if (current == goal) { break; //if reaches goal already } foreach (Tile neighbour in current.neighbours) { if (GameMaster.instance.IsTileOccupied(neighbour, colCheck)) //if next tile is occupied, skip { continue; } //add the total cost with next tile cost float newCost = totalCost[current] + neighbour.cost; //if neighbour is diagonal to current, add a little cost so they prefer straight line rather than diagonal if (current.DiagonalTo(neighbour)) { newCost += 0.01f; } //if the neighbour is unexplored OR(then) if the new cost is cheaper than other path if (!totalCost.ContainsKey(neighbour) || newCost < totalCost[neighbour]) { //replace it totalCost[neighbour] = newCost; //priority based on cost of movement and total distance // !!!!! // 2016-10-09 I think this is wrong, there is no distance to goal counted... float priority = newCost + current.DistanceToTile(neighbour); //register the next tile based on the priority targets.Enqueue(priority, neighbour); //register current tile as previous tile before next tile if (cameFrom.ContainsKey(neighbour)) { cameFrom[neighbour] = current; } else { cameFrom.Add(neighbour, current); } } } } List <Tile> results = new List <Tile>(); Tile curr = goal; //return results until start point while (curr != null) { results.Add(curr); //add current tile if (cameFrom.ContainsKey(curr)) { curr = cameFrom[curr]; //next tile is previous tile } else { break; } } results.Reverse(); //reverse it return(results); }