Пример #1
0
        private void AdjustVelocityForCollision(IAABBEntity entity, BoundingBox problem)
        {
            var velocity = entity.Velocity;

            if (entity.Velocity.X < 0)
            {
                velocity.X = entity.BoundingBox.Min.X - problem.Max.X;
            }
            if (entity.Velocity.X > 0)
            {
                velocity.X = entity.BoundingBox.Max.X - problem.Min.X;
            }
            if (entity.Velocity.Y < 0)
            {
                velocity.Y = entity.BoundingBox.Min.Y - problem.Max.Y;
            }
            if (entity.Velocity.Y > 0)
            {
                velocity.Y = entity.BoundingBox.Max.Y - problem.Min.Y;
            }
            if (entity.Velocity.Z < 0)
            {
                velocity.Z = entity.BoundingBox.Min.Z - problem.Max.Z;
            }
            if (entity.Velocity.Z > 0)
            {
                velocity.Z = entity.BoundingBox.Max.Z - problem.Min.Z;
            }
            entity.Velocity = velocity;
        }
Пример #2
0
 private void CheckWithTerrain(IAABBEntity entity, World world)
 {
     Vector3 collisionPoint, collisionDirection;
     if (entity.Position.Y + entity.Velocity.Y >= 0 && entity.Position.Y + entity.Velocity.Y <= 255) // Don't do checks outside the map
     {
         bool fireEvent = entity.Velocity != Vector3.Zero;
         // Do terrain collisions
         if (AdjustVelocityX(entity, world, out collisionPoint, out collisionDirection))
         {
             if (fireEvent)
                 entity.TerrainCollision(this, collisionPoint, collisionDirection);
         }
         if (AdjustVelocityY(entity, world, out collisionPoint, out collisionDirection))
         {
             entity.Velocity *= new Vector3(0.2, 1, 0.2); // TODO: More sophisticated friction
             if (fireEvent)
                 entity.TerrainCollision(this, collisionPoint, collisionDirection);
         }
         if (AdjustVelocityZ(entity, world, out collisionPoint, out collisionDirection))
         {
             if (fireEvent)
                 entity.TerrainCollision(this, collisionPoint, collisionDirection);
         }
     }
 }
Пример #3
0
        private void CheckWithTerrain(IAABBEntity entity, ReadOnlyWorld world)
        {
            Vector3 collisionPoint, collisionDirection;

            if (entity.Position.Y > 0 && entity.Position.Y <= 127) // Don't do checks outside the map
            {
                bool fireEvent = entity.Velocity != Vector3.Zero;
                // Do terrain collisions
                if (AdjustVelocityX(entity, world, out collisionPoint, out collisionDirection))
                {
                    if (fireEvent)
                    {
                        entity.TerrainCollision(collisionPoint, collisionDirection);
                    }
                }
                if (AdjustVelocityY(entity, world, out collisionPoint, out collisionDirection))
                {
                    entity.Velocity *= new Vector3(0.1, 1, 0.1); // TODO: More sophisticated friction
                    if (fireEvent)
                    {
                        entity.TerrainCollision(collisionPoint, collisionDirection);
                    }
                }
                if (AdjustVelocityZ(entity, world, out collisionPoint, out collisionDirection))
                {
                    if (fireEvent)
                    {
                        entity.TerrainCollision(collisionPoint, collisionDirection);
                    }
                }
            }
        }
 public void Initialize(Camera camera, IAABBEntity playerEntity)
 {
     m_Camera                 = camera;
     m_PlayerEntity           = playerEntity;
     m_DestroyRaycastSelector = DestroyRaycastSelect;
     m_PlaceRaycastSelector   = PlaceRaycastSelect;
 }
Пример #5
0
        public void DestroyEntity(IAABBEntity entity)
        {
            entity.OnRecycle();

            if (entity is IRenderableEntity renderableEntity)
            {
                m_RenderableEntities.Remove(renderableEntity);
            }

            if (entity is LuaBlockEntity blockEntity)
            {
                blockEntity.gameObject.SetActive(false);
                m_BlockEntityPool.Enqueue(blockEntity);
            }
        }
Пример #6
0
        private BoundingBox GetAABBVelocityBox(IAABBEntity entity)
        {
            var min = new Vector3(
                Math.Min(entity.BoundingBox.Min.X, entity.BoundingBox.Min.X + entity.Velocity.X),
                Math.Min(entity.BoundingBox.Min.Y, entity.BoundingBox.Min.Y + entity.Velocity.Y),
                Math.Min(entity.BoundingBox.Min.Z, entity.BoundingBox.Min.Z + entity.Velocity.Z)
                );
            var max = new Vector3(
                Math.Max(entity.BoundingBox.Max.X, entity.BoundingBox.Max.X + entity.Velocity.X),
                Math.Max(entity.BoundingBox.Max.Y, entity.BoundingBox.Max.Y + entity.Velocity.Y),
                Math.Max(entity.BoundingBox.Max.Z, entity.BoundingBox.Max.Z + entity.Velocity.Z)
                );

            return(new BoundingBox(min, max));
        }
