Основы разработки компьютерных игр в XNA Game Studio

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

Разбить на страницы
Показывать лекцию целиком

Примеры к лабораторной работе

Задачи работы

  • Освоить технику перемещения объектов
  • Освоить технику масштабирования объектов
  • Освоить технику перемещения камеры
  • Пространственные преобразования объектов

    Создадим новый проект P15_1 и на его примере рассмотрим следующие пространственные преобразования объектов

  • Перемещение
  • Вращение
  • Масштабирование
  • Для выполнения этих операций нам понадобится модификация мировой матрицы. Модификации, соответствующие перемещению объекта мы выполним по клавиатурным командам, остальные модификации будут выполняться автоматически в цикле обновления.

    Для этого примера мы создали несколько простых трехмерных моделей в редакторе Blender. В частности – это два разноцветных шара и куб. Вот как выглядит игровой экран проекта P15_1 (рис. 20.1.).

    (рис 20.1) Игровой экран проекта P15_1

    Для упрощения работы с несколькими игровыми объектами мы создадим игровой компонент - modCls, который будет отвечать за хранение параметров, соответствующих этим объектам и за их визуализацию. В листинге 20.1. вы можете видеть код этого объекта.

    using System;
    using System.Collections.Generic;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Audio;
    using Microsoft.Xna.Framework.GamerServices;
    using Microsoft.Xna.Framework.Graphics;
    using Microsoft.Xna.Framework.Input;
    using Microsoft.Xna.Framework.Storage;
    using Microsoft.Xna.Framework.Content;
    
    namespace P15_1
    {
        public class modCls : Microsoft.Xna.Framework.DrawableGameComponent
        {
            //Модель
            Model myModel;
            //Мировая матрица
            public  Matrix WorldMatrix;
            //Соотношение сторон экрана
            public  float aspectRatio;
            //Для управления графическим устройством
            GraphicsDeviceManager graphics;
            //Конструктор получает на вход 
            //игровой класс, модель, объект для управления графическим устройством
            public modCls(Game game, Model mod, GraphicsDeviceManager grf)
                : base(game)
            {
                myModel = mod;
                graphics = grf;
                aspectRatio = (float)graphics.GraphicsDevice.Viewport.Width /
    (float)graphics.GraphicsDevice.Viewport.Height;
            }
    
            public override void Initialize()
            {
                // TODO: Add your initialization code here
                base.Initialize();
            }
    
            public override void Update(GameTime gameTime)
            {
    
                foreach (ModelMesh mesh in myModel.Meshes)
                {
                    //Для каждого эффекта в сети
                    foreach (BasicEffect effect in mesh.Effects)
                    {
                        //Установить освещение по умолчанию
                        effect.LightingEnabled = true;
                        effect.EnableDefaultLighting();
                        //установить матрицы
                        effect.World = WorldMatrix;
                        effect.View = Matrix.CreateLookAt(new Vector3(0.0f, 0.0f, 10.0f), Vector3.Zero, Vector3.Up);
                        effect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f),
                             aspectRatio, 1.0f, 1000.0f);
                    }
                }
    
                base.Update(gameTime);
            }
            public override void Draw(GameTime gameTime)
            {
                foreach (ModelMesh mesh in myModel.Meshes)
                {
                    mesh.Draw();
                }
                base.Draw(gameTime);
            }
        }
    }

    Управление объектами возложено на основной игровой класс – его метод Update используется для вычисления новых позиций объектов и обновления информации объектов. Код этого класса вы можете видеть в листинге 20.2. Шар, расположенный сверху, автоматически циклически изменяет размер, куб вращается вокруг осей X и Y, шар, расположенный ниже, можно перемещать. Клавиши-стрелки используются для перемещения по осям X и Y (вверх, вниз, влево и вправо), клавиши W и S перемещают объект вперед и назад по оси Z.

    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_1
    {
        public class Game1 : Microsoft.Xna.Framework.Game
        {
            GraphicsDeviceManager graphics;
            //Мировая матрица
            Matrix WorldMatrixM, WorldMatrixM1, WorldMatrixM2;
            //Направление движения для модели modelCls1
            Vector3 directM1;
            //Модели - 
            //modelCls вращается
            //modelCls1 перемещается по клавиатурным командам
            //modelCls2 изменяет размер
            modCls modelCls, modelCls1, modelCls2;
            //Переменные для текущего размера и 
            //текущего приращения размера модели modelCls2
            float size, sizeDelta;
            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()
            {
                //загрузка моделей и создание объектов, используемых для 
                //хранения информации о моделях и их вывода на экран
                modelCls = new modCls(this, Content.Load<Model>("cube"), graphics);
                modelCls1 = new modCls(this, Content.Load<Model>("ball"), graphics);
                modelCls2 = new modCls(this, Content.Load<Model>("ball2"), graphics);
                //Добавляем объекты в коллекцию Components - для их 
                //автоматического вывода на экран
                Components.Add(modelCls);
                Components.Add(modelCls1);
                Components.Add(modelCls2);
                //Значения для приращения размера и текущего размера
                sizeDelta = 0.01f;
                size = 0.5f;
                //Установка исходного положения для модели modelCls1
                directM1 = new Vector3(2.0f, -1.0f, 1.0f);
                //Установка матриц, которые используются для управления объектами
                WorldMatrixM = Matrix.Identity;
                WorldMatrixM1 = Matrix.CreateTranslation(directM1);
                WorldMatrixM2 = Matrix.CreateScale(size);
            }
    
            protected override void UnloadContent()
            {
                // TODO: Unload any non ContentManager content here
            }
    
            protected override void Update(GameTime gameTime)
            {
    
    
                KeyboardState kb = Keyboard.GetState();
                //По нажатии клавиши-стрелки "вверх" перемещаем модель
                //modelCls1 вверх
                if (kb.IsKeyDown(Keys.Up))
                {
                    directM1.Y=directM1 .Y +0.1f;
                    WorldMatrixM1 = Matrix.CreateTranslation(directM1);
                }
                //Нажатие клавиши "вниз" - перемещение вниз
                if (kb.IsKeyDown(Keys.Down))
                {
                    directM1.Y = directM1.Y - 0.1f;
                    WorldMatrixM1 = Matrix.CreateTranslation(directM1);
                }
                //Нажатие клавиши "влево" - перемещение влево
                if (kb.IsKeyDown(Keys.Left))
                {
                    directM1.X = directM1.X - 0.1f;
                    WorldMatrixM1 = Matrix.CreateTranslation(directM1);
                }
                //Нажатие клавиши "вправо" - перемещение вправо
                if (kb.IsKeyDown(Keys.Right))
                {
                    directM1.X = directM1.X + 0.1f;
                    WorldMatrixM1 = Matrix.CreateTranslation(directM1);
                }
                //Нажатие клавиши "W" - перемещение вперед
                if (kb.IsKeyDown(Keys.W))
                {
                    directM1.Z = directM1.Z - 0.1f;
                    WorldMatrixM1 = Matrix.CreateTranslation(directM1);
                }
                //Нажатие клавиши "S" - перемещение назад
                if (kb.IsKeyDown(Keys.S))
                {
                    directM1.Z = directM1.Z + 0.1f;
                    WorldMatrixM1 = Matrix.CreateTranslation(directM1);
                }
                
                //Если текущий размер меньше 0.5 - 
                //устанавливаем приращение, равное 0.01
                //Если текущий размер больше 1.5 -
                //устанавливаем приращение -0.01
                if (size < 0.5) sizeDelta = 0.01f;
                if (size > 1.5) sizeDelta = -0.01f;
                size += sizeDelta;
    
                //Матрица для объекта modelCls1 устанавливается для поворота его вокруг
                //осей X и Y на один градус
                WorldMatrixM = WorldMatrixM * Matrix.CreateRotationY(MathHelper.ToRadians(1))*
                    Matrix .CreateRotationX (MathHelper .ToRadians (1));
                //Установка матрицы для объекта modelCls2
                WorldMatrixM2 = Matrix.CreateScale(size) * Matrix.CreateTranslation(new Vector3(-5.0f, 2.0f, -3.0f));
                //Передаем матрицы объектам
                modelCls.WorldMatrix = WorldMatrixM;
                modelCls1.WorldMatrix = WorldMatrixM1;
                modelCls2.WorldMatrix = WorldMatrixM2;
                base.Update(gameTime);
            }
    
       
            protected override void Draw(GameTime gameTime)
            {
                graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
                
                base.Draw(gameTime);
            }
        }
    }

    Рассмотрев способы модификации объектов, поговорим об особенностях настройки камеры.

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

    Камера играет огромную роль в трехмерных играх. В играх от первого лица позиция камеры ассоциируется с позицией игрока. Примерами таких игр игры класса simulator, shooter. В играх от третьего лица (strategy) камера расположена выше игрока и сдвинута назад – играющий может видеть своего персонажа и часть карты.

    Рассмотрим простой пример управления камерой, в котором реализовано перемещение камеры, а так же изменение угла зрения. Фактически это – пример работы камеры от первого лица. Изменение угла зрения очень похоже на изменение фокусного расстояния в оптических приборах – увеличение фокусного расстояния, которое приводит к уменьшению угла зрения, позволяет "приближать" далеко расположенные объекты. Уменьшение фокусного расстояния, соответствующее увеличению угла зрения, позволяет охватить взглядом большую территорию.

    Создадим новый проект – P15_2. Рассмотрим на его примере вышеописанные операции с камерой.

    В листинге 20.3. вы можете найти код класса Game1, реализующего демонстрацию работы с камерой.

    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_2
    {
        public class Game1 : Microsoft.Xna.Framework.Game
        {
            //соотношение сторон окна вывода
            float aspectRatio;
    
            //Матрицы
            Matrix viewMatrix;
            Matrix projMatrix;
            Matrix worldMatrix;
            //Модель
            Model ball;
            
            // Позиция и вращение камеры
            Vector3 camPos = new Vector3(0, 0, -50);
            float camRotation;
    
            // Направление камеры
            Vector3 cameraDirection = new Vector3(0, 0, 1);
    
            // Установка скорости поворота и передвижения
            float rotationSpeed = 0.01f;
            float forwardSpeed = 1.0f;
    
            //Угол зрения камеры
            float viewAngle = MathHelper.ToRadians(45.0f);
            GraphicsDeviceManager graphics;
    
            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");
                //Установка мировой матрицы
                worldMatrix = Matrix.Identity;
                //Соотношение сторон
                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)
            {
                //Получить состояние клавиатуры
                KeyboardState keyboardState = Keyboard.GetState();
    
                //Поворот влево
                if (keyboardState.IsKeyDown(Keys.Left))
                {
                     camRotation += rotationSpeed;
                }
                //Поворот вправо
                if (keyboardState.IsKeyDown(Keys.Right))
                {
                    camRotation -= rotationSpeed;
                }
    
                //Переедвижение вперед
                if (keyboardState.IsKeyDown(Keys.Up))
                {
                    //Создаем матрицу поворота
                    Matrix forwardMov = Matrix.CreateRotationY(camRotation);
                    //Создаем новый вектор, содержащий скорость движения
                    Vector3 v = new Vector3(0, 0, forwardSpeed);
                    //Трансформируем матрицу в вектор
                    v = Vector3.Transform(v, forwardMov);
                    //модифицируем позицию таким образом, чтобы
                    //она соответствовала новым данным
                    camPos.Z += v.Z;
                    camPos.X += v.X;
                }
                //Передвижение назад
                if (keyboardState.IsKeyDown(Keys.Down))
                {
                    Matrix forwardMovement = Matrix.CreateRotationY(camRotation);
                    Vector3 v = new Vector3(0, 0, -forwardSpeed);
                    v = Vector3.Transform(v, forwardMovement);
                    camPos.Z += v.Z;
                    camPos.X += v.X;
                }
    
                //Уменьшение угла обзора камеры
                if (keyboardState.IsKeyDown(Keys.W))
                {
                    viewAngle -= MathHelper.ToRadians(1.0f);
                }
                //Увеличение угла обзора камеры
                if (keyboardState.IsKeyDown(Keys.S))
                {
                    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);
    
                Matrix rotationMatrix = Matrix.CreateRotationY(camRotation);
    
                // Вектор направления камеры
                Vector3 cameraTransformed = Vector3.Transform(cameraDirection, rotationMatrix);
    
                // Вычисляем положение камеры
                Vector3 cameraLookat = camPos + cameraTransformed;
    
                // Устанавливаем матрицу вида
                viewMatrix = Matrix.CreateLookAt(camPos, cameraLookat, new Vector3(0.0f, 1.0f, 0.0f));
                //Устанавливаем проекционную матрицу
                projMatrix = Matrix.CreatePerspectiveFieldOfView(viewAngle, aspectRatio, 1.0f, 1000.0f);
    
                base.Update(gameTime);
            }
            /// <summary>
            /// This is called when the game should draw itself.
            /// </summary>
            /// <param name="gameTime">Provides a snapshot of timing values</param>
            protected override void Draw(GameTime gameTime)
            {
                graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
    
                foreach (ModelMesh mesh in ball.Meshes)
                {
                    foreach (BasicEffect effect in mesh.Effects)
                    {
                        effect.LightingEnabled = true;
                        effect.EnableDefaultLighting();
                        effect.Projection = projMatrix;
                        effect.View = viewMatrix;
                        effect.World = worldMatrix;
    
                    }
                    mesh.Draw();
                }
    
                base.Draw(gameTime);
            }
        }
    }

    На рис. 20.2. вы можете видеть изображение игрового экрана проекта P15_2.

    (рис 20.2) Экран проекта P15_2

    Шар, который мы видим в окне, искажен – угол обзора камеры увеличен, а расстояние от камеры до объекта сильно уменьшено.

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

    Рассмотрим пример, иллюстрирующий работу с камерой в режиме от первого лица и в режиме вида от третьего лица. Для подготовки этого примера мы использовали справочные материалы по 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.3. вы можете видеть состояние игрового экрана проекта P15_3 в режиме вида от третьего лица.

    (рис 20.3) Экран проекта P15_3, вид от третьего лица

    На рис. 20.4. вы можете видеть состояние экрана проекта P15_3 в режиме вида от первого лица.

    (рис 20.4) Экран проекта P15_3, вид от первого лица

    На рис. 20.5. вы можете видеть состояние экрана проекта P15_3 в режиме вида от третьего лица с уменьшенным полем видимости камеры.

    (рис 20.5) Экран проекта P15_3, вид от третьего лица, уменьшенное поле видимости
    Страницы:

    Примеры к лабораторной работе

    Задачи работы

  • Освоить технику перемещения объектов
  • Освоить технику масштабирования объектов
  • Освоить технику перемещения камеры
  • Пространственные преобразования объектов

    Создадим новый проект P15_1 и на его примере рассмотрим следующие пространственные преобразования объектов

  • Перемещение
  • Вращение
  • Масштабирование
  • Для выполнения этих операций нам понадобится модификация мировой матрицы. Модификации, соответствующие перемещению объекта мы выполним по клавиатурным командам, остальные модификации будут выполняться автоматически в цикле обновления.

    Для этого примера мы создали несколько простых трехмерных моделей в редакторе Blender. В частности – это два разноцветных шара и куб. Вот как выглядит игровой экран проекта P15_1 (рис. 20.1.).

    (рис 20.1) Игровой экран проекта P15_1

    Для упрощения работы с несколькими игровыми объектами мы создадим игровой компонент - modCls, который будет отвечать за хранение параметров, соответствующих этим объектам и за их визуализацию. В листинге 20.1. вы можете видеть код этого объекта.

    using System;
    using System.Collections.Generic;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Audio;
    using Microsoft.Xna.Framework.GamerServices;
    using Microsoft.Xna.Framework.Graphics;
    using Microsoft.Xna.Framework.Input;
    using Microsoft.Xna.Framework.Storage;
    using Microsoft.Xna.Framework.Content;
    
    namespace P15_1
    {
        public class modCls : Microsoft.Xna.Framework.DrawableGameComponent
        {
            //Модель
            Model myModel;
            //Мировая матрица
            public  Matrix WorldMatrix;
            //Соотношение сторон экрана
            public  float aspectRatio;
            //Для управления графическим устройством
            GraphicsDeviceManager graphics;
            //Конструктор получает на вход 
            //игровой класс, модель, объект для управления графическим устройством
            public modCls(Game game, Model mod, GraphicsDeviceManager grf)
                : base(game)
            {
                myModel = mod;
                graphics = grf;
                aspectRatio = (float)graphics.GraphicsDevice.Viewport.Width /
    (float)graphics.GraphicsDevice.Viewport.Height;
            }
    
            public override void Initialize()
            {
                // TODO: Add your initialization code here
                base.Initialize();
            }
    
            public override void Update(GameTime gameTime)
            {
    
                foreach (ModelMesh mesh in myModel.Meshes)
                {
                    //Для каждого эффекта в сети
                    foreach (BasicEffect effect in mesh.Effects)
                    {
                        //Установить освещение по умолчанию
                        effect.LightingEnabled = true;
                        effect.EnableDefaultLighting();
                        //установить матрицы
                        effect.World = WorldMatrix;
                        effect.View = Matrix.CreateLookAt(new Vector3(0.0f, 0.0f, 10.0f), Vector3.Zero, Vector3.Up);
                        effect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f),
                             aspectRatio, 1.0f, 1000.0f);
                    }
                }
    
                base.Update(gameTime);
            }
            public override void Draw(GameTime gameTime)
            {
                foreach (ModelMesh mesh in myModel.Meshes)
                {
                    mesh.Draw();
                }
                base.Draw(gameTime);
            }
        }
    }

    Управление объектами возложено на основной игровой класс – его метод Update используется для вычисления новых позиций объектов и обновления информации объектов. Код этого класса вы можете видеть в листинге 20.2. Шар, расположенный сверху, автоматически циклически изменяет размер, куб вращается вокруг осей X и Y, шар, расположенный ниже, можно перемещать. Клавиши-стрелки используются для перемещения по осям X и Y (вверх, вниз, влево и вправо), клавиши W и S перемещают объект вперед и назад по оси Z.

    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_1
    {
        public class Game1 : Microsoft.Xna.Framework.Game
        {
            GraphicsDeviceManager graphics;
            //Мировая матрица
            Matrix WorldMatrixM, WorldMatrixM1, WorldMatrixM2;
            //Направление движения для модели modelCls1
            Vector3 directM1;
            //Модели - 
            //modelCls вращается
            //modelCls1 перемещается по клавиатурным командам
            //modelCls2 изменяет размер
            modCls modelCls, modelCls1, modelCls2;
            //Переменные для текущего размера и 
            //текущего приращения размера модели modelCls2
            float size, sizeDelta;
            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()
            {
                //загрузка моделей и создание объектов, используемых для 
                //хранения информации о моделях и их вывода на экран
                modelCls = new modCls(this, Content.Load<Model>("cube"), graphics);
                modelCls1 = new modCls(this, Content.Load<Model>("ball"), graphics);
                modelCls2 = new modCls(this, Content.Load<Model>("ball2"), graphics);
                //Добавляем объекты в коллекцию Components - для их 
                //автоматического вывода на экран
                Components.Add(modelCls);
                Components.Add(modelCls1);
                Components.Add(modelCls2);
                //Значения для приращения размера и текущего размера
                sizeDelta = 0.01f;
                size = 0.5f;
                //Установка исходного положения для модели modelCls1
                directM1 = new Vector3(2.0f, -1.0f, 1.0f);
                //Установка матриц, которые используются для управления объектами
                WorldMatrixM = Matrix.Identity;
                WorldMatrixM1 = Matrix.CreateTranslation(directM1);
                WorldMatrixM2 = Matrix.CreateScale(size);
            }
    
            protected override void UnloadContent()
            {
                // TODO: Unload any non ContentManager content here
            }
    
            protected override void Update(GameTime gameTime)
            {
    
    
                KeyboardState kb = Keyboard.GetState();
                //По нажатии клавиши-стрелки "вверх" перемещаем модель
                //modelCls1 вверх
                if (kb.IsKeyDown(Keys.Up))
                {
                    directM1.Y=directM1 .Y +0.1f;
                    WorldMatrixM1 = Matrix.CreateTranslation(directM1);
                }
                //Нажатие клавиши "вниз" - перемещение вниз
                if (kb.IsKeyDown(Keys.Down))
                {
                    directM1.Y = directM1.Y - 0.1f;
                    WorldMatrixM1 = Matrix.CreateTranslation(directM1);
                }
                //Нажатие клавиши "влево" - перемещение влево
                if (kb.IsKeyDown(Keys.Left))
                {
                    directM1.X = directM1.X - 0.1f;
                    WorldMatrixM1 = Matrix.CreateTranslation(directM1);
                }
                //Нажатие клавиши "вправо" - перемещение вправо
                if (kb.IsKeyDown(Keys.Right))
                {
                    directM1.X = directM1.X + 0.1f;
                    WorldMatrixM1 = Matrix.CreateTranslation(directM1);
                }
                //Нажатие клавиши "W" - перемещение вперед
                if (kb.IsKeyDown(Keys.W))
                {
                    directM1.Z = directM1.Z - 0.1f;
                    WorldMatrixM1 = Matrix.CreateTranslation(directM1);
                }
                //Нажатие клавиши "S" - перемещение назад
                if (kb.IsKeyDown(Keys.S))
                {
                    directM1.Z = directM1.Z + 0.1f;
                    WorldMatrixM1 = Matrix.CreateTranslation(directM1);
                }
                
                //Если текущий размер меньше 0.5 - 
                //устанавливаем приращение, равное 0.01
                //Если текущий размер больше 1.5 -
                //устанавливаем приращение -0.01
                if (size < 0.5) sizeDelta = 0.01f;
                if (size > 1.5) sizeDelta = -0.01f;
                size += sizeDelta;
    
                //Матрица для объекта modelCls1 устанавливается для поворота его вокруг
                //осей X и Y на один градус
                WorldMatrixM = WorldMatrixM * Matrix.CreateRotationY(MathHelper.ToRadians(1))*
                    Matrix .CreateRotationX (MathHelper .ToRadians (1));
                //Установка матрицы для объекта modelCls2
                WorldMatrixM2 = Matrix.CreateScale(size) * Matrix.CreateTranslation(new Vector3(-5.0f, 2.0f, -3.0f));
                //Передаем матрицы объектам
                modelCls.WorldMatrix = WorldMatrixM;
                modelCls1.WorldMatrix = WorldMatrixM1;
                modelCls2.WorldMatrix = WorldMatrixM2;
                base.Update(gameTime);
            }
    
       
            protected override void Draw(GameTime gameTime)
            {
                graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
                
                base.Draw(gameTime);
            }
        }
    }

    Рассмотрев способы модификации объектов, поговорим об особенностях настройки камеры.

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

    Камера играет огромную роль в трехмерных играх. В играх от первого лица позиция камеры ассоциируется с позицией игрока. Примерами таких игр игры класса simulator, shooter. В играх от третьего лица (strategy) камера расположена выше игрока и сдвинута назад – играющий может видеть своего персонажа и часть карты.

    Рассмотрим простой пример управления камерой, в котором реализовано перемещение камеры, а так же изменение угла зрения. Фактически это – пример работы камеры от первого лица. Изменение угла зрения очень похоже на изменение фокусного расстояния в оптических приборах – увеличение фокусного расстояния, которое приводит к уменьшению угла зрения, позволяет "приближать" далеко расположенные объекты. Уменьшение фокусного расстояния, соответствующее увеличению угла зрения, позволяет охватить взглядом большую территорию.

    Создадим новый проект – P15_2. Рассмотрим на его примере вышеописанные операции с камерой.

    В листинге 20.3. вы можете найти код класса Game1, реализующего демонстрацию работы с камерой.

    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_2
    {
        public class Game1 : Microsoft.Xna.Framework.Game
        {
            //соотношение сторон окна вывода
            float aspectRatio;
    
            //Матрицы
            Matrix viewMatrix;
            Matrix projMatrix;
            Matrix worldMatrix;
            //Модель
            Model ball;
            
            // Позиция и вращение камеры
            Vector3 camPos = new Vector3(0, 0, -50);
            float camRotation;
    
            // Направление камеры
            Vector3 cameraDirection = new Vector3(0, 0, 1);
    
            // Установка скорости поворота и передвижения
            float rotationSpeed = 0.01f;
            float forwardSpeed = 1.0f;
    
            //Угол зрения камеры
            float viewAngle = MathHelper.ToRadians(45.0f);
            GraphicsDeviceManager graphics;
    
            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");
                //Установка мировой матрицы
                worldMatrix = Matrix.Identity;
                //Соотношение сторон
                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)
            {
                //Получить состояние клавиатуры
                KeyboardState keyboardState = Keyboard.GetState();
    
                //Поворот влево
                if (keyboardState.IsKeyDown(Keys.Left))
                {
                     camRotation += rotationSpeed;
                }
                //Поворот вправо
                if (keyboardState.IsKeyDown(Keys.Right))
                {
                    camRotation -= rotationSpeed;
                }
    
                //Переедвижение вперед
                if (keyboardState.IsKeyDown(Keys.Up))
                {
                    //Создаем матрицу поворота
                    Matrix forwardMov = Matrix.CreateRotationY(camRotation);
                    //Создаем новый вектор, содержащий скорость движения
                    Vector3 v = new Vector3(0, 0, forwardSpeed);
                    //Трансформируем матрицу в вектор
                    v = Vector3.Transform(v, forwardMov);
                    //модифицируем позицию таким образом, чтобы
                    //она соответствовала новым данным
                    camPos.Z += v.Z;
                    camPos.X += v.X;
                }
                //Передвижение назад
                if (keyboardState.IsKeyDown(Keys.Down))
                {
                    Matrix forwardMovement = Matrix.CreateRotationY(camRotation);
                    Vector3 v = new Vector3(0, 0, -forwardSpeed);
                    v = Vector3.Transform(v, forwardMovement);
                    camPos.Z += v.Z;
                    camPos.X += v.X;
                }
    
                //Уменьшение угла обзора камеры
                if (keyboardState.IsKeyDown(Keys.W))
                {
                    viewAngle -= MathHelper.ToRadians(1.0f);
                }
                //Увеличение угла обзора камеры
                if (keyboardState.IsKeyDown(Keys.S))
                {
                    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);
    
                Matrix rotationMatrix = Matrix.CreateRotationY(camRotation);
    
                // Вектор направления камеры
                Vector3 cameraTransformed = Vector3.Transform(cameraDirection, rotationMatrix);
    
                // Вычисляем положение камеры
                Vector3 cameraLookat = camPos + cameraTransformed;
    
                // Устанавливаем матрицу вида
                viewMatrix = Matrix.CreateLookAt(camPos, cameraLookat, new Vector3(0.0f, 1.0f, 0.0f));
                //Устанавливаем проекционную матрицу
                projMatrix = Matrix.CreatePerspectiveFieldOfView(viewAngle, aspectRatio, 1.0f, 1000.0f);
    
                base.Update(gameTime);
            }
            /// <summary>
            /// This is called when the game should draw itself.
            /// </summary>
            /// <param name="gameTime">Provides a snapshot of timing values</param>
            protected override void Draw(GameTime gameTime)
            {
                graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
    
                foreach (ModelMesh mesh in ball.Meshes)
                {
                    foreach (BasicEffect effect in mesh.Effects)
                    {
                        effect.LightingEnabled = true;
                        effect.EnableDefaultLighting();
                        effect.Projection = projMatrix;
                        effect.View = viewMatrix;
                        effect.World = worldMatrix;
    
                    }
                    mesh.Draw();
                }
    
                base.Draw(gameTime);
            }
        }
    }

    На рис. 20.2. вы можете видеть изображение игрового экрана проекта P15_2.

    (рис 20.2) Экран проекта P15_2

    Шар, который мы видим в окне, искажен – угол обзора камеры увеличен, а расстояние от камеры до объекта сильно уменьшено.

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

    Рассмотрим пример, иллюстрирующий работу с камерой в режиме от первого лица и в режиме вида от третьего лица. Для подготовки этого примера мы использовали справочные материалы по 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.3. вы можете видеть состояние игрового экрана проекта P15_3 в режиме вида от третьего лица.

    (рис 20.3) Экран проекта P15_3, вид от третьего лица

    На рис. 20.4. вы можете видеть состояние экрана проекта P15_3 в режиме вида от первого лица.

    (рис 20.4) Экран проекта P15_3, вид от первого лица

    На рис. 20.5. вы можете видеть состояние экрана проекта P15_3 в режиме вида от третьего лица с уменьшенным полем видимости камеры.

    (рис 20.5) Экран проекта P15_3, вид от третьего лица, уменьшенное поле видимости
    Вернуться к учебному плану