Управление камерой от первого лица

Недавно я запустил 3D-шутер от первого лица в Monogame, и у меня возникли проблемы с управлением камерой. Я не могу понять, как заставить камеру медленно поворачиваться по оси X, когда я удерживаю нажатой стрелку влево/вправо. ключи.

На данный момент код у меня такой:

Matrix view = Matrix.CreateLookAt(new Vector3(60, 20, 10), new Vector3(0, 0, 0), Vector3.UnitZ);
        Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), 800f / 600f, 0.1f, 100f);

А затем в разделе обновлений у меня есть это:

 if (kb.IsKeyDown(Keys.Left))
            {
                view = Matrix.CreateLookAt(new Vector3(60, 20, 10), new Vector3(-2, -2, -2), Vector3.UnitZ);
            }

Проблема в том, что в тот момент, когда этот код просто немного перемещает камеру в сторону, а затем останавливается. Я не уверен, как заставить его двигаться, пока я не отпущу ключ?

Весь мой код будет показан ниже, если я что-то забыл (вертикали этажей в настоящее время не работают, а имена, связанные с кораблем, связаны с тем, что я работал с учебником):

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace Game1
{
    /// <summary>
    /// This is the main type for your game.
    /// </summary>
    public class Game1 : Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        Model model;
        Vector3 ship1Location = new Vector3(40, 0, 0);
        Vector3 ship2Location = new Vector3(20, 0, 0);

        Matrix view = Matrix.CreateLookAt(new Vector3(60, 20, 10), new Vector3(0, 0, 0), Vector3.UnitZ);
        Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), 800f / 600f, 0.1f, 100f);

        VertexPositionTexture[] floorVerts;
        BasicEffect effect;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        protected override void Initialize()
        {
            floorVerts = new VertexPositionTexture[6];
            floorVerts[0].Position = new Vector3(-20, -20, 0);
            floorVerts[1].Position = new Vector3(-20, 20, 0);
            floorVerts[2].Position = new Vector3(20, -20, 0);
            floorVerts[3].Position = floorVerts[1].Position;
            floorVerts[4].Position = new Vector3(20, 20, 0);
            floorVerts[5].Position = floorVerts[2].Position;

            effect = new BasicEffect(graphics.GraphicsDevice);

            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            model = Content.Load<Model>("health2");

        }

        protected override void UnloadContent()
        {
        }

        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();




            Matrix ship1WorldMatrix = Matrix.CreateTranslation(ship1Location);
            Matrix ship2WorldMatrix = Matrix.CreateTranslation(ship2Location);

            if (IsCollision(model, ship1WorldMatrix, model, ship2WorldMatrix))
            {
                ship1Location = new Vector3(0, -20, 0);
            }
            KeyboardState kb = Keyboard.GetState();

            if (kb.IsKeyDown(Keys.A))
            {
                ship1Location += new Vector3(-0.1f, 0, 0);
            }

            if (kb.IsKeyDown(Keys.Left))
            {
                view = Matrix.CreateLookAt(new Vector3(60, 20, 10), new Vector3(-2, -2, -2), Vector3.UnitZ);
            }

            ship2Location += new Vector3(0, 0, 0);
            base.Update(gameTime);
        }

        private bool IsCollision(Model model1, Matrix world1, Model model2, Matrix world2)
        {
            for (int meshIndex1 = 0; meshIndex1 < model1.Meshes.Count; meshIndex1++)
            {
                BoundingSphere sphere1 = model1.Meshes[meshIndex1].BoundingSphere;
                sphere1 = sphere1.Transform(world1);

                for (int meshIndex2 = 0; meshIndex2 < model2.Meshes.Count; meshIndex2++)
                {
                    BoundingSphere sphere2 = model2.Meshes[meshIndex2].BoundingSphere;
                    sphere2 = sphere2.Transform(world2);

                    if (sphere1.Intersects(sphere2))
                        return true;
                }
            }
            return false;
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
            DrawGround();
            Matrix ship1WorldMatrix = Matrix.CreateTranslation(ship1Location);
            Matrix ship2WorldMatrix = Matrix.CreateTranslation(ship2Location);
            DrawModel(model, ship1WorldMatrix, view, projection);
            DrawModel(model, ship2WorldMatrix, view, projection);



            base.Draw(gameTime);
        }

        void DrawGround()
        {
            // The assignment of effect.View and effect.Projection
            // are nearly identical to the code in the Model drawing code.


            float aspectRatio =
                graphics.PreferredBackBufferWidth / (float)graphics.PreferredBackBufferHeight;
            float fieldOfView = Microsoft.Xna.Framework.MathHelper.PiOver4;
            float nearClipPlane = 1;
            float farClipPlane = 200;

            effect.Projection = Matrix.CreatePerspectiveFieldOfView(
                fieldOfView, aspectRatio, nearClipPlane, farClipPlane);


            foreach (var pass in effect.CurrentTechnique.Passes)
            {
                pass.Apply();

                graphics.GraphicsDevice.DrawUserPrimitives(
                    // We’ll be rendering two trinalges
                    PrimitiveType.TriangleList,
                    // The array of verts that we want to render
                    floorVerts,
                    // The offset, which is 0 since we want to start 
                    // at the beginning of the floorVerts array
                    0,
                    // The number of triangles to draw
                    2);
            }
        }



        private void DrawModel(Model model, Matrix world, Matrix view, Matrix projection)
        {
            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.AmbientLightColor = new Vector3(2f, 0, 0);
                    effect.World = world;
                    effect.View = view;
                    effect.Projection = projection;



                }

                mesh.Draw();
            }
        }
    }
}

