Программирование простой игры в DirectX
Создание объекта Car в движке игры
Теперь у нас есть класс Car и нужно разместить код создания и использования его экземпляра (объекта) в основном движке игры - классе DodgerGame.
#region Секция переменных-членов класса DodgerGame
..................................................
// Ссылка на объект автомобиля
private Car car = null;
#endregion
Листинг
17.29.
Объявление поля-ссылки объекта автомобиля в классе DodgerGame
Поскольку мы используем ссылку на устройство в конструкторе класса Car, то объект устройства должен быть создан прежде создания объекта автомобиля. Это так и есть, поскольку устройство мы создаем в функции InitializeGraphics() самым первым.
С учетом того, что устройство может сбрасываться и каждый раз после этого нужно восстанавливать все его характеристики, код создания автомобиля нужно разместить в обработчике сброса устройства OnDeviceReset() класса DodgerGame.
-
Поместите
в классе DodgerGame код создания объекта
автомобиля в конце обработчика OnDeviceReset() после
создания объекта дороги
// Обработчик события сброса устройства
private void OnDeviceReset(object sender, EventArgs e)
{
// Установка камеры
............................................
// Включить освещение сцены
device.RenderState.Lighting = true;
// Загрузка Mesh-файла и создание объекта дороги
roadMesh = LoadMesh(device, @".\road.x",
ref roadMaterials, ref roadTextures);
// Загрузка Mesh-файла и создание объекта автомобиля
car = new Car(device);
}
Листинг
17.30.
Создание объекта автомобиля в классе DodgerGame
Теперь нужно отобразить в сцене созданный объект автомобиля.
-
Добавьте
в функцию OnPaint() класса DodgerGame,
сразу после двух вызовов функции отображения дороги, код
рисования автомобиля
// Код организации рендеринга
protected override void OnPaint(PaintEventArgs e)
{
// Очистка экрана
device.Clear(ClearFlags.Target | ClearFlags.ZBuffer,
Color.CornflowerBlue, 1.0F, 0);
// Вычисление новых параметров рисования дороги
OnFrameUpdate();
// Формирование о отображение сцены
device.BeginScene();
{
// Отображение двух секций дороги с разной глубиной
DrawRoad(0.0F, 0.0F, RoadDepth0);
DrawRoad(0.0F, 0.0F, RoadDepth1);
// Отображение автомобиля
car.DrawCar(device);
}
device.EndScene();
device.Present();
this.Invalidate();
}
Листинг
17.31.
Вызов функции рисования автомобиля в классе DodgerGame
-
Добавьте
к проекту из прилагаемого каталога Source файл car.x командой Project/Add Existing Item
-
В
панели Solution Explorer вызовите для файла car.x через
контекстное меню панель Properties и установите свойство
оболочки Copy to Output Directory в
значение Copy if newer
-
Постройте
приложение и убедитесь, что появился неподвижный относительно
сцены автомобиль на движущейся дороге, прижатый к ее левой
стороне
Клавиатурное управление автомобилем
Применим для управления горизонтальными перемещениями автомобиля
клавиатурные стрелки, причем продублируем коды стрелок на
основной и дополнительной клавиатуре. Для остановки автомобиля
предусмотрим клавишу
на обоих клавиатурах.
-
В
классе DodgerGame переопределите виртуальный
метод OnKeyDown() формы,
унаследованный от ее библиотечного базового класса Control (выполните
переопределение заготовки метода вручную с
ввода ключевого слова override для правильного
создания оболочкой аргументов метода)
// Переопределение виртуального метода OnKeyDown() в классе DodgerGame
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
}
Листинг
17.32.
Переопределение виртуального метода OnKeyDown() вручную
// Переопределение виртуального метода OnKeyDown() в классе DodgerGame
protected override void OnKeyDown(KeyEventArgs e)
{
// Выход по Esc - завершение работы приложения
if (e.KeyCode == Keys.Escape)
this.Close();
// Перемещение влево
if (e.KeyCode == Keys.Left || e.KeyCode == Keys.NumPad4)
{
car.IsMovingLeft = true;
car.IsMovingRight = false;
}
// Перемещение вправо
if (e.KeyCode == Keys.Right || e.KeyCode == Keys.NumPad6)
{
car.IsMovingRight = true;
car.IsMovingLeft = false;
}
// Остановить перемещение автомобиля
if (e.KeyCode == Keys.Down || e.KeyCode == Keys.NumPad2)
{
car.IsMovingLeft = false;
car.IsMovingRight = false;
}
}
Листинг
17.33.
Клавиатурное управление горизонтальными перемещениями автомобиля
Здесь мы отлавливаем и обрабатываем нажатия клавиш со стрелками для перемещения автомобиля влево или вправо и устанавливаем флаги необходимости этого перемещения. Также предусмотрены клавиши завершения работы приложения и сброса флагов для остановки перемещения. Коды нажатых клавиш мы сравниваем с полями перечисления System.Windows.Forms.Keys, в котором имеются именованные коды для всех клавиш клавиатуры.
-
Добавьте
в класс Car функцию LocationCar() для
пересчета новых горизонтальных позиций автомобиля в зависимости
от установленных характеристик его перемещения
// Управление перемещением автомобиля
public void LocationCar(float elapsedTime)
{
// Перемещаем влево
if (movingLeft)
{
this.Location += carSpeed * elapsedTime;
// Если достигли левого края дороги...
if (this.Location>= DodgerGame.ROAD_LOCATION_LEFT)
{
movingLeft = false;
this.Location = DodgerGame.ROAD_LOCATION_LEFT;
}
}
// Перемещаем вправо
if (movingRight)
{
this.Location -= carSpeed * elapsedTime;
// Если достигли правого края дороги...
if (this.Location <= DodgerGame.ROAD_LOCATION_RIGHT)
{
movingRight = false;
this.Location = DodgerGame.ROAD_LOCATION_RIGHT;
}
}
}
Листинг
17.34.
Расчет новых позиций для перемещения автомобиля
-
Добавьте
в класс Car функцию IncrementSpeed() для
увеличения скорости горизонтального перемещения автомобиля
// Функция увеличения скорости горизонтального перемещения автомобиля
public void IncrementSpeed()
{
carSpeed += SPEED_INCREMENT;
}
Листинг
17.35.
Увеличение скорости автомобиля
-
Вставьте
вызов функции LocationCar() в конец метода OnFrameUpdate() класса DodgerGame
// Функция обновления кадра, привязанная
// к таймеру повышенной точности
private void OnFrameUpdate()
{
// Извлекаем точное время
elapsedTime = Utility.Timer(DirectXTimer.GetElapsedTime);
// Вычисляем текущую глубину дороги
RoadDepth0 += RoadSpeed * elapsedTime;
RoadDepth1 += RoadSpeed * elapsedTime;
// Проверяем необходимость смены секций дороги
if (RoadDepth0>75.0F)
{
RoadDepth0 = RoadDepth1 - 100.0F;
}
if (RoadDepth1>75.0F)
{
RoadDepth1 = RoadDepth0 - 100.0F;
}
// Вычисление координаты нового положения автомобиля
car.LocationCar(elapsedTime);
}
Листинг
17.36.
Вызов функции вычисления координаты перемещения автомобиля
-
Запустите
приложение и убедитесь, что положение автомобиля управляется
стрелками обеих клавиатур и все закрепленные за клавишами
функциональности выполняются
Добавление препятствий
На данном этапе мы создали движущуюся дорогу и управляемый автомобиль (хоть управление и примитивное, но поучительное с точки зрения кода). У нас получился автомобильный симулятор - создается полное ощущение движения автомобиля. Теперь мы создадим препятствия, которые пользователь нашей игры должен объезжать. Ранее мы предусмотрели в параметризованном конструкторе автомобиля создание сферы, чтобы можно было контролировать моменты столкновения автомобиля с препятствиями при неудачном их объезде. Весь код создания препятствий упакуем в новом классе с именем Obstacle (препятствия).

