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

Игровой мир, освещение, тени

Аннотация: Эта лабораторная работа посвящена методикам создания игрового мира, работе с освещением объектов.

Цель работы: Научиться создавать игровой мир, применять эффекты к его объектам

26.1. Подходы к созданию игрового мира

Для создания игрового мира трехмерной игры используют несколько подходов.

Игровой мир можно конструировать из отдельных объектов. Например, для того, чтобы создать комнату, можно использовать плоскости для строительства стен, пола и потолка, различные объекты для создания предметов, находящихся в комнате. При таком подходе для обработки взаимодействия игрового объекта и окружения можно применить уже знакомый вам подход проверки столкновений объектов. Этот подход мы использовали в предыдущих проектах – в примере с передвижением объекта среди группы других объектов, в примере, где нужно было касаться объектов для того, чтобы не допустить их падения.

Игровой мир можно сконструировать в трехмерном редакторе – например – ту же комнату, или целое здание, или ландшафт – и загрузить в игру в виде отдельной модели.

Мир можно сконструировать средствами XNA

Рассмотрим работу с игровым миром, который представлен в виде отдельной модели, содержащей все его элементы.

26.2. Загрузка игрового мира

В качестве объекта игрового мира, который мы использовали для демонстрации, применен готовый игровой объектHouse – взятый с сайта http://www.turbosquid.com.

Создадим новый игровой проект P19_1. На рис. 26.1 вы можете видеть его окно Обозреватель решений.

Обозреватель решений для проекта P19_1

Рис. 26.1. Обозреватель решений для проекта P19_1

В качестве игрового объекта мы используем модель ball.fbx, для построения игрового мира применим модель дома house1.x и плоскость plane.fbx. В этом проекте мы используем уже знакомый вам по предыдущим проектам класс modCls – он применяется для вывода моделей. Для управления игровым объектом мы применяем экранные стрелки, представленные файлом Arrows.png

В листинге 26.1 вы можете видеть код класса Game1.

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

namespace P19_1
{
    /// <summary>
    /// Это главный тип игры
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        //Матрицы
        Matrix viewMatrix;
        Matrix projMatrix;
        //Модели
        Model ball, house, plane;
        // Позиция объекта, поворот
        Vector3 avatarPosition = new Vector3(0, 0, -10);
        float avatarlRotation;

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

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

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

        //Расстояние от камеры до переднего и заднего плана
        float nearClip = 1.0f;
        float farClip = 2000.0f;
        //Объекты
        modCls ballObj;
        modCls mHouse;
        modCls mPlane;

