平滑碰撞(墙面滑动)

时间:2013-10-11 00:15:28

标签: c# 3d xna collision

我最近开始学习XNA和C#因为我正在做的学校项目。我在YouTube上关注本教程,了解XNA如何使用3D: http://www.youtube.com/watch?v=XkpZLzT5OV4

实际上效果很好,我已经对我的项目进行了一些修改/添加了一些功能。我最近开始实现碰撞检测,它可以很好地使用BoundingBoxes,但相机在碰撞时会停止。我想在墙上滑动,就像其他第一人称游戏一样。基本上,如果移动指向墙壁,相机会停止。我希望相机在墙上“滑动”,移除指向墙壁的移动,并使其仅平行于墙壁。我希望这是有道理的。这样,玩家在触摸墙壁时仍然可以四处移动。 我查看了谷歌上的很多帖子,我看到我需要玩玩家的速度。但是,我的代码中没有实现任何速度,我不知道如何添加它。

以下是我的主要课程:

这是我的Camera类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace Deimos
{
class Camera : GameComponent
{
    // ...

    // Constructor
    public Camera(Game game, Vector3 position, Vector3 rotation, float speed)
        : base(game)
    {
        CameraSpeed = speed;

        // Setup projection matrix
        Projection = Matrix.CreatePerspectiveFieldOfView(
            MathHelper.PiOver4,
            Game.GraphicsDevice.Viewport.AspectRatio,
            0.05f,
            1000.0f // Draw distance
        );

        // Set the camera position and rotation
        moveTo(position, rotation);


        PreviousMouseState = Mouse.GetState();
    }





    // Set camera position and rotation
    private void moveTo(Vector3 position, Vector3 rotation)
    {
        // Thanks to the properties set at the beginning, setting up these values will execute 
        // the code inside the property (i.e update our vectors)
        Position = position;
        Rotation = rotation;
    }

    // Update the look at vector
    private void updateLookAt()
    {
        // Build a rotation matrix
        Matrix rotationMatrix = Matrix.CreateRotationX(CameraRotation.X) * Matrix.CreateRotationY(CameraRotation.Y);
        // Build look at offset vector
        Vector3 lookAtOffset = Vector3.Transform(Vector3.UnitZ, rotationMatrix);
        // Update our camera's look at vector
        CameraLookAt = CameraPosition + lookAtOffset;
    }

    // Methods that simulate movement
    private Vector3 previewMove(Vector3 amount)
    {
        // Create a rotate matrix
        Matrix rotate = Matrix.CreateRotationY(CameraRotation.Y);
        // Create a movement vector
        Vector3 movement = new Vector3(amount.X, amount.Y, amount.Z);
        movement = Vector3.Transform(movement, rotate);
        // Return the value of camera position + movement vector

        if (Collision.CheckCollision(CameraPosition + movement)) // Testing for the UPCOMING position
        {
            return CameraPosition;
        }
        else
        {
            return CameraPosition + movement;
        }
    }

    // Method that actually moves the camera
    private void move(Vector3 scale)
    {
        moveTo(previewMove(scale), Rotation);
    }

    // Update method, overriding the original one
    public override void Update(GameTime gameTime)
    {
        float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;

        CurrentMouseState = Mouse.GetState();

        // Let's get user inputs
        KeyboardState ks = Keyboard.GetState();

        // Handle basic key movement
        Vector3 moveVector = Vector3.Zero;
        if (ks.IsKeyDown(ForwardKey))
        {
            moveVector.Z = 1;
        }
        if (ks.IsKeyDown(BackKey))
        {
            moveVector.Z = -1;
        }

        if (ks.IsKeyDown(LeftKey))
        {
            moveVector.X = 1;
        }
        if (ks.IsKeyDown(RightKey))
        {
            moveVector.X = -1;
        }

        if (ks.IsKeyDown(Keys.Up))
        {
            moveVector.Y = 1;
        }
        if (ks.IsKeyDown(Keys.Down))
        {
            moveVector.Y = -1;
        }

        if (moveVector != Vector3.Zero) // If we are actually moving (if the vector changed depending on the ifs)
        {
            // Normalize that vector so that we don't move faster diagonally
            moveVector.Normalize();

            // Now we add in move factor and speed
            moveVector *= dt * CameraSpeed;

            DebugScreen.Log(moveVector.ToString());

            // Move camera!
            move(moveVector);
        }


        // Handle mouse movement
        float deltaX;
        float deltaY;
        if (CurrentMouseState != PreviousMouseState)
        {
            // Cache mouse location
            deltaX = CurrentMouseState.X - (Game.GraphicsDevice.Viewport.Width / 2); // We devide by 2 because mouse will be in the center
            deltaY = CurrentMouseState.Y - (Game.GraphicsDevice.Viewport.Height / 2);

            MouseRotationBuffer.X -= MouseSpeed * deltaX * dt;
            MouseRotationBuffer.Y -= MouseSpeed * deltaY * dt;

            // Limit the user so he can't do an unlimited movement with his mouse (like a 7683°)
            if(MouseRotationBuffer.Y < MathHelper.ToRadians(-75.0f))
                MouseRotationBuffer.Y = MouseRotationBuffer.Y - (MouseRotationBuffer.Y - MathHelper.ToRadians(-75.0f));
            if(MouseRotationBuffer.Y > MathHelper.ToRadians(75.0f))
                MouseRotationBuffer.Y = MouseRotationBuffer.Y - (MouseRotationBuffer.Y - MathHelper.ToRadians(75.0f));

            float mouseInverted = (MouseInverted == true) ? 1 : -1;

            Rotation = new Vector3(
                mouseInverted * MathHelper.Clamp(
                    MouseRotationBuffer.Y,
                    MathHelper.ToRadians(-75.0f),
                    MathHelper.ToRadians(75.0f)
                ),
                MathHelper.WrapAngle(MouseRotationBuffer.X), 
                                     // This is so the camera isn't going really fast after some time 
                                     // (as we are increasing the speed with time)
                                     0
                                     );

            // Resetting them
            deltaX = 0;
            deltaY = 0;

        }

        // Putting the cursor in the middle of the screen
        Mouse.SetPosition(Game.GraphicsDevice.Viewport.Width / 2, Game.GraphicsDevice.Viewport.Height / 2);

        PreviousMouseState = CurrentMouseState;

        base.Update(gameTime);

    }
}
}

