コード例 #1
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);
        }
コード例 #2
0
ファイル: PhysicsEngine.cs プロジェクト: suicvne/TrueCraft
        /// <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);
        }
コード例 #3
0
ファイル: PhysicsEngine.cs プロジェクト: suicvne/TrueCraft
        /// <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);
        }
コード例 #4
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);
        }