Пример #7
0
        public bool TestTerrainCollisionCylinder(IAABBEntity entity, out Vector3 collisionPoint)
        {
            collisionPoint = Vector3.Zero;
            var testBox      = GetAABBVelocityBox(entity);
            var testCylinder = new BoundingCylinder(testBox.Min, testBox.Max,
                                                    entity.BoundingBox.Min.DistanceTo(entity.BoundingBox.Max));

            var collision = false;

            for (var x = (int)Math.Floor(testBox.Min.X); x <= (int)Math.Ceiling(testBox.Max.X); x++)
            {
                for (var z = (int)Math.Floor(testBox.Min.Z); z <= (int)Math.Ceiling(testBox.Max.Z); z++)
                {
                    for (var y = (int)Math.Floor(testBox.Min.Y); y <= (int)Math.Ceiling(testBox.Max.Y); y++)
                    {
                        var coords = new Coordinates3D(x, y, z);
                        if (!World.IsValidPosition(coords))
                        {
                            continue;
                        }

                        var _box = BlockPhysicsProvider.GetBoundingBox(World, coords);
                        if (_box == null)
                        {
                            continue;
                        }

                        var box = _box.Value.OffsetBy(coords.AsVector3());
                        if (testCylinder.Intersects(box))
                        {
                            if (testBox.Intersects(box))
                            {
                                collision = true;
                                AdjustVelocityForCollision(entity, box);
                                testBox      = GetAABBVelocityBox(entity);
                                testCylinder = new BoundingCylinder(testBox.Min, testBox.Max,
                                                                    entity.BoundingBox.Min.DistanceTo(entity.BoundingBox.Max));
                                collisionPoint = coords.AsVector3();
                            }
                        }
                    }
                }
            }

            return(collision);
        }
Пример #8
0
        public bool TestTerrainCollisionCylinder(IAABBEntity entity, out Vector3 collisionPoint)
        {
            collisionPoint = Vector3.Zero;
            var testBox = GetAABBVelocityBox(entity);
            var testCylinder = new BoundingCylinder(testBox.Min, testBox.Max,
                entity.BoundingBox.Min.DistanceTo(entity.BoundingBox.Max));

            bool collision = false;
            for (int x = (int)(Math.Floor(testBox.Min.X)); x <= (int)(Math.Ceiling(testBox.Max.X)); x++)
            {
                for (int z = (int)(Math.Floor(testBox.Min.Z)); z <= (int)(Math.Ceiling(testBox.Max.Z)); z++)
                {
                    for (int y = (int)(Math.Floor(testBox.Min.Y)); y <= (int)(Math.Ceiling(testBox.Max.Y)); y++)
                    {
                        var coords = new Coordinates3D(x, y, z);
                        if (!World.IsValidPosition(coords))
                            continue;

                        var _box = BlockPhysicsProvider.GetBoundingBox(World, coords);
                        if (_box == null)
                            continue;

                        var box = _box.Value.OffsetBy(coords);
                        if (testCylinder.Intersects(box))
                        {
                            if (testBox.Intersects(box))
                            {
                                collision = true;
                                AdjustVelocityForCollision(entity, box);
                                testBox = GetAABBVelocityBox(entity);
                                testCylinder = new BoundingCylinder(testBox.Min, testBox.Max,
                                    entity.BoundingBox.Min.DistanceTo(entity.BoundingBox.Max));
                                collisionPoint = coords;
                            }
                        }
                    }
                }
            }
            return collision;
        }
        private float CheckBody(IAABBEntity entity)
        {
            AABB       aabb   = entity.BoundingBox + entity.Position;
            Vector3Int center = aabb.Center.FloorToInt();
            int        minY   = Mathf.FloorToInt(aabb.Min.y);
            int        maxY   = Mathf.FloorToInt(aabb.Max.y);

            BlockData blockData = null;
            int       index     = int.MaxValue;

            for (int y = minY; y < maxY; y++)
            {
                BlockData block = entity.World.RWAccessor.GetBlock(center.x, y, center.z);

                // 根据 m_Fluids 数组元素的顺序来确定方块
                for (int i = 0; i < m_Fluids.Length; i++)
                {
                    // 越靠前,优先级越高
                    if (i >= index)
                    {
                        break;
                    }

                    if (block.InternalName == m_Fluids[i].BlockName)
                    {
                        blockData = block;
                        index     = i;
                        break;
                    }
                }
            }

            if (blockData != null && m_BlockAtBody != blockData.InternalName)
            {
                m_BlockAtBody = blockData.InternalName;
                return(m_Fluids[index].VelocityMultiplier);
            }

            return(m_FluidMap.TryGetValue(m_BlockAtBody, out FluidInfo info) ? info.VelocityMultiplier : 1); // default is 1
        }
        private void CheckHead(IAABBEntity entity, Transform camera)
        {
            Vector3 pos = camera.position;
            int     y   = Mathf.FloorToInt(pos.y);

            if (y < 0 || y >= ChunkHeight)
            {
                return;
            }

            int       x     = Mathf.FloorToInt(pos.x);
            int       z     = Mathf.FloorToInt(pos.z);
            BlockData block = entity.World.RWAccessor.GetBlock(x, y, z);

            if (block.InternalName != m_BlockAtHead && m_FluidMap.TryGetValue(block.InternalName, out FluidInfo info))
            {
                m_BlockAtHead = block.InternalName;
                ShaderUtility.ViewDistance           = info.ViewDistance;
                ShaderUtility.WorldAmbientColorDay   = info.AmbientColorDay;
                ShaderUtility.WorldAmbientColorNight = info.AmbientColorNight;
            }
        }
