// Simple grassfire to calculate shortest distance along path to target position for every position. // - i.e. breadth-first expansion from target position. static void CalculateShortestWalkableDistancesToTarget(int rowCount, int colCount, byte *gridWalls, CartesianGridCoordinates targetPosition, NativeArray <int> targetDistances) { var cellCount = rowCount * colCount; var closed = new UnsafeBitArray(cellCount, Allocator.Temp, NativeArrayOptions.ClearMemory); var pending = new UnsafeBitArray(cellCount, Allocator.Temp, NativeArrayOptions.ClearMemory); var open = new UnsafeRingQueue <int>(cellCount, Allocator.Temp); var targetCellIndex = (targetPosition.y * colCount) + targetPosition.x; var cellIndexNorth = targetCellIndex + colCount; var cellIndexSouth = targetCellIndex - colCount; var cellIndexWest = targetCellIndex - 1; var cellIndexEast = targetCellIndex + 1; for (int i = 0; i < targetDistances.Length; i++) { targetDistances[i] = -1; } targetDistances[targetCellIndex] = 0; pending.Set(targetCellIndex, true); closed.Set(targetCellIndex, true); var validDirections = CartesianGridMovement.ValidDirections(targetPosition, rowCount, colCount, gridWalls); var validNorth = ((validDirections & (byte)CartesianGridDirectionBit.North) != 0); var validSouth = ((validDirections & (byte)CartesianGridDirectionBit.South) != 0); var validWest = ((validDirections & (byte)CartesianGridDirectionBit.West) != 0); var validEast = ((validDirections & (byte)CartesianGridDirectionBit.East) != 0); if (validNorth) { open.Enqueue(cellIndexNorth); pending.Set(cellIndexNorth, true); } if (validSouth) { open.Enqueue(cellIndexSouth); pending.Set(cellIndexSouth, true); } if (validWest) { open.Enqueue(cellIndexWest); pending.Set(cellIndexWest, true); } if (validEast) { open.Enqueue(cellIndexEast); pending.Set(cellIndexEast, true); } CalculateShortestWalkableDistancesToTargetInner(rowCount, colCount, gridWalls, targetDistances, pending, closed, open); closed.Dispose(); pending.Dispose(); open.Dispose(); }
public void UnsafeRingQueue_Enqueue_Dequeue() { var test = new UnsafeRingQueue <int>(16, Allocator.Persistent); Assert.AreEqual(0, test.Length); int item; Assert.False(test.TryDequeue(out item)); test.Enqueue(123); Assert.AreEqual(1, test.Length); Assert.True(test.TryEnqueue(456)); Assert.AreEqual(2, test.Length); Assert.True(test.TryDequeue(out item)); Assert.AreEqual(123, item); Assert.AreEqual(1, test.Length); Assert.AreEqual(456, test.Dequeue()); Assert.AreEqual(0, test.Length); test.Dispose(); }
public void UnsafeRingQueue_Throws() { using (var test = new UnsafeRingQueue <int>(1, Allocator.Persistent)) { Assert.Throws <InvalidOperationException>(() => { test.Dequeue(); }); Assert.DoesNotThrow(() => { test.Enqueue(123); }); Assert.Throws <InvalidOperationException>(() => { test.Enqueue(456); }); int item = 0; Assert.DoesNotThrow(() => { item = test.Dequeue(); }); Assert.AreEqual(123, item); Assert.DoesNotThrow(() => { test.Enqueue(456); }); Assert.DoesNotThrow(() => { item = test.Dequeue(); }); Assert.AreEqual(456, item); Assert.Throws <InvalidOperationException>(() => { test.Dequeue(); }); } }
// Simple grassfire to calculate shortest distance along path to target position for every position. // - i.e. breadth-first expansion from target position. static void CalculateShortestWalkableDistancesToTarget(NativeArray <int> targetDistances, int rowCount, byte *gridWalls, CartesianGridCoordinates targetPosition, CartesianGridOnCubeFace cubeFace, float4x4 *faceLocalToLocal) { var cellCount = rowCount * rowCount; var closed = new UnsafeBitArray(6 * cellCount, Allocator.Temp, NativeArrayOptions.ClearMemory); var pending = new UnsafeBitArray(6 * cellCount, Allocator.Temp, NativeArrayOptions.ClearMemory); var open = new UnsafeRingQueue <int>(6 * cellCount, Allocator.Temp); var faceIndex = cubeFace.Value; var faceTargetCellIndex = (targetPosition.y * rowCount) + targetPosition.x; for (int i = 0; i < targetDistances.Length; i++) { targetDistances[i] = -1; } var targetCellIndex = (faceIndex * cellCount) + faceTargetCellIndex; targetDistances[targetCellIndex] = 0; pending.Set(targetCellIndex, true); closed.Set(targetCellIndex, true); var cellIndexNorth = CartesianGridOnCubeUtility.CellIndexNorth(targetCellIndex, rowCount, faceLocalToLocal); var cellIndexSouth = CartesianGridOnCubeUtility.CellIndexSouth(targetCellIndex, rowCount, faceLocalToLocal); var cellIndexWest = CartesianGridOnCubeUtility.CellIndexWest(targetCellIndex, rowCount, faceLocalToLocal); var cellIndexEast = CartesianGridOnCubeUtility.CellIndexEast(targetCellIndex, rowCount, faceLocalToLocal); var rowStride = (rowCount + 1) / 2; var faceStride = rowCount * rowStride; var faceGridWallsOffset = faceIndex * faceStride; var validDirections = CartesianGridMovement.ValidDirections(targetPosition, rowCount, rowCount, gridWalls + faceGridWallsOffset); var validNorth = ((validDirections & (byte)CartesianGridDirectionBit.North) != 0); var validSouth = ((validDirections & (byte)CartesianGridDirectionBit.South) != 0); var validWest = ((validDirections & (byte)CartesianGridDirectionBit.West) != 0); var validEast = ((validDirections & (byte)CartesianGridDirectionBit.East) != 0); if (validNorth) { open.Enqueue(cellIndexNorth); pending.Set(cellIndexNorth, true); } if (validSouth) { open.Enqueue(cellIndexSouth); pending.Set(cellIndexSouth, true); } if (validWest) { open.Enqueue(cellIndexWest); pending.Set(cellIndexWest, true); } if (validEast) { open.Enqueue(cellIndexEast); pending.Set(cellIndexEast, true); } CalculateShortestWalkableDistancesToTargetInner(targetDistances, rowCount, gridWalls, faceLocalToLocal, pending, closed, open); closed.Dispose(); pending.Dispose(); open.Dispose(); }
static void CalculateShortestWalkableDistancesToTargetInner(NativeArray <int> targetDistances, int rowCount, byte *gridWalls, float4x4 *faceLocalToLocal, UnsafeBitArray pending, UnsafeBitArray closed, UnsafeRingQueue <int> open) { var cellCount = rowCount * rowCount; var maxPathLength = 6 * (cellCount + 1); while (open.Length > 0) { var cellIndex = open.Dequeue(); var cellPosition = CartesianGridOnCubeUtility.CellFaceCoordinates(cellIndex, rowCount); var faceIndex = CartesianGridOnCubeUtility.CellFaceIndex(cellIndex, rowCount); var rowStride = (rowCount + 1) / 2; var faceStride = rowCount * rowStride; var faceGridWallsOffset = faceIndex * faceStride; var validDirections = CartesianGridMovement.ValidDirections(cellPosition, rowCount, rowCount, gridWalls + faceGridWallsOffset); var validNorth = ((validDirections & (byte)CartesianGridDirectionBit.North) != 0); var validSouth = ((validDirections & (byte)CartesianGridDirectionBit.South) != 0); var validWest = ((validDirections & (byte)CartesianGridDirectionBit.West) != 0); var validEast = ((validDirections & (byte)CartesianGridDirectionBit.East) != 0); var cellIndexNorth = CartesianGridOnCubeUtility.CellIndexNorth(cellIndex, rowCount, faceLocalToLocal); var cellIndexSouth = CartesianGridOnCubeUtility.CellIndexSouth(cellIndex, rowCount, faceLocalToLocal); var cellIndexWest = CartesianGridOnCubeUtility.CellIndexWest(cellIndex, rowCount, faceLocalToLocal); var cellIndexEast = CartesianGridOnCubeUtility.CellIndexEast(cellIndex, rowCount, faceLocalToLocal); var distanceNorth = maxPathLength; var distanceSouth = maxPathLength; var distanceEast = maxPathLength; var distanceWest = maxPathLength; var closedNorth = false; var closedSouth = false; var closedWest = false; var closedEast = false; if (validNorth) { if (closed.IsSet(cellIndexNorth)) { distanceNorth = targetDistances[cellIndexNorth]; closedNorth = true; } else if (!pending.IsSet(cellIndexNorth)) { open.Enqueue(cellIndexNorth); pending.Set(cellIndexNorth, true); } } if (validSouth) { if (closed.IsSet(cellIndexSouth)) { distanceSouth = targetDistances[cellIndexSouth]; closedSouth = true; } else if (!pending.IsSet(cellIndexSouth)) { open.Enqueue(cellIndexSouth); pending.Set(cellIndexSouth, true); } } if (validWest) { if (closed.IsSet(cellIndexWest)) { distanceWest = targetDistances[cellIndexWest]; closedWest = true; } else if (!pending.IsSet(cellIndexWest)) { open.Enqueue(cellIndexWest); pending.Set(cellIndexWest, true); } } if (validEast) { if (closed.IsSet(cellIndexEast)) { distanceEast = targetDistances[cellIndexEast]; closedEast = true; } else if (!pending.IsSet(cellIndexEast)) { open.Enqueue(cellIndexEast); pending.Set(cellIndexEast, true); } } var closedNeighbor = closedNorth || closedSouth || closedWest || closedEast; Assert.IsTrue(closedNeighbor); var bestDist = math.cmin(new int4(distanceNorth, distanceSouth, distanceEast, distanceWest)) + 1; Assert.IsFalse(bestDist > (maxPathLength + 1)); targetDistances[cellIndex] = bestDist; closed.Set(cellIndex, true); } }
static void CalculateShortestWalkableDistancesToTargetInner(int rowCount, int colCount, byte *gridWalls, NativeArray <int> targetDistances, UnsafeBitArray pending, UnsafeBitArray closed, UnsafeRingQueue <int> open) { var cellCount = rowCount * colCount; while (open.Count > 0) { var cellIndex = open.Dequeue(); var y = cellIndex / colCount; var x = cellIndex - (y * colCount); var cellPosition = new CartesianGridCoordinates { x = (short)x, y = (short)y }; var validDirections = CartesianGridMovement.ValidDirections(cellPosition, rowCount, colCount, gridWalls); var validNorth = ((validDirections & (byte)CartesianGridDirectionBit.North) != 0); var validSouth = ((validDirections & (byte)CartesianGridDirectionBit.South) != 0); var validWest = ((validDirections & (byte)CartesianGridDirectionBit.West) != 0); var validEast = ((validDirections & (byte)CartesianGridDirectionBit.East) != 0); var cellIndexNorth = cellIndex + colCount; var cellIndexSouth = cellIndex - colCount; var cellIndexWest = cellIndex - 1; var cellIndexEast = cellIndex + 1; var distanceNorth = cellCount + 1; var distanceSouth = cellCount + 1; var distanceEast = cellCount + 1; var distanceWest = cellCount + 1; if (validNorth) { if (closed.IsSet(cellIndexNorth)) { distanceNorth = targetDistances[cellIndexNorth]; } else if (!pending.IsSet(cellIndexNorth)) { open.Enqueue(cellIndexNorth); pending.Set(cellIndexNorth, true); } } if (validSouth) { if (closed.IsSet(cellIndexSouth)) { distanceSouth = targetDistances[cellIndexSouth]; } else if (!pending.IsSet(cellIndexSouth)) { open.Enqueue(cellIndexSouth); pending.Set(cellIndexSouth, true); } } if (validWest) { if (closed.IsSet(cellIndexWest)) { distanceWest = targetDistances[cellIndexWest]; } else if (!pending.IsSet(cellIndexWest)) { open.Enqueue(cellIndexWest); pending.Set(cellIndexWest, true); } } if (validEast) { if (closed.IsSet(cellIndexEast)) { distanceEast = targetDistances[cellIndexEast]; } else if (!pending.IsSet(cellIndexEast)) { open.Enqueue(cellIndexEast); pending.Set(cellIndexEast, true); } } var bestDist = math.cmin(new int4(distanceNorth, distanceSouth, distanceEast, distanceWest)) + 1; targetDistances[cellIndex] = bestDist; closed.Set(cellIndex, true); } }