这是我的碰撞课:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;


namespace Deimos
{
class Collision
{
    // ...
    public Boolean CheckCollision(Vector3 cameraPosition)
    {
        // Creating the sphere of the camera for later collisions checks
        BoundingBox cameraBox = new BoundingBox(
            new Vector3(
                cameraPosition.X - (PlayerDimention.X / 2),
                cameraPosition.Y - (PlayerDimention.Y),
                cameraPosition.Z - (PlayerDimention.Z / 2)
            ),
            new Vector3(
                cameraPosition.X + (PlayerDimention.X / 2),
                cameraPosition.Y,
                cameraPosition.Z + (PlayerDimention.Z / 2)
            )
        );

        // Let's check for collision with our boxes
        if (CollisionBoxesArray != null)
        {
            for (int i = 0; i < CollisionBoxesArray.Length; i++)
            {
                if (CollisionBoxesArray[i].Contains(cameraBox) != ContainmentType.Disjoint) // If our player is inside the collision region
                    return true;
            }
        }
        if (CollisionSpheresArray != null)
        {
            // And with our spheres
            for (int i = 0; i < CollisionSpheresArray.Length; i++)
            {
                if (CollisionSpheresArray[i].Contains(cameraBox) != ContainmentType.Disjoint)
                    return true;
            }
        }

        return false;

    }

}
}

我真的不知道该怎么办。非常感谢。

编辑:我更新了我的帖子,删除了一些不必要的代码,因此它对您来说更具可读性。 我也更好地解释了我的问题。

1 个答案:

答案 0 :(得分:1)

我觉得这样的事情可能有用。这与你做的基本相同,只是previewMove返回一个允许你沿着墙壁滑动的Vector3。该功能现在所做的是返回一个值,该值检查相机是否可以在运动矢量的X,Y或Z方向上移动,以及相机是否可以在X,Y和/或Z中移动,它将(那些)值添加到CameraPosition

private Vector3 previewMove(Vector3 amount)
{
    // Create a rotate matrix
    Matrix rotate = Matrix.CreateRotationY(CameraRotation.Y);
    // Create a movement vector
    Vector3 movement = new Vector3(amount.X, amount.Y, amount.Z);
    movement = Vector3.Transform(movement, rotate);
    // Return the value of camera position + movement vector

    return CameraPosition + new Vector3(
        Collision.CheckCollision(CameraPosition + new Vector3(movement.X, 0, 0)) ? 0 : movement.X,
        Collision.CheckCollision(CameraPosition + new Vector3(0, movement.Y, 0)) ? 0 : movement.Y,
        Collision.CheckCollision(CameraPosition + new Vector3(0, 0, movement.Z)) ? 0 : movement.Z);

}

我没有尝试过代码,所以我不知道这会有多好用。但希望它会有所帮助。