Пример #11
0
        /// <summary>
        /// Performs terrain collision tests and adjusts the Y-axis velocity accordingly
        /// </summary>
        /// <returns>True if the entity collides with the terrain</returns>
        private bool AdjustVelocityY(IAABBEntity entity, World world, out Vector3 collision, out Vector3 collisionDirection)
        {
            collision = Vector3.Zero;
            collisionDirection = Vector3.Zero;
            if (entity.Velocity.Y == 0)
                return false;
            // Do some enviornment guessing to improve speed
            int minX = (int)entity.Position.X - (entity.Position.X < 0 ? 1 : 0);
            int maxX = (int)(entity.Position.X + entity.Size.Width) - (entity.Position.X < 0 ? 1 : 0);
            int minZ = (int)entity.Position.Z - (entity.Position.Z < 0 ? 1 : 0);
            int maxZ = (int)(entity.Position.Z + entity.Size.Depth) - (entity.Position.Z < 0 ? 1 : 0);
            int minY, maxY;

            // Expand bounding box to include area to be tested
            if (entity.Velocity.Y < 0)
            {
                TempBoundingBox = new BoundingBox(
                    new Vector3(entity.BoundingBox.Min.X, entity.BoundingBox.Min.Y + entity.Velocity.Y, entity.BoundingBox.Min.Z) - (entity.Size / 2),
                    new Vector3(entity.BoundingBox.Max.X, entity.BoundingBox.Max.Y, entity.BoundingBox.Max.Z) - (entity.Size / 2)
                );

                maxY = (int)(TempBoundingBox.Max.Y);
                minY = (int)(TempBoundingBox.Min.Y + entity.Velocity.Y);
            }
            else
            {
                TempBoundingBox = new BoundingBox(
                    entity.BoundingBox.Min - (entity.Size / 2),
                    new Vector3(
                    entity.BoundingBox.Max.X, entity.BoundingBox.Max.Y + entity.Velocity.Y, entity.BoundingBox.Max.Z) - (entity.Size / 2)
                );
                minY = (int)(entity.BoundingBox.Min.Y);
                maxY = (int)(entity.BoundingBox.Max.Y + entity.Velocity.Y);
            }

            // Clamp Y into map boundaries
            if (minY < 0)
                minY = 0;
            if (minY >= World.Height)
                minY = World.Height - 1;
            if (maxY < 0)
                maxY = 0;
            if (maxY >= World.Height)
                maxY = World.Height - 1;

            // Do terrain checks
            double? collisionPoint = null;
            BoundingBox blockBox;
            for (int x = minX; x <= maxX; x++)
            {
                for (int y = minY; y <= maxY; y++)
                {
                    for (int z = minZ; z <= maxZ; z++)
                    {
                        var position = new Vector3(x, y, z);
                        var boundingBox = BlockPhysicsProvider.GetBoundingBox(world, (Coordinates3D)position);
                        if (boundingBox == null)
                            continue;
                        blockBox = boundingBox.Value.OffsetBy(position);
                        if (TempBoundingBox.Intersects(blockBox))
                        {
                            if (entity.Velocity.Y < 0)
                            {
                                if (!collisionPoint.HasValue)
                                    collisionPoint = blockBox.Max.Y;
                                else if (collisionPoint.Value < blockBox.Max.Y)
                                    collisionPoint = blockBox.Max.Y;
                            }
                            else
                            {
                                if (!collisionPoint.HasValue)
                                    collisionPoint = blockBox.Min.Y;
                                else if (collisionPoint.Value > blockBox.Min.Y)
                                    collisionPoint = blockBox.Min.Y;
                            }
                            collision = position;
                        }
                    }
                }
            }

            if (collisionPoint != null)
            {
                if (entity.Velocity.Y < 0)
                {
                    // TODO: Do block event
                    //var block = world.GetBlock(collision);
                    //block.OnBlockWalkedOn(world, collision, this);
                    entity.Velocity = new Vector3(entity.Velocity.X,
                        entity.Velocity.Y + (collisionPoint.Value - TempBoundingBox.Min.Y),
                        entity.Velocity.Z);
                    collisionDirection = Vector3.Down;
                }
                else if (entity.Velocity.Y > 0)
                {
                    entity.Velocity = new Vector3(entity.Velocity.X,
                        entity.Velocity.Y - (TempBoundingBox.Max.Y - collisionPoint.Value),
                        entity.Velocity.Z);
                    collisionDirection = Vector3.Up;
                }
                return true;
            }

            return false;
        }
