public void Clear() { pathfinder.StopAllCoroutines(); Node startNode = NodeFromWorldPoint(player.position); Node targetNode = NodeFromWorldPoint(target.position); if (pathfinder.openSet != null) { pathfinder.openSet.Clear(); } if (pathfinder.closedSet != null) { pathfinder.closedSet.Clear(); } path.Clear(); if (pathfinder.openSet != null) { pathfinder.closedSet.Add(startNode); } if (pathfinder.closedSet != null) { pathfinder.SetNeighbor(startNode, targetNode); } startNode.hCost = pathfinder.GetDistance(startNode, targetNode); foreach (GameObject tile in tiles) { Tile tileThis = tile.GetComponent <Tile>(); Node thisNode = NodeFromWorldPoint(tile.transform.position); thisNode.gCost = 0; thisNode.hCost = 0; if (tileThis.tileTypeSwitch == 3 || tileThis.tileTypeSwitch == 2 || tileThis.tileTypeSwitch == 6 && !pathfinder.openSet.Contains(thisNode) && !pathfinder.closedSet.Contains(thisNode)) { tileThis.tileTypeSwitch = 1; } playerStart = true; targetStart = true; } }
void Update() { if (FirefighterManager.instance.firefighters.Count == 0) { if (Input.GetMouseButtonDown(0)) { Debug.Log("mouse clicked"); Vector3 cameraPos = Camera.main.transform.position; Vector3 mousePos = Input.mousePosition + new Vector3(0, 0, -cameraPos.z); Vector3 mousePosInWorldPoint = Camera.main.ScreenToWorldPoint(mousePos); Tile tile = grid.WorldPointToTile(mousePosInWorldPoint); if (tile.isOutside) { FirefighterManager.instance.AddFirefighter(tile.worldPosition); } } } else { if (Input.GetMouseButtonDown(0)) { Debug.Log("mouse clicked"); Vector3 cameraPos = Camera.main.transform.position; Vector3 mousePos = Input.mousePosition + new Vector3(0, 0, -cameraPos.z); Vector3 mousePosInWorldPoint = Camera.main.ScreenToWorldPoint(mousePos); Tile targetTile = grid.WorldPointToTile(mousePosInWorldPoint); firefighter = FirefighterManager.instance.firefighters[0]; Vector3 firefighterPos = firefighter.transform.position; Tile currentTile = grid.WorldPointToTile(firefighterPos); int dist = pathfinder.GetDistance(currentTile, targetTile); if (firefighter.actionPoints != 0 && firefighter.actionPoints >= dist) { firefighter.transform.position = targetTile.worldPosition; firefighter.actionPoints -= dist; Debug.Log("remaining AP: " + firefighter.actionPoints); } } } }
private HashSet <Vector2Int> RecursiveFinder(Vector2Int center, float depth) { recursiveCalls++; HashSet <Vector2Int> toReturn = new HashSet <Vector2Int>(); if (depth <= 0) { return(toReturn); } toReturn = GetValid(center); foreach (Vector2Int next in GetValid(center)) { toReturn.UnionWith(RecursiveFinder(next, depth - Pathfinding.GetDistance(next, center))); } visited.Add(center); return(toReturn); }
public Edge(Vector2Int from, Vector2Int to) { end = to; start = from; distance = (float)Pathfinding.GetDistance(to, from); }
/// <summary> /// Logic to be executed on enemy turn /// </summary> /// <param name="targets">List of possible targets</param> private void OnEnemyTurn(List <BattleEntity> targets) { target = GetTarget(targets); currentAttack = DetermineAttackScore(target); consumable = DetermineConsumableScore(); node = DetermineMoveScore(target, canAttack: currentAttack != null, canConsume: consumable != null); //print("A-score: " + attackingScore + " C-score: "+ consumableScore + " M-Score: "+moveScore); //If enemy cant do anything just end turn if (currentAttack == null && (consumable == null || consumableScore <= 0) && !canMove) { RaiseEndTurnEvent(); } state = GetState(); switch (state) { case State.Attack: print("Attacking..."); if (currentAttack != null && moveForAttack) //TODO remove the first condition { Node nodeToMoveTo = null; List <Node> movementRangeNodes = Pathfinding.GetRange(battleController.Nodes, nodeParent, (data.Speed)); int minDistance = int.MaxValue; for (int i = 0; i < movementRangeNodes.Count; i++) { if (nodeParent != movementRangeNodes[i] && target.nodeParent != movementRangeNodes[i]) { List <Node> attackRangeNodes = Pathfinding.GetRange(battleController.Nodes, movementRangeNodes[i], currentAttack.Range); int currentDistance = Pathfinding.GetDistance(target.nodeParent, movementRangeNodes[i]); if (currentDistance < minDistance) { minDistance = currentDistance; nodeToMoveTo = movementRangeNodes[i]; } } } List <Node> path = Pathfinding.FindPath(nodeParent, nodeToMoveTo, reverse: true); for (int i = 0; i < path.Count; i++) { int distance = Pathfinding.GetDistance(path[i], target.nodeParent); if (distance <= currentAttack.Range) { path = Pathfinding.FindPath(nodeParent, path[i], reverse: true); break; } } SetPathNodes(path); node = path[path.Count - 1]; checkForLocationReached = true; } else if (currentAttack != null) { Attack.AttackTarget(currentAttack, target); RaiseEndTurnEvent(); } break; case State.Consumable: print("consuming"); consumable.Consume(this); data.Consumables.Remove(consumable); print("Consuming " + consumable.Name); consumable = null; //TODO allow selecting other targets(party members) RaiseEndTurnEvent(); break; case State.Move: print("Moving..."); List <Node> _path = Pathfinding.FindPath(nodeParent, node, reverse: true); if (_path != null) { SetPathNodes(_path); node = _path[_path.Count - 1]; } checkForLocationReached = true; break; } }
private Node DetermineMoveScore(BattleEntity target, bool canAttack, bool canConsume) { List <Node> movementRange = Pathfinding.GetRange(battleController.Nodes, nodeParent, data.Speed); Node node = null; if (!canMove) { moveScore = -100000; return(null); } //IF cant attack or consume, then moving is the only option if (!canAttack && !canConsume) { //print("cant attack or comsume"); moveScore = 1000; } //TODO do stuff if health is slow aka RETREAT //if health low //Move as far as you can away //Use healing consumable int minDistance = int.MinValue; if (data.CurrentHealth <= data.MaxHealth / 2 && canConsume) { //Find node farthest from target but within range foreach (Node _node in movementRange) { int distance = Pathfinding.GetDistance(_node, target.nodeParent); if (distance > minDistance) { node = _node; minDistance = distance; } } moveScore += 200; } //Get highest range attack Attack highestRangeAttack = data.Attacks[0]; for (int i = 1; i < data.Attacks.Count; i++) { if (data.Attacks[i].Range > highestRangeAttack.Range) { highestRangeAttack = data.Attacks[i]; } } if (node == null) { //Get closest node that is within the range foreach (Node _node in movementRange) { int distance = Pathfinding.GetDistance(_node, target.nodeParent); if (distance < minDistance && distance >= highestRangeAttack.Range) { node = _node; minDistance = distance; } } } minDistance = int.MaxValue; if (node == null) { foreach (Node _node in movementRange) { int distance = Pathfinding.GetDistance(_node, target.nodeParent); if (distance < minDistance) { minDistance = distance; node = _node; } } } moveScore += 20; return(node); }
/// <summary> /// Determines the attack score /// </summary> /// <param name="target">The target</param> /// <returns>The chosen attack</returns> private Attack DetermineAttackScore(BattleEntity target) { this.RefreshParent(); int distanceToTarget = Pathfinding.GetDistance(nodeParent, target.nodeParent); target.RefreshParent(); Attack currentAttack = null; List <Attack> allAttacks = new List <Attack>(); List <Attack> attacksInReadyRange = new List <Attack>(); List <Attack> attacksInMovementRange = new List <Attack>(); foreach (Attack attack in data.Attacks) { int valueOne, valueTwo; valueOne = valueTwo = (attack.Range - distanceToTarget); if (canMove) { valueTwo += data.Speed; } //entity is able to attack if (valueOne >= 0) { allAttacks.Add(attack); attacksInReadyRange.Add(attack); attackingScore += 10; moveForAttack = false; } //Entity can attack if moves else if (valueTwo >= 0) { allAttacks.Add(attack); attacksInMovementRange.Add(attack); attackingScore += data.Speed; moveForAttack = true; } } if (attacksInReadyRange.Count > 0) { currentAttack = attacksInReadyRange[0]; } else if (attacksInMovementRange.Count > 0) { currentAttack = attacksInMovementRange[0]; } //Get the attack with highest damage //TODO factor in other values such as armour piercing for (int i = 1; i < allAttacks.Count; i++) { if (allAttacks[i].Damage > currentAttack.Damage) { currentAttack = allAttacks[i]; } } //target can be killed in one hit if (currentAttack != null && target.data.CurrentHealth <= currentAttack.Damage) { //print("Setting attack score to max"); attackingScore = 999; } else if (currentAttack != null) { attackingScore = 50; } return(currentAttack); }
private IEnumerator FindPath(Vector2 startPos, Vector2 targetPos, Grid grid) { Vector2[] waypoints = new Vector2[0]; bool pathSuccess = false; Node startNode = grid.NodeFromWorldPoint(startPos); Node targetNode = grid.NodeFromWorldPoint(targetPos); if (startNode.walkable && targetNode.walkable) { List <Node> openSet = new List <Node>(); HashSet <Node> closedSet = new HashSet <Node>(); openSet.Add(startNode); while (openSet.Count > 0) // stopper la boucle si la liste ouverte est vide { // a. Récupération du node avec le plus petit F contenu dans la liste ouverte. On le nommera CURRENT. Node currentNode = openSet[0]; for (int i = 0; i < openSet.Count; i++) { if (openSet[i].fCost < currentNode.fCost || openSet[i].fCost == currentNode.fCost && openSet[i].hCost < currentNode.hCost) { currentNode = openSet[i]; } } openSet.Remove(currentNode); // b. Basculer CURRENT dans la liste fermée. closedSet.Add(currentNode); // stopper la boucle si on ajoute le noeud d'arrivée à la liste fermée if (currentNode == targetNode) { pathSuccess = true; break; } // récupération des voisins de CURRENT // Pour chacun des nodes adjacents à CURRENT appliquer la méthode suivante: foreach (Node neighbour in grid.Get8Neighbours(currentNode)) { //Si le node est un obstacle ou est dans la liste fermée ignorez-le et passer à l'analyse d'un autre node. if (!neighbour.walkable || closedSet.Contains(neighbour)) { continue; } int newMovementCostToNeighbour = currentNode.gCost + Pathfinding.GetDistance(currentNode, neighbour); if (newMovementCostToNeighbour < neighbour.gCost || !openSet.Contains(neighbour)) { /* on calcule le nouveau g */ neighbour.gCost = newMovementCostToNeighbour; /*on calcule le nouveau h */ neighbour.hCost = Pathfinding.GetDistance(neighbour, targetNode); neighbour.parent = currentNode; if (!openSet.Contains(neighbour)) { openSet.Add(neighbour); } } } } } else { Debug.LogWarning("erreur les tiles a de depart fin ne sont pas walkable / debut : " + startNode.walkable + "fin : " + targetNode.walkable); } yield return(null); //??? // on est sorti de la liste, on a deux solutions, soit la liste ouverte est vide dans ces cas là il // n'y a pas de solutions et on retoure directement finalPath; if (pathSuccess) { // Soit on maintenant on construit le chemin à rebours; waypoints = Pathfinding.RetracePath(startNode, targetNode); } //Debug.Log("Simple Path Finish Status : " + pathSuccess.ToString() + " - Lenght : " + waypoints.Length); FinishedProcessingPath(waypoints, pathSuccess); }