Спонсор: Microsoft
Опубликован: 10.04.2009 | Доступ: свободный | Студентов: 3247 / 243 | Оценка: 4.49 / 4.39 | Длительность: 17:21:00
Специальности: Программист
Самостоятельная работа 15:

Пространственные преобразования объектов

Настройка перемещения камеры: продвинутые приемы

Рассмотрим пример, иллюстрирующий работу с камерой в режиме от первого лица и в режиме вида от третьего лица. Для подготовки этого примера мы использовали справочные материалы по XNA.

Создадим новый проект P15_3. Наш проект выполняет следующие действия. Он выводит на экран плоскость и набор кубов, среди которых может двигаться шар. Причем, движение может осуществляться в двух режимах. В первом режиме демонстрируется работа камеры при виде от первого лица – шар в таком случае не выводится, сцена выглядит так, как будто мы смотрим на нее с позиции шара. Во втором режиме демонстрируется вид от третьего лица – камера находится выше объекта. В играх часто применяется следующий прием – главный игровой объект неподвижен, а игровой мир перемещается, создавая иллюзию движения этого объекта. В нашем случае все выглядит точно так же – шар неподвижно находится в центре экрана, но за счет перемещения игровой сцены создается иллюзия его движения по экрану и по сцене.

В листинге 20.4. вы можете найти код класса Game1, который содержит пример. Для перемещения используются клавиши-стрелки, для смены состояний камеры – клавиши A и S. Клавиша A переключает программу в режим камеры от первого лица, S – в режим вида от третьего лица. Клавиша R уменьшает поле зрения камеры, клавиша F – увеличивает.

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace P15_3
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        //Матрицы
        Matrix viewMatrix;
        Matrix projMatrix;
        //Модели
        Model ball, cube, plane;
        // Позиция объекта, поворот
        Vector3 avatarPosition = new Vector3(0, 0, -50);
        float avatarlRotation;

        // Положение камеры
        Vector3 cameraReference = new Vector3(0, 0, 10);
        Vector3 thirdPersonReference = new Vector3(0, 200, -200);

        // Скорости поворота и движения
        float rotationSpeed = 1f / 60f;
        float forwardSpeed = 50f / 60f;

        //Поле зрения камеры
        float viewAngle = MathHelper.ToRadians(45.0f);

        //Расстояние от камеры до переднего и заднего плана
        //static float nearClip = 5.0f;
        float nearClip = 1.0f;
        float farClip = 2000.0f;

        // Установка позиции камеры 2 - вид от третьего лица
        //1 - от первого лица
        int cameraState = 2;
        //Соотношение сторон экрана
        float aspectRatio;
       public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            
        }

        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
        }
        protected override void LoadContent()
        {
            //Загрузка моделей
            ball = Content.Load<Model>("ball");
            cube = Content.Load<Model>("cube");
            plane = Content.Load<Model>("plane");
            aspectRatio = (float)graphics.GraphicsDevice.Viewport.Width /
  (float)graphics.GraphicsDevice.Viewport.Height;
        }

        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        protected override void Update(GameTime gameTime)
        {
          //обновить положение объекта
            UpdateAvatarPosition();
            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
            //Если состояние камеры 1 - вызвать процедуру
            //обновлеие камеры от первого лица
            //если 2 - от третьего лица
            switch (cameraState)
            {
                case 1:
                    UpdateCamera();
                    break;
                case 2:
                    UpdateCameraThirdPerson();
                    break;
            }
            //вывести объекты сцены
            DrawScene();
                      //Если выбран вид от третьего лица - вывести объект
            if (cameraState == 2)
            {
                DrawModel(ball, Matrix.CreateRotationY(avatarlRotation) * Matrix.CreateTranslation(avatarPosition));
            }
          
            base.Draw(gameTime);
        }

        //Обновляем состояние объекта
        void UpdateAvatarPosition()
        {
            KeyboardState keyboardState = Keyboard.GetState();

            //Поворот влево
            if (keyboardState.IsKeyDown(Keys.Left))
            {
                avatarlRotation += rotationSpeed;
            }
            //Поворот вправо
            if (keyboardState.IsKeyDown(Keys.Right) )
            {
                avatarlRotation -= rotationSpeed;
            }
            //Движение вперед
            if (keyboardState.IsKeyDown(Keys.Up) )
            {
                Matrix forwardMovement = Matrix.CreateRotationY(avatarlRotation);
                Vector3 v = new Vector3(0, 0, forwardSpeed);
                v = Vector3.Transform(v, forwardMovement);
                avatarPosition.Z += v.Z;
                avatarPosition.X += v.X;
            }
            //Движение назад
            if (keyboardState.IsKeyDown(Keys.Down) )
            {
                Matrix forwardMovement = Matrix.CreateRotationY(avatarlRotation);
                Vector3 v = new Vector3(0, 0, -forwardSpeed);
                v = Vector3.Transform(v, forwardMovement);
                avatarPosition.Z += v.Z;
                avatarPosition.X += v.X;
            }
            //Переключить на режим камеры от первого лица
            if (keyboardState.IsKeyDown(Keys.A))
            {
                cameraState=1;
            }

            //Переключить на режим камеры от третьего лица
            if (keyboardState.IsKeyDown(Keys.S))
            {
                cameraState = 2;
            }
            //Уменьшение угла обзора камеры
            if (keyboardState.IsKeyDown(Keys.R))
            {
                viewAngle -= MathHelper.ToRadians(1.0f);
            }
            //Увеличение угла обзора камеры
            if (keyboardState.IsKeyDown(Keys.F))
            {
                viewAngle += MathHelper.ToRadians(1.0f);
            }
            //Если новый угол обзора вышел за дозволенные пределы
            //изменяем его
            if (viewAngle > MathHelper.ToRadians(180.0f)) viewAngle = MathHelper.ToRadians(179.9f);
            if (viewAngle < MathHelper.ToRadians(0.0f)) viewAngle = MathHelper.ToRadians(0.1f);
        }

        //Обновляем состояние камеры при выбранном виде от первого лица
        void UpdateCamera()
        {
            //Текущая позиция камеры
            Vector3 cameraPosition = avatarPosition;
            //Поворот
            Matrix rotationMatrix = Matrix.CreateRotationY(avatarlRotation);

            // Направление камеры
            Vector3 transformedReference = Vector3.Transform(cameraReference, rotationMatrix);

            // Новая позиция камеры
            Vector3 cameraLookat = cameraPosition + transformedReference;

            //Матрица вида
            viewMatrix = Matrix.CreateLookAt(cameraPosition, cameraLookat, new Vector3(0.0f, 1.0f, 0.0f));
            //проекционная матрица
            projMatrix = Matrix.CreatePerspectiveFieldOfView(viewAngle, aspectRatio, nearClip, farClip);
        }

        //Обновляем положение камеры при выбранном виде от третьего лица
        void UpdateCameraThirdPerson()
        {
            //Поворот камеры
            Matrix rotationMatrix = Matrix.CreateRotationY(avatarlRotation);

            // Направление камеры
            Vector3 transformedReference = Vector3.Transform(thirdPersonReference, rotationMatrix);

            // Позиция камеры
            Vector3 cameraPosition = transformedReference + avatarPosition;

            //Матрица вида
            viewMatrix = Matrix.CreateLookAt(cameraPosition, avatarPosition, new Vector3(0.0f, 1.0f, 0.0f));
            //Проецкионная матрица
            projMatrix = Matrix.CreatePerspectiveFieldOfView(viewAngle, aspectRatio, nearClip, farClip);
        }

       //Вывод объектов сцены
        void DrawScene()
        {
            //Вывести кубы, расположенные в пять рядов
            //по пять штук в трех уровнях
            for (int x = 0; x < 5; x++)
            {
                for (int y = 0; y < 3; y++)
                {
                    for (int z = 0; z < 5; z++)
                    {
                        DrawModel(cube, Matrix.CreateTranslation(x * 40, y * 3, z * 40));
                    }
                }
            }
            //Вывести плоскость - при выводе увеличиваем модель и поворачиваем соответствующим
            //образом
            DrawModel(plane, Matrix.CreateScale (100)*Matrix .CreateRotationY (MathHelper .ToRadians (90))*
                Matrix.CreateRotationZ(MathHelper.ToRadians(90))*
                Matrix .CreateTranslation (80,-2.5f,80));
        }

        //Процедура вывода модели
        //Принимает мировую матрицу для позиционирования модели
        //и переменную модели

        void DrawModel(Model model, Matrix world)
        {
            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.LightingEnabled = true;
                    effect.EnableDefaultLighting();
                    effect.Projection = projMatrix;
                    effect.View = viewMatrix;
                    effect.World = world;
                }
                mesh.Draw();
            }
        }
    }
}
Листинг 20.4. Код класса Game1
Alina Lasskaja
Alina Lasskaja

Быть может кто-то из Вас знает игру Sims, к какому жанру она относиться? Жизненная симуляция, ролевая игра, там можно и дома строить.....