Пример #12
0
 private BoundingBox GetAABBVelocityBox(IAABBEntity entity)
 {
     var min = new Vector3(
         Math.Min(entity.BoundingBox.Min.X, entity.BoundingBox.Min.X + entity.Velocity.X),
         Math.Min(entity.BoundingBox.Min.Y, entity.BoundingBox.Min.Y + entity.Velocity.Y),
         Math.Min(entity.BoundingBox.Min.Z, entity.BoundingBox.Min.Z + entity.Velocity.Z)
     );
     var max = new Vector3(
         Math.Max(entity.BoundingBox.Max.X, entity.BoundingBox.Max.X + entity.Velocity.X),
         Math.Max(entity.BoundingBox.Max.Y, entity.BoundingBox.Max.Y + entity.Velocity.Y),
         Math.Max(entity.BoundingBox.Max.Z, entity.BoundingBox.Max.Z + entity.Velocity.Z)
     );
     return new BoundingBox(min, max);
 }
Пример #13
0
 private void AdjustVelocityForCollision(IAABBEntity entity, BoundingBox problem)
 {
     var velocity = entity.Velocity;
     if (entity.Velocity.X < 0)
         velocity.X = entity.BoundingBox.Min.X - problem.Max.X;
     if (entity.Velocity.X > 0)
         velocity.X = entity.BoundingBox.Max.X - problem.Min.X;
     if (entity.Velocity.Y < 0)
         velocity.Y = entity.BoundingBox.Min.Y - problem.Max.Y;
     if (entity.Velocity.Y > 0)
         velocity.Y = entity.BoundingBox.Max.Y - problem.Min.Y;
     if (entity.Velocity.Z < 0)
         velocity.Z = entity.BoundingBox.Min.Z - problem.Max.Z;
     if (entity.Velocity.Z > 0)
         velocity.Z = entity.BoundingBox.Max.Z - problem.Min.Z;
     entity.Velocity = velocity;
 }
