Опубликован: 14.08.2012 | Доступ: свободный | Студентов: 880 / 20 | Оценка: 5.00 / 5.00 | Длительность: 09:59:00
Специальности: Программист
Самостоятельная работа 17:

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

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

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

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

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

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

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

namespace P17_2
{
    /// <summary>
    /// Это главный тип игры
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        //соотношение сторон окна вывода
        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);
        //Стрелки
        Texture2D txtArrows;
        Rectangle keyForward = new Rectangle(500, 280, 100, 100);
        Rectangle keyUp = new Rectangle(600, 280, 100, 100);
        Rectangle keyBack = new Rectangle(700, 280, 100, 100);
        Rectangle keyLeft = new Rectangle(500, 380, 100, 100);
        Rectangle keyDown = new Rectangle(600, 380, 100, 100);
        Rectangle keyRight = new Rectangle(700, 380, 100, 100);
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            graphics.IsFullScreen = true;
            // Частота кадра на Windows Phone по умолчанию — 30 кадров в секунду.
            TargetElapsedTime = TimeSpan.FromTicks(333333);

            // Дополнительный заряд аккумулятора заблокирован.
            InactiveSleepTime = TimeSpan.FromSeconds(1);
        }

        /// <summary>
        /// Позволяет игре выполнить инициализацию, необходимую перед запуском.
        /// Здесь можно запросить нужные службы и загрузить неграфический
        /// контент.  Вызов base.Initialize приведет к перебору всех компонентов и
        /// их инициализации.
        /// </summary>
        protected override void Initialize()
        {
            // ЗАДАЧА: добавьте здесь логику инициализации

            base.Initialize();
        }

        /// <summary>
        /// LoadContent будет вызываться в игре один раз; здесь загружается
        /// весь контент.
        /// </summary>
        protected override void LoadContent()
        {
            // Создайте новый SpriteBatch, который можно использовать для отрисовки текстур.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            txtArrows = Content.Load<Texture2D>("Arrows");
            //Загрузка модели
            ball = Content.Load<Model>("ball");
            //Установка мировой матрицы
            worldMatrix = Matrix.Identity;
            //Соотношение сторон
            aspectRatio = (float)graphics.GraphicsDevice.Viewport.Width /
(float)graphics.GraphicsDevice.Viewport.Height;

            // ЗАДАЧА: используйте здесь this.Content для загрузки контента игры
        }

        /// <summary>
        /// UnloadContent будет вызываться в игре один раз; здесь выгружается
        /// весь контент.
        /// </summary>
        protected override void UnloadContent()
        {
            // ЗАДАЧА: выгрузите здесь весь контент, не относящийся к ContentManager
        }
        //Проверка попадания касания в область, занимаемую одним из элементов управления
        private bool MenuSelect(Rectangle m, Vector2 p)
        {
            bool res = false;
            if (p.X > m.X && p.X < m.X + m.Width && p.Y > m.Y && p.Y < m.Y + m.Height)
            {
                res = true;
            }

            return res;
        }
        /// <summary>
        /// Позволяет игре запускать логику обновления мира,
        /// проверки столкновений, получения ввода и воспроизведения звуков.
        /// </summary>
        /// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param>
        protected override void Update(GameTime gameTime)
        {
            // Позволяет выйти из игры
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            TouchCollection touchLocations = TouchPanel.GetState();

            foreach (TouchLocation touchLocation in touchLocations)
            {
                //Если пользователь коснулся элемента управления либо продолжает касаться
                if (touchLocation.State == TouchLocationState.Pressed || touchLocation.State == TouchLocationState.Moved)
                {
                    //Увеличение угла обзора
                    if (MenuSelect(keyForward, touchLocation.Position))
                    {
                        viewAngle += MathHelper.ToRadians(1.0f);
                    }
                    //Вперед
                    if (MenuSelect(keyUp, touchLocation.Position))
                    {
                        //Создаем матрицу поворота
                        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 (MenuSelect(keyBack, touchLocation.Position))
                    {
                        viewAngle -= MathHelper.ToRadians(1.0f);
                    }
                    //Влево
                    if (MenuSelect(keyLeft, touchLocation.Position))
                    {
                        camRotation -= rotationSpeed;
                    }
                    //Нащад
                    if (MenuSelect(keyDown, touchLocation.Position))
                    {
                        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 (MenuSelect(keyRight, touchLocation.Position))
                    {
                        camRotation += rotationSpeed;
                    }

                }
            }
            
            //Если новый угол обзора вышел за дозволенные пределы
            //изменяем его
            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>
        /// Вызывается, когда игра отрисовывается.
        /// </summary>
        /// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param>
        protected override void Draw(GameTime gameTime)
        {
            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();
            }

            spriteBatch.Begin();
            spriteBatch.Draw(txtArrows, new Rectangle(500, 280, 300, 200), Color.White);
            spriteBatch.End();
            //Для нормального отображение 3D-сцены после работы spriteBatch
            GraphicsDevice.DepthStencilState = DepthStencilState.Default;

            base.Draw(gameTime);
        }
    }
}

Листинг 24.3. Код класса Game1

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

Экран проекта P17_2

Рис. 24.2. Экран проекта P17_2
Гулич Анна
Гулич Анна
Невозможно пройти тесты, в окне с вопросами пусто