Китай |
Программирование простой игры в 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 (препятствия).