Пример #14
0
        public bool TestTerrainCollisionZ(IAABBEntity entity, out Vector3 collisionPoint)
        {
            // Things we need to do:
            // 1 - expand bounding box to include the destination and everything within
            // 2 - collect all blocks within that area
            // 3 - test bounding boxes in direction of motion

            collisionPoint = Vector3.Zero;

            if (entity.Velocity.Z == 0)
                return false;

            bool negative;

            BoundingBox testBox;
            if (entity.Velocity.Z < 0)
            {
                testBox = new BoundingBox(
                    new Vector3(
                        entity.BoundingBox.Min.X,
                        entity.BoundingBox.Min.Y,
                        entity.BoundingBox.Min.Z + entity.Velocity.Z),
                    entity.BoundingBox.Max);
                negative = true;
            }
            else
            {
                testBox = new BoundingBox(
                    entity.BoundingBox.Min,
                    new Vector3(
                        entity.BoundingBox.Max.X,
                        entity.BoundingBox.Max.Y,
                        entity.BoundingBox.Max.Z + entity.Velocity.Z));
                negative = false;
            }

            double? collisionExtent = null;
            for (int x = (int)(Math.Floor(testBox.Min.X)); x <= (int)(Math.Ceiling(testBox.Max.X)); x++)
            {
                for (int z = (int)(Math.Floor(testBox.Min.Z)); z <= (int)(Math.Ceiling(testBox.Max.Z)); z++)
                {
                    for (int y = (int)(Math.Floor(testBox.Min.Y)); y <= (int)(Math.Ceiling(testBox.Max.Y)); y++)
                    {
                        var coords = new Coordinates3D(x, y, z);
                        if (!World.IsValidPosition(coords))
                            continue;

                        var _box = BlockPhysicsProvider.GetBoundingBox(World, coords);
                        if (_box == null)
                            continue;

                        var box = _box.Value.OffsetBy(coords);
                        if (testBox.Intersects(box))
                        {
                            if (negative)
                            {
                                if (collisionExtent == null || collisionExtent.Value < box.Max.Z)
                                {
                                    collisionExtent = box.Max.Z;
                                    collisionPoint = coords;
                                }
                            }
                            else
                            {
                                if (collisionExtent == null || collisionExtent.Value > box.Min.Z)
                                {
                                    collisionExtent = box.Min.Z;
                                    collisionPoint = coords;
                                }
                            }
                        }
                    }
                }
            }

            if (collisionExtent != null) // Collision detected, adjust accordingly
            {
                var extent = collisionExtent.Value;
                double diff;
                if (negative)
                    diff = -(entity.BoundingBox.Min.Z - extent);
                else
                    diff = extent - entity.BoundingBox.Max.Z;
                entity.Velocity = new Vector3(entity.Velocity.X, entity.Velocity.Y, diff);
                return true;
            }
            return false;
        }
Пример #15
0
        /// <summary>
        /// Performs terrain collision tests and adjusts the Z-axis velocity accordingly
        /// </summary>
        /// <returns>True if the entity collides with the terrain</returns>
        private bool AdjustVelocityZ(IAABBEntity entity, ReadOnlyWorld world, out Vector3 collision, out Vector3 collisionDirection)
        {
            collision          = Vector3.Zero;
            collisionDirection = Vector3.Zero;
            if (entity.Velocity.Z == 0)
            {
                return(false);
            }
            // Do some enviornment guessing to improve speed
            int minX = (int)entity.Position.X - (entity.Position.X < 0 ? 1 : 0);
            int maxX = (int)(entity.Position.X + entity.Size.Depth) - (entity.Position.X < 0 ? 1 : 0);
            int minY = (int)entity.Position.Y - (entity.Position.Y < 0 ? 1 : 0);
            int maxY = (int)(entity.Position.Y + entity.Size.Width) - (entity.Position.Y < 0 ? 1 : 0);
            int minZ, maxZ;

            // Expand bounding box to include area to be tested
            if (entity.Velocity.Z < 0)
            {
                TempBoundingBox = new BoundingBox(
                    new Vector3(entity.BoundingBox.Min.X, entity.BoundingBox.Min.Y, entity.BoundingBox.Min.Z + entity.Velocity.Z),
                    entity.BoundingBox.Max);

                maxZ = (int)(TempBoundingBox.Max.Z);
                minZ = (int)(TempBoundingBox.Min.Z + entity.Velocity.Z) - 1;
            }
            else
            {
                TempBoundingBox = new BoundingBox(
                    entity.BoundingBox.Min,
                    new Vector3(entity.BoundingBox.Max.X, entity.BoundingBox.Max.Y, entity.BoundingBox.Max.Z + entity.Velocity.Z)
                    );
                minZ = (int)(entity.BoundingBox.Min.Z);
                maxZ = (int)(entity.BoundingBox.Max.Z + entity.Velocity.Z) + 1;
            }

            // Do terrain checks
            double?     collisionPoint = null;
            BoundingBox blockBox;

            for (int x = minX; x <= maxX; x++)
            {
                for (int y = minY; y <= maxY; y++)
                {
                    for (int z = minZ; z <= maxZ; z++)
                    {
                        var position    = new Coordinates3D(x, y, z);
                        var boundingBox = BlockPhysicsProvider.GetBoundingBox(world.World, position);
                        if (boundingBox == null)
                        {
                            continue;
                        }
                        blockBox = boundingBox.Value.OffsetBy(position + new Vector3(0.5));
                        if (TempBoundingBox.Intersects(blockBox))
                        {
                            if (entity.Velocity.Z < 0)
                            {
                                if (!collisionPoint.HasValue)
                                {
                                    collisionPoint = blockBox.Max.Z;
                                }
                                else if (collisionPoint.Value < blockBox.Max.Z)
                                {
                                    collisionPoint = blockBox.Max.Z;
                                }
                            }
                            else
                            {
                                if (!collisionPoint.HasValue)
                                {
                                    collisionPoint = blockBox.Min.Z;
                                }
                                else if (collisionPoint.Value > blockBox.Min.Z)
                                {
                                    collisionPoint = blockBox.Min.Z;
                                }
                            }
                            collision = position;
                        }
                    }
                }
            }

            if (collisionPoint != null)
            {
                if (entity.Velocity.Z < 0)
                {
                    entity.Velocity = new Vector3(
                        entity.Velocity.X,
                        entity.Velocity.Y,
                        entity.Velocity.Z - (TempBoundingBox.Min.Z - collisionPoint.Value));
                    collisionDirection = Vector3.Backwards;
                }
                else if (entity.Velocity.Z > 0)
                {
                    entity.Velocity = new Vector3(
                        entity.Velocity.X,
                        entity.Velocity.Y,
                        entity.Velocity.Z - (TempBoundingBox.Max.Z - collisionPoint.Value));
                    collisionDirection = Vector3.Forwards;
                }
                return(true);
            }

            return(false);
        }
