public void Tick() //This method should be called by MatchEngine { for (int i = m_activeTasks.Count - 1; i >= 0; --i) { PathFinderTask task = m_activeTasks[i]; Debug.Assert(!task.IsTerminated); if (task.CallbackIfCompleted()) { if (!task.IsTerminated && m_activeTasks[i] == task) { m_activeTasks.RemoveAt(i); m_idToActiveTask.Remove(task.UnitId); } } } }
public void Find(long unitId, long targetId, IVoxelDataController dataController, Coordinate[] waypoints, Action <long, Coordinate[]> callback, Action <long> terminateCallback) { if (waypoints == null) { throw new ArgumentNullException("waypoints"); } PathFinderTask task; if (m_idToActiveTask.TryGetValue(unitId, out task)) { task.Terminate(); m_activeTasks.Remove(task); } task = new PathFinderTask(dataController.PlayerIndex, unitId, targetId, dataController.Map, dataController.MapSize, dataController.ControlledData, waypoints[0] /*dataController.Coordinate*/, dataController.Abilities, waypoints, m_matrixPools, callback, terminateCallback); m_idToActiveTask[unitId] = task; m_activeTasks.Add(task); }
private Coordinate GetCoordinate(PathFinderTask task, int row, int col) { int type = task.ControlledData.Type; int weight = task.ControlledData.Weight; int height = task.ControlledData.Height; MapCell cell = task.Map.Get(row, col, weight); VoxelData target; VoxelData beneath = cell.GetDefaultTargetFor(type, weight, task.PlayerIndex, false, out target); if (beneath == null) { return(new Coordinate(row, col, 0, weight)); } int altitude = beneath.Altitude + beneath.Height; return(new Coordinate(row, col, altitude, weight)); }
private bool TryToMove(bool checkTarget, PathFinderTask task, Coordinate from, Coordinate next, out Coordinate result, out VoxelData resultData) { resultData = null; MapCell cell = task.Map.Get(next.Row, next.Col, next.Weight); int type = task.ControlledData.Type; int weight = task.ControlledData.Weight; int height = task.ControlledData.Height; MapCell targetCell; if (checkTarget) { VoxelData targetData = cell.GetById(task.TargetId); if (targetData != null) { next.Altitude = targetData.Altitude; CmdResultCode canMove = VoxelDataController.CanMove(task.ControlledData, task.Abilities, task.Map, task.MapSize, from, next, false, false, false, out targetCell); if (canMove == CmdResultCode.Success) { resultData = targetData; result = next; return(true); } } } //Change altitude if failed with target coordinate VoxelData target; VoxelData beneath = cell.GetDefaultTargetFor(type, weight, task.PlayerIndex, false, out target); if (beneath == null) { result = from; return(false); } // This will allow bomb movement bool isLastStep = task.Waypoints[task.Waypoints.Length - 1].MapPos == next.MapPos; if (isLastStep) { //Try target coordinate first next = task.Waypoints[task.Waypoints.Length - 1]; //last step is param false -> force CanMove to check next coordinate as is CmdResultCode canMove = VoxelDataController.CanMove(task.ControlledData, task.Abilities, task.Map, task.MapSize, from, next, false, false, false, out targetCell); if (canMove == CmdResultCode.Success) { result = next; return(true); } } if (target != beneath) //this will allow bombs to move over spawners { if (!isLastStep && target != null && !(target.IsCollapsableBy(type, weight) || target.IsAttackableBy(task.ControlledData))) { result = from; return(false); } } next.Altitude = beneath.Altitude + beneath.Height; //last step param is false -> force CanMove to check next coordinate as is CmdResultCode canMoveResult = VoxelDataController.CanMove(task.ControlledData, task.Abilities, task.Map, task.MapSize, from, next, false, false, false, out targetCell); if (canMoveResult != CmdResultCode.Success) { result = from; return(false); } result = next; return(true); }
private void CompleteTask(PathFinderTask task, int[,] hopsMatrix, int size) { Coordinate coord = task.ClosestToGoal; int row = coord.Row; int col = coord.Col; List <Coordinate> path = new List <Coordinate>(); path.Add(coord); int minHops = hopsMatrix[row, col]; int minRow = 0; int minCol = 0; Coordinate minCoord = new Coordinate(); while (minHops != 0) { bool canMove = false; for (int r = -1; r <= 1; r++) { for (int c = -1; c <= 1; c++) { int s = r + c; if (s != -1 && s != 1) { continue; } int prevRow = row + r; int prevCol = col + c; if (prevCol < 0 || prevRow < 0 || prevRow >= size || prevCol >= size) { continue; } int hops = hopsMatrix[prevRow, prevCol]; if (hops == (minHops - 1)) { Coordinate prevCoord = GetCoordinate(task, prevRow, prevCol); Coordinate modifiedCoord; VoxelData notUsed; if (TryToMove(false, task, prevCoord, coord, out modifiedCoord, out notUsed)) //possible errors here (yes you were right... infinite loop if try to move failed? { minHops = hops; minRow = prevRow; minCol = prevCol; minCoord = prevCoord; canMove = true; } } } } if (!canMove) { //if can't move clear path path.Clear(); for (int r = -1; r <= 1; r++) { for (int c = -1; c <= 1; c++) { int s = r + c; if (s != -1 && s != 1) { continue; } int prevRow = row + r; int prevCol = col + c; if (prevCol < 0 || prevRow < 0 || prevRow >= size || prevCol >= size) { continue; } int hops = hopsMatrix[prevRow, prevCol]; if (hops == (minHops - 1)) { //take first appropriate coordinate Coordinate prevCoord = GetCoordinate(task, prevRow, prevCol); minHops = hops; minRow = prevRow; minCol = prevCol; minCoord = prevCoord; canMove = true; break; } } } } if (canMove) { row = minRow; col = minCol; coord = minCoord; path.Add(coord); } else { //if still can't move then something went wrong and infinite loop take place here Debug.LogError("Infinite Loop"); break; //we break this loop } } path.Reverse(); task.SetCompleted(path.ToArray()); }
public void Update() { int batchSize = GameConstants.PathFinderBatchSize; while (m_activeTasks.Count > 0) { int completedTasksCount = 0; for (int i = 0; i < m_activeTasks.Count; ++i) { PathFinderTask task = m_activeTasks[i]; if (task.IsCompleted) { completedTasksCount++; if (m_activeTasks.Count == completedTasksCount) { return; } continue; } if (batchSize == 0) { return; } batchSize--; Coordinate goal = task.Waypoints[task.Waypoints.Length - 1]; int[,] hopsMatrix = task.HopsMatrix; int size = hopsMatrix.GetLength(0); if (task.DataQueue.Count > 0) { PathFinderTask.Data current = task.DataQueue.Dequeue(); if (current.Coordinate.MapPos == goal.MapPos) { //path found CompleteTask(task, hopsMatrix, size); } else { //searching for path for (int r = -1; r <= 1; r++) { for (int c = -1; c <= 1; c++) { int s = r + c; if (s != -1 && s != 1) { continue; } int nextHops = current.Hops + 1; Coordinate next = current.Coordinate.Add(r, c); MapPos pos = next.MapPos; if (pos.Col < 0 || pos.Row < 0 || pos.Col >= size || pos.Row >= size) { continue; } if (hopsMatrix[pos.Row, pos.Col] <= nextHops) { continue; } VoxelData targetData; if (TryToMove(task.HasTarget, task, current.Coordinate, next, out next, out targetData)) { hopsMatrix[pos.Row, pos.Col] = nextHops; if (targetData != null) { task.ClosestToGoal = next; task.Waypoints[task.Waypoints.Length - 1] = next; task.DataQueue.Clear(); c = 2; //break inner for loop; r = 2; //break outer for loop } else { int closestDistance = task.ClosestToGoal.MapPos.SqDistanceTo(goal.MapPos); int distanceToGoal = pos.SqDistanceTo(goal.MapPos); if (distanceToGoal < closestDistance) { task.ClosestToGoal = next; } } task.DataQueue.Enqueue(new PathFinderTask.Data(next, nextHops)); } } } } } else { // path was not found CompleteTask(task, hopsMatrix, size); } } } }