public void AIActionStart(Unit _unit) { int enemyHero = (_unit.side + 1) % 2; bool isRangeAttack = _unit.IsRangeAttack; List <Unit> enemyList = BattleManager.instance.units[enemyHero]; //远程单位,且没有被近身 if (isRangeAttack) { Unit target = GetMaxDamageUnit(_unit, enemyList, isRangeAttack); UnitActionMgr.order = new Order(OrderType.rangeAttack, _unit, target); } else { int speed = _unit.GetComponent <Unit>().speed; List <Unit> targetList = GetEnemiesWithinRange(_unit, speed + 1); Unit target; if (targetList.Count > 0) { //攻击范围内有目标 target = GetMaxDamageUnit(_unit, targetList, isRangeAttack); List <NodeItem> path = AStarManager.FindPath(BattleManager.instance.map, _unit.nodeItem, target.nodeItem, false); path.RemoveAt(path.Count - 1); if (_unit.isWalker) { UnitActionMgr.order = new Order(OrderType.attack, _unit, path, target); } else { UnitActionMgr.order = new Order(OrderType.attack, _unit, path[path.Count - 1], target); } } else { //攻击范围内无目标 target = GetNearestUnit(_unit, enemyList); //且可到达 List <NodeItem> path = AStarManager.FindPath(BattleManager.instance.map, _unit.nodeItem, target.nodeItem, false); //去掉移动力之外的部分 path.RemoveRange(speed, path.Count - speed); if (_unit.isWalker) { UnitActionMgr.order = new Order(OrderType.move, _unit, path, target); } else { UnitActionMgr.order = new Order(OrderType.move, _unit, path[path.Count - 1], target); } } } }
public List <Vector2> FindPath(Vector2Int _startLandIdx, Vector2Int _distLandIdx) { return(ChangeNodeListToPath(AStarManager.FindPath(_startLandIdx, _distLandIdx))); }
public override LinkedList <Node> GeneratePath(int _enemyPosX, int _enemyPosY) { GridManager grid = DungeonManager.Instance.Grids[(int)GridType.Knight]; LinkedList <Node> retPath = null; retPath = AStarManager.FindPath( grid.nodes[_enemyPosX, _enemyPosY], grid.nodes[GameManager.Instance.Player.PosX, GameManager.Instance.Player.PosY], grid); if (retPath == null) { /* Here we try the nearest nodes. If the second AStarPath still returns null, * it could be that the enemy piece is completely blocked off. * So don't waste more time trying to find a path, just random * move to the adjacent blocks. */ // Spiral Nearest when the adjacent tiles are not available. Spiral max radius of 3 tiles. int targetPosX = GameManager.Instance.Player.PosX; int targetPosY = GameManager.Instance.Player.PosY; bool emptyTileFound = false; int increment = 1; int iMax = 1; while ((iMax - 1) < 5) { for (int y = 0; y < iMax; y++) { targetPosY += increment; if (DungeonManager.Instance.IsCellEmpty(targetPosX, targetPosY)) { retPath = AStarManager.FindPath( grid.nodes[_enemyPosX, _enemyPosY], grid.nodes[targetPosX, targetPosY], grid); emptyTileFound = true; break; } } for (int x = 0; x < iMax; x++) { targetPosX += increment; if (DungeonManager.Instance.IsCellEmpty(targetPosX, targetPosY)) { retPath = AStarManager.FindPath( grid.nodes[_enemyPosX, _enemyPosY], grid.nodes[targetPosX, targetPosY], grid); emptyTileFound = true; break; } } if (emptyTileFound) { break; } iMax++; increment *= -1; } // If the path is still null (maybe enemy is blocked off by structure), just random anyhow position to the adjacent tiles. if (retPath == null) { LinkedList <Node> neighbours = grid.nodes[_enemyPosX, _enemyPosY].neighbours; for (LinkedListNode <Node> curNode = neighbours.First; curNode != null; curNode = curNode.Next) { if (DungeonManager.Instance.IsCellEmpty(curNode.Value.PosX, curNode.Value.PosY)) { retPath = new LinkedList <Node>(); retPath.AddFirst(grid.nodes[curNode.Value.PosX, curNode.Value.PosY]); retPath.AddFirst(grid.nodes[_enemyPosX, _enemyPosY]); break; } } } } // If STILL null (can't move all; all neighbours blocked), then no choice, return null and don't move. return(retPath); }
public override LinkedList <Node> GeneratePath(int _enemyPosX, int _enemyPosY) { GridManager grid = DungeonManager.Instance.Grids[(int)GridType.King]; LinkedList <Node> retPath = null; // For king only, because the possibilities are a LOT more, so best to check if player is blocked off // For example, when it is completely surrounded by enemies, king cannot reach it. // So better to just skip the first AStar search because it is so expensive. // Check if there are any empty adjacent nodes to the player. LinkedList <Node> playerNodeNeighbours = grid.nodes[GameManager.Instance.Player.PosX, GameManager.Instance.Player.PosY].neighbours; for (LinkedListNode <Node> curNode = playerNodeNeighbours.First; curNode != null; curNode = curNode.Next) { // If it is one of the surrounding pieces, just directly generate the path. // Need this check, otherwise one of the pieces will move out of formation, // as it detects that the player is surrounded, but does not realize that it is one of the 8 surrounding pieces. if (curNode.Value.PosX == _enemyPosX && curNode.Value.PosY == _enemyPosY) { retPath = AStarManager.FindPath( grid.nodes[_enemyPosX, _enemyPosY], grid.nodes[GameManager.Instance.Player.PosX, GameManager.Instance.Player.PosY], grid); break; } if (DungeonManager.Instance.IsCellEmpty(curNode.Value.PosX, curNode.Value.PosY)) { retPath = AStarManager.FindPath( grid.nodes[_enemyPosX, _enemyPosY], grid.nodes[GameManager.Instance.Player.PosX, GameManager.Instance.Player.PosY], grid); break; } } if (retPath == null) { /* Here we try the nearest nodes. If the second AStarPath still returns null, * it could be that the enemy piece is completely blocked off. * So don't waste more time trying to find a path, just random * move to the adjacent blocks. */ // Spiral Nearest when the adjacent tiles are not available. Spiral max radius of 3 tiles. int targetPosX = GameManager.Instance.Player.PosX; int targetPosY = GameManager.Instance.Player.PosY; bool emptyTileFound = false; int increment = 1; int iMax = 1; while ((iMax - 1) < 5) { for (int y = 0; y < iMax; y++) { targetPosY += increment; if (DungeonManager.Instance.IsCellEmpty(targetPosX, targetPosY)) { retPath = AStarManager.FindPath( grid.nodes[_enemyPosX, _enemyPosY], grid.nodes[targetPosX, targetPosY], grid); emptyTileFound = true; break; } } for (int x = 0; x < iMax; x++) { targetPosX += increment; if (DungeonManager.Instance.IsCellEmpty(targetPosX, targetPosY)) { retPath = AStarManager.FindPath( grid.nodes[_enemyPosX, _enemyPosY], grid.nodes[targetPosX, targetPosY], grid); emptyTileFound = true; break; } } if (emptyTileFound) { break; } iMax++; increment *= -1; } // If the path is still null (maybe enemy is blocked off by structure), just random anyhow position to the adjacent tiles. if (retPath == null) { LinkedList <Node> neighbours = grid.nodes[_enemyPosX, _enemyPosY].neighbours; for (LinkedListNode <Node> curNode = neighbours.First; curNode != null; curNode = curNode.Next) { if (DungeonManager.Instance.IsCellEmpty(curNode.Value.PosX, curNode.Value.PosY)) { retPath = new LinkedList <Node>(); retPath.AddFirst(grid.nodes[curNode.Value.PosX, curNode.Value.PosY]); retPath.AddFirst(grid.nodes[_enemyPosX, _enemyPosY]); break; } } } } // If STILL null (can't move all; all neighbours blocked), then no choice, return null and don't move. return(retPath); }
//寻找路径 bool FindPath(Unit _unit, NodeItem _target) { if (path != null) { ClearPath(); } NodeItem unitNode = _unit.nodeItem; /* * //判断是双格单位,而且前方点更近,则使用前方点进行寻路 * if(_unit.type.isTwoHexsUnit && (_target.pos - _unit.nodeAhead.pos).magnitude < (_target.pos - _unit.nodeItem.pos).magnitude) * { * unitNode = _unit.nodeAhead; * } * * if(_unit.type.isTwoHexsUnit) * { * //前方点不存在或被占用,则使用上个点为目的地 * Vector2Int pos = _target.pos; * pos.x += _unit.sideFacing; * if(!BattleManager.instance.map.isNodeAvailable(pos) || !BattleManager.instance.map.GetNode(pos).walkable) * { * pos.x -= 2 * _unit.sideFacing; * _target = BattleManager.instance.map.GetNodeItem(pos); * } * } */ //根据是否是双格单位,选中寻路方法 if (!_unit.type.isTwoHexsUnit) { path = AStarManager.FindPath(BattleManager.instance.map, unitNode, _target, !_unit.isWalker); } else { path = new List <NodeItem>(); MapManager map = BattleManager.instance.map; //如果目标点的前方点不存在,或者不在可到达节点,则目标点向后移动 Vector2Int ahead = new Vector2Int(_target.pos.x + _unit.sideFacing, _target.pos.y); if (!map.isNodeAvailable(ahead) || !NodeSelector.reachableNodes.Contains(map.GetNodeItem(ahead))) { _target = map.GetNodeItem(new Vector2Int(_target.pos.x - _unit.sideFacing, _target.pos.y)); } foreach (var item in AStarManager.FindPath_TwoHex(map, map.GetNode(unitNode.pos), map.GetNode(_unit.nodeAhead.pos), map.GetNode(_target.pos), !_unit.isWalker)) { path.Add(map.GetNodeItem(item.pos)); } } //print(path.Count); if (path == null) { //print("未能找到路径"); return(false); } path.RemoveAt(0); foreach (var item in path) { item.GetComponent <NodeItem_Battle>().ChangeBackgoundColor("path"); } return(true); }
//点击节点 public override void OnNodePressed(NodeItem _node) { NodeItem_Travel node = (NodeItem_Travel)_node; NodeObject_Travel obj = (NodeObject_Travel)node.nodeObject; Hero hero = TravelManager.currentHero; if (hero == null) { Debug.LogError("当前英雄为空"); } //有路径,而且点击的是终点,则开始移动。否则寻路 if (path != null && node.pathType == TravelPathType.goal) { //是空地直接移动 //否则移动到目标点,然后开始交互 if (obj == null) { MoveObjectAlongPath(hero.gameObject, path); } else { targetNodeObject = obj; if (obj.objectType == TravelNodeType.empty) { MoveObjectAlongPath(hero.gameObject, path); } //是英雄,或者单位,或者物品,只要移动到相邻处,就能开始交互 else if (obj.objectType == TravelNodeType.hero || obj.objectType == TravelNodeType.unit || obj.objectType == TravelNodeType.item) { List <NodeItem> shortPath = new List <NodeItem>(path); shortPath.RemoveAt(shortPath.Count - 1); MoveObjectAlongPath(hero.gameObject, shortPath); } else { //城镇或者地点类物体,进入后交互 MoveObjectAlongPath(hero.gameObject, path); } } } else { //清除之前的路径显示 ClearPath(); path = AStarManager.FindPath(this, hero.nodeItem, _node); int movementRate = hero.movementRate; if (path != null) { NodeItem lastNode; for (int i = 1; i < path.Count; i++) { lastNode = path[i - 1]; if (movementRate >= 0) { movementRate -= GetNodeDistance(lastNode, path[i]); } NodeItem_Travel currentNode = (NodeItem_Travel)path[i]; if (i == path.Count - 1) { //是终点 currentNode.UpdateStatus(TravelPathType.goal); } else { currentNode.UpdateStatus(TravelPathType.path); } if (movementRate >= 0) { currentNode.ChangeColor(color_reachable); } else { currentNode.ChangeColor(color_outOfReach); } lastNode.GetComponent <NodeItem_Travel>().ArrowFaceTarget(path[i].gameObject); } } } }