Пример #16
0
        /// <summary>
        /// Performs terrain collision tests and adjusts the Y-axis velocity accordingly
        /// </summary>
        /// <returns>True if the entity collides with the terrain</returns>
        private bool AdjustVelocityY(IAABBEntity entity, ReadOnlyWorld world, out Vector3 collision, out Vector3 collisionDirection)
        {
            collision          = Vector3.Zero;
            collisionDirection = Vector3.Zero;
            if (entity.Velocity.Y == 0)
            {
                return(false);
            }
            // Do some enviornment guessing to improve speed
            int minX = (int)entity.Position.X - (entity.Position.X < 0 ? 1 : 0);
            int maxX = (int)(entity.Position.X + entity.Size.Width) - (entity.Position.X < 0 ? 1 : 0);
            int minZ = (int)entity.Position.Z - (entity.Position.Z < 0 ? 1 : 0);
            int maxZ = (int)(entity.Position.Z + entity.Size.Depth) - (entity.Position.Z < 0 ? 1 : 0);
            int minY, maxY;

            // Expand bounding box to include area to be tested
            if (entity.Velocity.Y < 0)
            {
                TempBoundingBox = new BoundingBox(
                    new Vector3(entity.BoundingBox.Min.X, entity.BoundingBox.Min.Y + entity.Velocity.Y, entity.BoundingBox.Min.Z),
                    entity.BoundingBox.Max);

                maxY = (int)(TempBoundingBox.Max.Y);
                minY = (int)(TempBoundingBox.Min.Y + entity.Velocity.Y) - 1;
            }
            else
            {
                TempBoundingBox = new BoundingBox(
                    entity.BoundingBox.Min,
                    new Vector3(entity.BoundingBox.Max.X, entity.BoundingBox.Max.Y + entity.Velocity.Y, entity.BoundingBox.Max.Z));
                minY = (int)(entity.BoundingBox.Min.Y);
                maxY = (int)(entity.BoundingBox.Max.Y + entity.Velocity.Y) + 1;
            }

            // Clamp Y into map boundaries
            if (minY < 0)
            {
                minY = 0;
            }
            if (minY >= TrueCraft.Core.World.World.Height)
            {
                minY = TrueCraft.Core.World.World.Height - 1;
            }
            if (maxY < 0)
            {
                maxY = 0;
            }
            if (maxY >= TrueCraft.Core.World.World.Height)
            {
                maxY = TrueCraft.Core.World.World.Height - 1;
            }

            // Do terrain checks
            double?     collisionPoint = null;
            BoundingBox blockBox;

            for (int x = minX; x <= maxX; x++)
            {
                for (int y = minY; y <= maxY; y++)
                {
                    for (int z = minZ; z <= maxZ; z++)
                    {
                        var position = new Coordinates3D(x, y, z);
                        if (!World.IsValidPosition(position))
                        {
                            continue;
                        }
                        var boundingBox = BlockPhysicsProvider.GetBoundingBox(world.World, position);
                        if (boundingBox == null)
                        {
                            continue;
                        }
                        blockBox = boundingBox.Value.OffsetBy(position + new Vector3(0.5));
                        if (TempBoundingBox.Intersects(blockBox))
                        {
                            if (entity.Velocity.Y < 0)
                            {
                                if (!collisionPoint.HasValue)
                                {
                                    collisionPoint = blockBox.Max.Y;
                                }
                                else if (collisionPoint.Value < blockBox.Max.Y)
                                {
                                    collisionPoint = blockBox.Max.Y;
                                }
                            }
                            else
                            {
                                if (!collisionPoint.HasValue)
                                {
                                    collisionPoint = blockBox.Min.Y;
                                }
                                else if (collisionPoint.Value > blockBox.Min.Y)
                                {
                                    collisionPoint = blockBox.Min.Y;
                                }
                            }
                            collision = position;
                        }
                    }
                }
            }

            if (collisionPoint != null)
            {
                if (entity.Velocity.Y < 0)
                {
                    // TODO: Do block event
                    //var block = world.GetBlock(collision);
                    //block.OnBlockWalkedOn(world, collision, this);
                    entity.Velocity = new Vector3(entity.Velocity.X,
                                                  entity.Velocity.Y + (collisionPoint.Value - TempBoundingBox.Min.Y),
                                                  entity.Velocity.Z);
                    collisionDirection = Vector3.Down;
                }
                else if (entity.Velocity.Y > 0)
                {
                    entity.Velocity = new Vector3(entity.Velocity.X,
                                                  entity.Velocity.Y - (TempBoundingBox.Max.Y - collisionPoint.Value),
                                                  entity.Velocity.Z);
                    collisionDirection = Vector3.Up;
                }
                return(true);
            }

            return(false);
        }
 public void UpdateState(IAABBEntity entity, Transform camera, out float velocityMultiplier)
 {
     CheckHead(entity, camera);
     velocityMultiplier = CheckBody(entity);
 }
