Опубликован: 13.07.2010 | Уровень: специалист | Доступ: платный
Самостоятельная работа 17:

Программирование простой игры в DirectX

Создание объекта Car в движке игры

Теперь у нас есть класс Car и нужно разместить код создания и использования его экземпляра (объекта) в основном движке игры - классе DodgerGame.

  • Поместите в секцию #region переменных класса DodgerGame ссылку на объект класса Car
#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
  • Постройте приложение и убедитесь, что появился неподвижный относительно сцены автомобиль на движущейся дороге, прижатый к ее левой стороне

Клавиатурное управление автомобилем

Применим для управления горизонтальными перемещениями автомобиля клавиатурные стрелки, причем продублируем коды стрелок на основной и дополнительной клавиатуре. Для остановки автомобиля предусмотрим клавишу \downarrow на обоих клавиатурах.

  • В классе 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 (препятствия).

Иван Циферблат
Иван Циферблат
Россия, Таганрог, 36, 2000