Программирование простой игры в DirectX
Создание автомобиля
Имея движущуюся дорогу, приступим к программированию автомобиля. Для этого создадим отдельный класс, в котором разместим всю необходимую для управления автомобилем функциональность. В процессе рендеринга автомобиль должен оставаться неподвижным относительно перемещающейся сцены, за исключением перемещений влево-вправо, когда он будет объезжать препятствия, которые мы создадим позднее.
Добавление к проекту нового класса Car
- Выполните команду Project/Add Class и добавьте к проекту файл с именем Car.cs нового пустого класса
- Удалите из проекта лишние ссылки, автоматически добавленные оболочкой при создании нового файла (хотя это и не обязательно!)
- Скопируйте из начала файла DodgerGame объявления using используемых библиотечных пространств имен и разместите их также в начале файла Car.cs, чтобы можно было использовать короткие имена библиотечных классов
using System; using System.Drawing; using System.Windows.Forms; using Microsoft.DirectX; using Microsoft.DirectX.Direct3D; namespace Dodger { class Car { } }Листинг 17.23. Поключение библиотечных пространств имен в директивах using к файлу Car.cs
using System; using System.Drawing; using System.Windows.Forms; using Microsoft.DirectX; using Microsoft.DirectX.Direct3D; namespace Dodger { class Car { #region Секция переменных-характеристик автомобиля // Константы public const float HEIGHT = 2.5f;// Высота автомобиля public const float DEPTH = 3.0f;// Глубина автомобиля public const float SPEED_INCREMENT = 0.1f;// Приращение скорости бокового перемещения private const float SCALE = 0.85f; // Отношение размера автомобиля к ширине дороги // Переменные private float carLocation = DodgerGame.ROAD_LOCATION_LEFT;// Текущее положение слева private float carDiameter;// Диаметр для расчета столкновений с препятствием private float carSpeed = 10.0f;// Текущая боковая скорость автомобиля private bool movingLeft = false;// Направление перемещения влево private bool movingRight = false;// Направление перемещения вправо // Ссылки для Mesh-объекта автомобиля private Mesh carMesh = null; private Material[] carMaterials = null; private Texture[] carTextures = null; #endregion } }Листинг 17.24. Создание секции переменных-членов класса Car
Данные константы и переменные представляют собой все характеристики, необходимые для управления автомобилем.
- Добавьте в класс Car конструктор с параметрами, который при создании автомобиля автоматически загружает или устанавливает все его характеристики, необходимые для рендеринга
// Параметризованный конструктор класса public Car(Device device) { // Создать и загрузить Mesh-объект "Автомобиль", // используя ранее разработанный метод класса DodgerGame carMesh = DodgerGame.LoadMesh(device, @".\car.x", ref carMaterials, ref carTextures); // Мы должны вычислить сферу ограничения для нашего автомобиля VertexBuffer vb = carMesh.VertexBuffer; try { // Замкнуть вершинный буфер перед вычислением GraphicsStream stm = vb.Lock(0, 0, LockFlags.None); Vector3 center; // Мы не будем использовать центр, //но ссылка на него требуется float radius = Geometry.ComputeBoundingSphere(stm, carMesh.NumberVertices, carMesh.VertexFormat, out center); // Вычислим диаметр автомобиля carDiameter = (radius * 2) * SCALE; } finally { // Независимо от результата попытки // отмыкаем и устанавливаем вершинный буфер vb.Unlock(); vb.Dispose(); } }Листинг 17.25. Параметризованный конструктор класса Car
Здесь мы использовали статический метод класса DodgerGame для создания объекта автомобиля и загрузки в него Mesh-информации из файла car.x, только с другими ссылками. Мы вычислили граничную сферу, которая полностью включает все точки автомобиля, полученные из вершинного буфера. При использовании вершинного буфера автомобиля его необходимо замкнуть - сделать недоступным другим потокам. В блоке finally, который будет выполнен всегда и последним, мы разблокируем и освобождаем вершинный буфер.
Далее необходимо добавить метод, выполняющий прорисовку нашего автомобиля. В качестве аргумента нужно передать в этот метод ссылку на устройство, которое должно быть одним для всей сцены.
// Функция прорисовки автомобиля public void DrawCar(Device device) { // Автомобиль является слишком большим, предварительно уменьшим его device.Transform.World = Matrix.Scaling(SCALE, SCALE, SCALE) * Matrix.Translation(carLocation, HEIGHT, DEPTH); for (int i = 0; i < carMaterials.Length; i++) { device.Material = carMaterials[i]; device.SetTexture(0, carTextures[i]); carMesh.DrawSubset(i); } }Листинг 17.26. Функция DrawCar() отображения автомобиля
Здесь мы использовали такой-же код, как и при отображении дороги, но с предварительным масштабированием автомобиля.
Добавление свойств в класс Car
Ранее в секции #region объявления переменных класса Car мы создали ссылочные поля с доступом private, которые будут видны только внутри этого класса.
// Переменные private float carLocation = DodgerGame.ROAD_LOCATION_LEFT;// Текущее полощение слева private float carDiameter;// Диаметр для расчета столкновений с препятствием private float carSpeed = 10.0f;// Текущая боковая скорость автомобиля private bool movingLeft = false;// Направление перемещения влево private bool movingRight = false;// Направление перемещения вправоЛистинг 17.27. Созданные ранее ссылки с внутренним доступом
Но эти переменные являются управляемыми характеристиками автомобиля и должны изменяться внутри класса управления игрой DodgerGame. Поэтому упакуем их в общедоступные свойства, используя возможности языка C#.
#region Секция переменных-характеристик автомобиля // Константы public const float HEIGHT = 2.5f;// Высота автомобиля public const float DEPTH = 3.0f;// Глубина автомобиля public const float SPEED_INCREMENT = 0.1f;// Приращение скорости бокового перемещения private const float SCALE = 0.85f; // Отношение размера автомобиля к ширине дороги // Переменные private float carLocation = DodgerGame.ROAD_LOCATION_LEFT;// Текущее положение слева private float carDiameter;// Диаметр для расчета столкновений с препятствием private float carSpeed = 10.0f;// Текущая боковая скорость автомобиля private bool movingLeft = false;// Направление перемещения влево private bool movingRight = false;// Направление перемещения вправо // Ссылки для Mesh-объекта автомобиля private Mesh carMesh = null; private Material[] carMaterials = null; private Texture[] carTextures = null; // Общедоступные свойства для характеристик класса Car public float Location // Текущее положение слева { get { return carLocation; } set { carLocation = value; } } public float Diameter // Диаметр для расчета столкновений с препятствием { get { return carDiameter; } } public float Speed // Текущая боковая скорость автомобиля { get { return carSpeed; } set { carSpeed = value; } } public bool IsMovingLeft // Направление перемещения влево { get { return movingLeft; } set { movingLeft = value; } } public bool IsMovingRight // Направление перемещения вправо { get { return movingRight; } set { movingRight = value; } } #endregionЛистинг 17.28. Добавление общедоступных свойств в класс Car