Пример #18
0
 public static void EntityDestroy(this BlockData block, IWorld world, IAABBEntity entity, LuaTable context)
 {
     world.BlockDataTable.GetBlockBehaviour(block.ID)?.entity_destroy(entity, context);
 }
Пример #19
0
 public static void EntityFixedUpdate(this BlockData block, IWorld world, IAABBEntity entity, LuaTable context)
 {
     world.BlockDataTable.GetBlockBehaviour(block.ID)?.entity_fixed_update(entity, context);
 }
Пример #20
0
 public static void EntityOnCollisions(this BlockData block, IWorld world, IAABBEntity entity, CollisionFlags flags, LuaTable context)
 {
     world.BlockDataTable.GetBlockBehaviour(block.ID)?.entity_on_collisions(entity, flags, context);
 }
Пример #21
0
        // TODO: There's a lot of code replication here, perhaps it can be consolidated
        /// <summary>
        /// Performs terrain collision tests and adjusts the X-axis velocity accordingly
        /// </summary>
        /// <returns>True if the entity collides with the terrain</returns>
        private bool AdjustVelocityX(IAABBEntity entity, World world, out Vector3 collision, out Vector3 collisionDirection)
        {
            collision = Vector3.Zero;
            collisionDirection = Vector3.Zero;
            if (entity.Velocity.X == 0)
                return false;
            // Do some enviornment guessing to improve speed
            int minY = (int)entity.Position.Y - (entity.Position.Y < 0 ? 1 : 0);
            int maxY = (int)(entity.Position.Y + entity.Size.Width) - (entity.Position.Y < 0 ? 1 : 0);
            int minZ = (int)entity.Position.Z - (entity.Position.Z < 0 ? 1 : 0);
            int maxZ = (int)(entity.Position.Z + entity.Size.Depth) - (entity.Position.Z < 0 ? 1 : 0);
            int minX, maxX;

            // Expand bounding box to include area to be tested
            if (entity.Velocity.X < 0)
            {
                TempBoundingBox = new BoundingBox(
                    new Vector3(entity.BoundingBox.Min.X + entity.Velocity.X, entity.BoundingBox.Min.Y, entity.BoundingBox.Min.Z) - (entity.Size / 2),
                    new Vector3(entity.BoundingBox.Max.X, entity.BoundingBox.Max.Y, entity.BoundingBox.Max.Z) - (entity.Size / 2)
                );

                maxX = (int)(TempBoundingBox.Max.X);
                minX = (int)(TempBoundingBox.Min.X + entity.Velocity.X);
            }
            else
            {
                TempBoundingBox = new BoundingBox(
                    entity.BoundingBox.Min - (entity.Size / 2),
                    new Vector3(
                    entity.BoundingBox.Max.X + entity.Velocity.X, entity.BoundingBox.Max.Y, entity.BoundingBox.Max.Z) - (entity.Size / 2)
                );
                minX = (int)(entity.BoundingBox.Min.X);
                maxX = (int)(entity.BoundingBox.Max.X + entity.Velocity.X);
            }

            // Do terrain checks
            double? collisionPoint = null;
            BoundingBox blockBox;
            for (int x = minX; x <= maxX; x++)
            {
                for (int y = minY; y <= maxY; y++)
                {
                    for (int z = minZ; z <= maxZ; z++)
                    {
                        var position = new Vector3(x, y, z);
                        var boundingBox = BlockPhysicsProvider.GetBoundingBox(world, (Coordinates3D)position);
                        if (boundingBox == null)
                            continue;
                        blockBox = boundingBox.Value.OffsetBy(position);
                        if (TempBoundingBox.Intersects(blockBox))
                        {
                            if (entity.Velocity.X < 0)
                            {
                                if (!collisionPoint.HasValue)
                                    collisionPoint = blockBox.Max.X;
                                else if (collisionPoint.Value < blockBox.Max.X)
                                    collisionPoint = blockBox.Max.X;
                            }
                            else
                            {
                                if (!collisionPoint.HasValue)
                                    collisionPoint = blockBox.Min.X;
                                else if (collisionPoint.Value > blockBox.Min.X)
                                    collisionPoint = blockBox.Min.X;
                            }
                            collision = position;
                        }
                    }
                }
            }

            if (collisionPoint != null)
            {
                if (entity.Velocity.X < 0)
                {
                    entity.Velocity = new Vector3(
                        entity.Velocity.X - (TempBoundingBox.Min.X - collisionPoint.Value),
                        entity.Velocity.Y,
                        entity.Velocity.Z);
                    collisionDirection = Vector3.Left;
                }
                else if (entity.Velocity.X > 0)
                {
                    entity.Velocity = new Vector3(
                        entity.Velocity.X - (TempBoundingBox.Max.X - collisionPoint.Value),
                        entity.Velocity.Y,
                        entity.Velocity.Z);
                    collisionDirection = Vector3.Right;
                }
                return true;
            }

            return false;
        }
