コード例 #1
0
ファイル: PhysicsEngine.cs プロジェクト: nevercast/Craft.Net
        // 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 blockId = world.GetBlockId(position);
                        var boundingBox = Block.GetBoundingBox(blockId);
                        if (boundingBox == null)
                            continue;
                        blockBox = new BoundingBox(boundingBox.Value.Min + position,
                            boundingBox.Value.Max + 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;
        }
コード例 #2
0
ファイル: PhysicsEngine.cs プロジェクト: nevercast/Craft.Net
        /// <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 blockId = world.GetBlockId(position);
                        var boundingBox = Block.GetBoundingBox(blockId);
                        if (boundingBox == null)
                            continue;
                        blockBox = new BoundingBox(boundingBox.Value.Min + position,
                            boundingBox.Value.Max + 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;
        }
コード例 #3
0
ファイル: Block.cs プロジェクト: nevercast/Craft.Net
 internal static void DefaultBlockUpdateHandler(BlockDescriptor block, World world, Coordinates3D updatedBlock)
 {
     var logic = GetLogicDescriptor(block);
     var support = logic.GetSupportDirection(block, world, updatedBlock);
     var supportingBlock = updatedBlock;
     switch (support)
     {
         case SupportDirection.Down:
             supportingBlock = updatedBlock + Coordinates3D.Down;
             break;
         case SupportDirection.Up:
             supportingBlock = updatedBlock + Coordinates3D.Up;
             break;
         case SupportDirection.East:
             supportingBlock = updatedBlock + Coordinates3D.East;
             break;
         case SupportDirection.West:
             supportingBlock = updatedBlock + Coordinates3D.West;
             break;
         case SupportDirection.North:
             supportingBlock = updatedBlock + Coordinates3D.North;
             break;
         case SupportDirection.South:
             supportingBlock = updatedBlock + Coordinates3D.South;
             break;
         default:
             return;
     }
     if (!World.IsValidPosition(supportingBlock))
         return;
     if (world.GetBlockId(supportingBlock) == 0) // TODO: Air isn't the only thing that can't support some blocks
         OnBlockMined(block, world, updatedBlock, null); // TODO: Consider using a seperate delegate for blocks destroyed through non-player actions
 }
コード例 #4
0
ファイル: CakeItem.cs プロジェクト: nevercast/Craft.Net
 public static void OnItemUsedOnBlock(ItemDescriptor item, World world, Coordinates3D clickedBlock, Coordinates3D clickedSide, Coordinates3D cursorPosition)
 {
     if (world.GetBlockId(clickedBlock + clickedSide) == 0)
         world.SetBlockId(clickedBlock + clickedSide, CakeBlock.BlockId);
 }
コード例 #5
0
ファイル: Block.cs プロジェクト: nevercast/Craft.Net
 internal static void DefaultBlockPlacedHandler(BlockDescriptor block, World world, Coordinates3D clickedBlock, Coordinates3D clickedSide, Coordinates3D cursorPosition)
 {
     if (world.GetBlockId(clickedBlock + clickedSide) == 0) // TODO: There are more situations than just air when a block can be overwritten
     {
         world.SetBlockId(clickedBlock + clickedSide, block.Id);
         world.SetMetadata(clickedBlock + clickedSide, block.Metadata);
     }
 }