Beispiel #1
0
    protected override JobHandle OnUpdate(JobHandle lastJobHandle)
    {
        // Get component data from the GridPlane
        var cartesianGridPlane             = GetSingleton <CartesianGridOnPlane>();
        var rowCount                       = cartesianGridPlane.Blob.Value.RowCount;
        var colCount                       = cartesianGridPlane.Blob.Value.ColCount;
        var targetDirectionsBufferCapacity = ((colCount + 1) / 2) * rowCount;
        var gridWalls                      = (byte *)cartesianGridPlane.Blob.Value.Walls.GetUnsafePtr();

        // Initialize the buffer for the target paths with size appropriate to grid.
        Entities
        .WithName("InitializeTargets")
        .WithAll <CartesianGridTarget>()
        .WithNone <CartesianGridTargetDirection>()
        .WithStructuralChanges()
        .ForEach((Entity entity) =>
        {
            var buffer = EntityManager.AddBuffer <CartesianGridTargetDirection>(entity);
            buffer.ResizeUninitialized(targetDirectionsBufferCapacity);
        }).Run();

        // Rebuild all the paths to the target *only* when the target's grid position changes.
        Entities
        .WithName("UpdateTargetPaths")
        .WithAll <CartesianGridTarget>()
        .ForEach((Entity entity, ref CartesianGridTargetCoordinates prevTargetPosition, in CartesianGridCoordinates targetPosition, in DynamicBuffer <CartesianGridTargetDirection> targetDirections) =>
        {
            if (prevTargetPosition.Equals(targetPosition))
            {
                return;
            }

            prevTargetPosition = new CartesianGridTargetCoordinates(targetPosition);
            CartesianGridOnPlaneShortestPath.CalculateShortestPathsToTarget(targetDirections.Reinterpret <byte>().AsNativeArray(), rowCount, colCount, targetPosition, gridWalls);
        }).Run();
            public int WalkPathDistance(CartesianGridCoordinates sourcePosition, CartesianGridCoordinates targetPosition)
            {
                var directionsRowStride = (ColCount + 1) / 2;
                var directionsSize      = RowCount * directionsRowStride;

                var targetDirections = new NativeArray <byte>(directionsSize, Allocator.Temp);
                var sourceDirections = new NativeArray <byte>(directionsSize, Allocator.Temp);

                // For testing purposes, recalculate paths every time.
                CartesianGridOnPlaneShortestPath.CalculateShortestPathsToTarget(targetDirections, RowCount, ColCount, targetPosition, Walls);
                CartesianGridOnPlaneShortestPath.CalculateShortestPathsToTarget(sourceDirections, RowCount, ColCount, sourcePosition, Walls);

                // Test distance form source->target is same as target->source
                var sourceToTargetDistance = WalkPath(sourcePosition, targetDirections, 0);
                var targetToSourceDistance = WalkPath(targetPosition, sourceDirections, 0);

                Assert.AreEqual(sourceToTargetDistance, targetToSourceDistance);

                var expectedDistance = sourceToTargetDistance;

                // Sample path variations (not exhaustive, always follow the variation path option)
                for (int i = 1; i < 4; i++)
                {
                    // Test distance form source->target is same as target->source
                    // Test distance is same for all variations
                    sourceToTargetDistance = WalkPath(sourcePosition, targetDirections, i);
                    Assert.AreEqual(expectedDistance, sourceToTargetDistance);
                    targetToSourceDistance = WalkPath(targetPosition, sourceDirections, i);
                    Assert.AreEqual(expectedDistance, targetToSourceDistance);
                }

                targetDirections.Dispose();
                sourceDirections.Dispose();

                return(expectedDistance);
            }
            int WalkPath(CartesianGridCoordinates startPosition, NativeArray <byte> targetDirections, int pathOffset)
            {
                var validDirections = CartesianGridOnPlaneShortestPath.LookupDirectionToTarget(startPosition, RowCount, ColCount, targetDirections);
                var direction       = CartesianGridMovement.PathVariation[((pathOffset & 3) * 16) + validDirections];

                if (direction == 0xff) // No path
                {
                    return(0);
                }

                var nextPosition = new CartesianGridCoordinates();

                if (direction == 0)
                {
                    nextPosition = new CartesianGridCoordinates {
                        x = startPosition.x, y = (short)(startPosition.y + 1)
                    }
                }
                ;
                else if (direction == 1)
                {
                    nextPosition = new CartesianGridCoordinates {
                        x = startPosition.x, y = (short)(startPosition.y - 1)
                    }
                }
                ;
                else if (direction == 2)
                {
                    nextPosition = new CartesianGridCoordinates {
                        x = (short)(startPosition.x - 1), y = (short)startPosition.y
                    }
                }
                ;
                else if (direction == 3)
                {
                    nextPosition = new CartesianGridCoordinates {
                        x = (short)(startPosition.x + 1), y = (short)startPosition.y
                    }
                }
                ;
                else
                {
                    Assert.Fail();
                }

                // Test no wall in the direction given
                if (direction == 0)
                {
                    Assert.IsFalse(TestWallBit(startPosition.x, startPosition.y, CartesianGridDirectionBit.North));
                }
                else if (direction == 1)
                {
                    Assert.IsFalse(TestWallBit(startPosition.x, startPosition.y, CartesianGridDirectionBit.South));
                }
                else if (direction == 2)
                {
                    Assert.IsFalse(TestWallBit(startPosition.x, startPosition.y, CartesianGridDirectionBit.West));
                }
                else if (direction == 3)
                {
                    Assert.IsFalse(TestWallBit(startPosition.x, startPosition.y, CartesianGridDirectionBit.East));
                }

                return(1 + WalkPath(nextPosition, targetDirections, pathOffset));
            }
Beispiel #4
0
    protected override JobHandle OnUpdate(JobHandle lastJobHandle)
    {
        int pathOffset = m_PathVariationOffset;

        m_PathVariationOffset = (m_PathVariationOffset + 1) & 3;

        // Get component data from the GridPlane
        var cartesianGridPlane = GetSingleton <CartesianGridOnPlane>();
        var rowCount           = cartesianGridPlane.Blob.Value.RowCount;
        var colCount           = cartesianGridPlane.Blob.Value.ColCount;
        var trailingOffsets    = (float2 *)cartesianGridPlane.Blob.Value.TrailingOffsets.GetUnsafePtr();

        var targetEntities    = m_TargetQuery.ToEntityArray(Allocator.TempJob);
        var targetCoordinates = m_TargetQuery.ToComponentDataArray <CartesianGridCoordinates>(Allocator.TempJob);
        var getCartesianGridTargetDirectionFromEntity = GetBufferFromEntity <CartesianGridTargetDirection>(true);

        // Offset center to grid cell
        var cellCenterOffset = new float2(((float)colCount * 0.5f) - 0.5f, ((float)rowCount * 0.5f) - 0.5f);

        // Whenever a CartesianGridFollowTarget reaches a new grid cell, make a decision about what next direction to turn.
        lastJobHandle = Entities
                        .WithName("ChangeDirectionTowardNearestTarget")
                        .WithNativeDisableUnsafePtrRestriction(trailingOffsets)
                        .WithEntityQueryOptions(EntityQueryOptions.FilterWriteGroup)
                        .WithReadOnly(targetCoordinates)
                        .WithReadOnly(getCartesianGridTargetDirectionFromEntity)
                        .WithAll <CartesianGridFollowTarget>()
                        .ForEach((ref CartesianGridDirection gridDirection,
                                  ref CartesianGridCoordinates gridCoordinates,
                                  ref Translation translation) =>
        {
            var dir = gridDirection.Value;
            if (dir != 0xff)         // If moving, update grid based on trailing direction.
            {
                var nextGridPosition = new CartesianGridCoordinates(translation.Value.xz + trailingOffsets[dir], rowCount, colCount);
                if (gridCoordinates.Equals(nextGridPosition))
                {
                    // Don't allow translation to drift
                    translation.Value = CartesianGridMovement.SnapToGridAlongDirection(translation.Value, dir, gridCoordinates, cellCenterOffset);
                    return;         // Still in the same grid cell. No need to change direction.
                }

                gridCoordinates = nextGridPosition;
            }

            var targetEntity = FindTargetShortestManhattanDistance(gridCoordinates, rowCount, colCount, targetCoordinates, targetEntities);
            if (targetEntity == Entity.Null)
            {
                // No target for whatever reason, don't move.
                gridDirection.Value = 0xff;
                return;
            }

            // Lookup next direction along shortest path to target from table stored in CartesianGridTargetDirection
            // - When multiple shortest path available, use pathOffset to select which option.
            var targetDirections = getCartesianGridTargetDirectionFromEntity[targetEntity].Reinterpret <byte>().AsNativeArray();
            var validDirections  = CartesianGridOnPlaneShortestPath.LookupDirectionToTarget(gridCoordinates, rowCount, colCount, targetDirections);
            gridDirection.Value  = CartesianGridMovement.PathVariation[(pathOffset * 16) + validDirections];
        }).Schedule(lastJobHandle);

        lastJobHandle = targetEntities.Dispose(lastJobHandle);
        lastJobHandle = targetCoordinates.Dispose(lastJobHandle);

        return(lastJobHandle);
    }