Пример #22
0
        public bool TestTerrainCollisionZ(IAABBEntity entity, out Vector3 collisionPoint)
        {
            // Things we need to do:
            // 1 - expand bounding box to include the destination and everything within
            // 2 - collect all blocks within that area
            // 3 - test bounding boxes in direction of motion

            collisionPoint = Vector3.Zero;

            if (entity.Velocity.Z == 0)
            {
                return(false);
            }

            bool negative;

            BoundingBox testBox;

            if (entity.Velocity.Z < 0)
            {
                testBox = new BoundingBox(
                    new Vector3(
                        entity.BoundingBox.Min.X,
                        entity.BoundingBox.Min.Y,
                        entity.BoundingBox.Min.Z + entity.Velocity.Z),
                    entity.BoundingBox.Max);
                negative = true;
            }
            else
            {
                testBox = new BoundingBox(
                    entity.BoundingBox.Min,
                    new Vector3(
                        entity.BoundingBox.Max.X,
                        entity.BoundingBox.Max.Y,
                        entity.BoundingBox.Max.Z + entity.Velocity.Z));
                negative = false;
            }

            double?collisionExtent = null;

            for (var x = (int)Math.Floor(testBox.Min.X); x <= (int)Math.Ceiling(testBox.Max.X); x++)
            {
                for (var z = (int)Math.Floor(testBox.Min.Z); z <= (int)Math.Ceiling(testBox.Max.Z); z++)
                {
                    for (var y = (int)Math.Floor(testBox.Min.Y); y <= (int)Math.Ceiling(testBox.Max.Y); y++)
                    {
                        var coords = new Coordinates3D(x, y, z);
                        if (!World.IsValidPosition(coords))
                        {
                            continue;
                        }

                        var _box = BlockPhysicsProvider.GetBoundingBox(World, coords);
                        if (_box == null)
                        {
                            continue;
                        }

                        var box = _box.Value.OffsetBy(coords.AsVector3());
                        if (testBox.Intersects(box))
                        {
                            if (negative)
                            {
                                if (collisionExtent == null || collisionExtent.Value < box.Max.Z)
                                {
                                    collisionExtent = box.Max.Z;
                                    collisionPoint  = coords.AsVector3();
                                }
                            }
                            else
                            {
                                if (collisionExtent == null || collisionExtent.Value > box.Min.Z)
                                {
                                    collisionExtent = box.Min.Z;
                                    collisionPoint  = coords.AsVector3();
                                }
                            }
                        }
                    }
                }
            }

            if (collisionExtent != null)             // Collision detected, adjust accordingly
            {
                var    extent = collisionExtent.Value;
                double diff;
                if (negative)
                {
                    diff = -(entity.BoundingBox.Min.Z - extent);
                }
                else
                {
                    diff = extent - entity.BoundingBox.Max.Z;
                }
                entity.Velocity = new Vector3(entity.Velocity.X, entity.Velocity.Y, (float)diff);
                return(true);
            }

            return(false);
        }