person jayelj    schedule 09.01.2016    source источник


Ответы (1)


Поскольку положение камеры и точка, на которую она смотрит, являются необходимыми параметрами для создания матрицы вида, вы можете просто повернуть (например, по орбите) LookAt camLookAt вокруг camPosition следующим образом:

//declare class scope variables
Vector3 camPosition = new Vector3(60, 20, 10);//your starting camera position
Vector3 camLookAt = Vector3.Zero;//your starting camera focus point (look at)
Vector2 camUp = Vector3.Up;
float camYawRate = 0.004f;//set to taste


//in the Update method
float elapsed = gameTime.ElapsedGameTime.TotalSeconds;

//later in the method...
if (kb.IsKeyDown(Keys.Left))
    {
      camLookAt = Vector3.Transform(camLookAt - camPosition,Matrix.CreateRotationY(-camYawRate * elapsedTime)) + camPosition;);//remove the - sign from camYawRate to rotate to the right (or vice versa)

      view = Matrix.CreateLookAt(camPosition, camLookAt, camUp);
    }

И все, попробуй. Добавьте еще один такой же блок для поворота вправо.

person Steve H    schedule 10.01.2016
comment
Я знаю, что этот код устарел, но не могли бы вы исправить последний бит с помощью +camPosition;? Куда он должен идти, потому что вы не можете напрямую добавить Vector3 в Matrix. - person liaquore; 30.04.2019
comment
Написано правильно. Это не добавляет camPositon в матрицу. Он добавляет его к результату метода Vector3.Transform. Вот так: Vector3.Transform(Vector3, Matrix) + camPosition. Результатом Vector3.Transform является Vector3. Он добавляет camPosition к этому результату. Этот фрагмент кода заставляет камеру вращаться на месте. В 3D, чтобы повернуть на месте, вы переводите объект в исходную точку, немного поворачиваете его, а затем переводите обратно туда, где он был. +camPosition возвращает последний перевод в нужное место. Надеюсь это поможет. - person Steve H; 01.05.2019
comment
В моем классе камеры есть два поплавка Yaw и Pitch. Я хочу иметь их в классе, и когда я хочу переместить камеру, я добавляю или удаляю эти две переменные. В моем методе Update для моей камеры у меня есть строки кода: LookAt = Vector3.Transform(Vector3.Backward - Position, Matrix.CreateRotationY(-Yaw)) + Position и LookAt = Vector3.Transform(Vector3.Backward - Position, Matrix.CreateRotationX(-Pitch)) + Position. С помощью этого кода я могу изменить только высоту звука. Как мне сделать так, чтобы я мог двигаться одновременно? - person liaquore; 01.05.2019
comment
Проблема заключается в том, чтобы сохранить вашу ориентацию в виде двух поплавков. В 3D вы должны избегать использования углов для хранения общей информации о рыскании, тангаже и крене от кадра к кадру. Становится излишне сложным выполнять вращения вокруг одной оси, не затрагивая при этом другую ось. Вместо этого используйте матрицу. тогда это просто объединение матрицы последнего кадра с другой матрицей, построенной на этом кадре, которая представляет собой небольшое вращение или перевод stevehazen.wordpress.com/2010/02/15/ Приятного обучения. - person Steve H; 01.05.2019