// 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(); });
        }
    }
示例#4
0
    // 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();
    }
示例#5
0
    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);
        }
    }