        //Соотношение сторон экрана
        float aspectRatio;
        //Стрелки
        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);
            TouchPanel.EnabledGestures = GestureType.Pinch;
            // Дополнительный заряд аккумулятора заблокирован.
            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);
            //Загрузка моделей
            ball = Content.Load<Model>("ball");
            house = Content.Load<Model>("house1");
            plane = Content.Load<Model>("plane");
            aspectRatio = (float)graphics.GraphicsDevice.Viewport.Width /
  (float)graphics.GraphicsDevice.Viewport.Height;
            txtArrows = Content.Load<Texture2D>("Arrows");
            
        }

        /// <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();

            //обновить положение объекта
            UpdateAvatarPosition();
            //Обновить камеру
            UpdateCameraThirdPerson();
            //Сформировать объекты сцены
            DrawScene();
            base.Update(gameTime);
        }

        /// <summary>
        /// Вызывается, когда игра отрисовывается.
        /// </summary>
        /// <param name="gameTime">Предоставляет моментальный снимок значений времени.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            base.Draw(gameTime);
            //Вывод стрелок
            spriteBatch.Begin();
            spriteBatch.Draw(txtArrows, new Rectangle(500, 280, 300, 200), Color.White);
            spriteBatch.End();
            //Для нормального отображение 3D-сцены после работы spriteBatch
            GraphicsDevice.DepthStencilState = DepthStencilState.Default;
        }
        //Обновляем состояние объекта
        void UpdateAvatarPosition()
        {

            TouchCollection touchLocations = TouchPanel.GetState();
            foreach (TouchLocation touchLocation in touchLocations)
            {
                if (touchLocation.State == TouchLocationState.Pressed || touchLocation.State == TouchLocationState.Moved)
                {
                    //Движение вверх
                    if (MenuSelect(keyForward, touchLocation.Position))
                    {
                        Matrix forwardMovement = Matrix.CreateRotationY(avatarlRotation);
                        Vector3 v = new Vector3(0, forwardSpeed, 0);
                        v = Vector3.Transform(v, forwardMovement);
                        avatarPosition.Y += v.Y;
                    }
                    //Вперед
                    if (MenuSelect(keyUp, touchLocation.Position))
                    {
                        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 (MenuSelect(keyBack, touchLocation.Position))
                    {
                        Matrix forwardMovement = Matrix.CreateRotationY(avatarlRotation);
                        Vector3 v = new Vector3(0, -forwardSpeed, 0);
                        v = Vector3.Transform(v, forwardMovement);
                        avatarPosition.Y += v.Y;

                    }
                    //Поворот влево
                    if (MenuSelect(keyLeft, touchLocation.Position))
                    {
                        avatarlRotation += rotationSpeed;
                    }
                    //Назад
                    if (MenuSelect(keyDown, touchLocation.Position))
                    {
                        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 (MenuSelect(keyRight, touchLocation.Position))
                    {
                        avatarlRotation -= rotationSpeed;
                    }

                }
            }

            //До тех пор, пока разрешена обработка жестов
            while (TouchPanel.IsGestureAvailable)
            {
                //прочитаем жест
                GestureSample gs = TouchPanel.ReadGesture();
                if (gs.GestureType == GestureType.Pinch)
                {
                    //Найдем предыдущие координаты, вычтя из текущих координат приращение
                    Vector2 oldPos = gs.Position - gs.Delta;
                    Vector2 oldPos2 = gs.Position2 - gs.Delta2;
                    //Получим расстояние между текущими точками касания
                    float currentDist = Vector2.Distance(gs.Position, gs.Position2);
                    //Получим расстояние между предыдущими точками касания
                    float oldDist = Vector2.Distance(oldPos, oldPos2);
                    //Умножим переменную, отвечающую за масштабирование спрайта
                    //на результат деления текущего расстояния на предыдущее
                    if (currentDist / oldDist > 1)
                    {
                        viewAngle -= MathHelper.ToRadians(0.5f);
                    }
                    else
                    {
                        viewAngle += MathHelper.ToRadians(0.5f);
                    }

                }
            }
            
      
            //Если новый угол обзора вышел за дозволенные пределы
            //изменяем его
            if (viewAngle > MathHelper.ToRadians(180.0f)) viewAngle = MathHelper.ToRadians(179.9f);
            if (viewAngle < MathHelper.ToRadians(0.0f)) viewAngle = MathHelper.ToRadians(0.1f);
        }
        //Обновляем положение камеры при выбранном виде от третьего лица
        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()
        {
            //очистить коллекцию компонентов
            Components.Clear();
            //Вывести дом
            mHouse = new modCls(this, house, graphics);
            mHouse.WorldMatrix = Matrix.CreateTranslation(0, 0, -5) * Matrix.CreateScale(5f);
            mHouse.ViewMatrix = viewMatrix;
            mHouse.ProjectMatrix = projMatrix;
            Components.Add(mHouse);
            //выведем игровой объект
            ballObj = new modCls(this, ball, graphics);
            ballObj.WorldMatrix = Matrix.CreateRotationY(avatarlRotation) * Matrix.CreateTranslation(avatarPosition);
            ballObj.ViewMatrix = viewMatrix;
            ballObj.ProjectMatrix = projMatrix;
            Components.Add(ballObj);
            //Вывести плоскость
            mPlane = new modCls(this, plane, graphics);
            mPlane.WorldMatrix = Matrix.CreateScale(700) * Matrix.CreateRotationY(MathHelper.ToRadians(90)) *
                Matrix.CreateRotationZ(MathHelper.ToRadians(90)) *
                Matrix.CreateTranslation(0, -2, 0);
            mPlane.ViewMatrix = viewMatrix;
            mPlane.ProjectMatrix = projMatrix;
            Components.Add(mPlane);
        }

    }
}
Листинг 26.1. Код класса Game1
Гулич Анна
Гулич Анна
Невозможно пройти тесты, в окне с вопросами пусто