Мобильная версия сайта | |||||||||
[Главная] | [Новости] | [Статьи] |
[Проекты] |
[Ссылки] |
[Автор] |
||||
[Архив новостей] | |||||||||
[Форум] | на форуме можно задать вопрос, посмотреть ответы на часто задаваемые вопросы | ||||||||
Здравствуйте! Вы попали на информационно-образовательный сайт посвященный информатике, информационным технологиям и компьютерным играм. Подробнее о целях и задачах сайта в разделе Главная. [English version of this page here...] | |||||||||
[Базовые уроки по DirectX] [Основы DirectMusic на Delphi] [Основы DirectInput8 на Delphi] [Основы DirectSound8 на Delphi] | |||||||||
[Разработка компьютерной игры] [Пример игры Donuts3D] [Delphi DirectX] | |||||||||
Эмулятор электронной игры Электроника ИМ-02 "Ну, Погоди!" | |||||||||
скачайте полную версию игры, зарегистрируйтесь и получите бесплатно полный исходный код игры для компиляции в delphi 7 или 2006 и уроки delphi directx 8.1 содержащие статьи по созданию собственной 2D/3D игры в среде delphi directx | |||||||||
Урок 4 Построение класса приложения | |||||||||
О том, что потребуется для данного урока читайте в основном разделе - уроки delphi directx 8.1 | |||||||||
Далее у читателя подразумевается наличие базовых знаний языка Delphi. | |||||||||
[назад] [страница 2] [далее] [к содержанию] | |||||||||
Познакомившись с кодом класса CD3DApplication описанным в модуле D3DApp.pas библиотеки delphi directx 8.1 мы переходим к рассмотрению класса TD3DGameApp являющегося базовым классом D3D-приложения, используемым в игре "Ну, Погоди!". По большому счету ничего нового о функционировании D3D-приложения Вы здесь не узнаете, однако в качестве примера того, как строится конкретный базовый класс на примере конкретной законченной игры дальнейшее повествование будет Вам все же небезынтиресно. | |||||||||
Начнём с того, что модуль D3DApp.pas и CD3DApplication в игре "Ну, Погоди!" не применяется вообще. Вместо этого был создан самостоятельный базовый класс ориентированный именно на потребности конкретной игры, а не на те особенности, которые необходимо было рассмотреть в качестве примера во всех приложениях из DirectX SDK. Иными словами назначение класса CD3DApplication именно демонстративное. Класс TD3DGameApp, который мы рассмотрим ниже, ориентирован на определенную конкретику, связанную с особенностями проекта игры "Ну, Погоди!" |
|||||||||
Функционирование приложения строится на тех же принципах, которые мы рассматривали начиная с 1 урока. | |||||||||
Однако заглянув в исходный код игры Вы обнаружите очень много деталей, которые отсутствовали в примерах, которые мы рассматривали до этого. В классе присутствуют очень много различных полей и методов, несущих конкретную смысловую нагрузку и связанных с реализацией этой игры, кроме того, здесь реализован вывод звука средствами DirectSound8. |
|||||||||
Что потребуется при написании собственной игры? Сначала я перечислю то, что потребуется обязательно при реализации абсолютно любой игры - счетчик текущего времени, списки текстур, моделей, звуков, музыкальных, текстовых файлов, индикаторы различных состояний и режимов приложения и игры, объект управления игрой посредством DirectInput, списки действий по управлению игрой объявленных в виде констант, клавиши сопоставленные каждому игровому действию. Остальные поля и методы, дополнительные классы и классы необходимых игровых объектов зависят от конкретной специфики Вашей игры, а также фантазии и опыта разработки. Самое главное - это то, что код должен быть таким, чтобы Вы могли свободно понимать его не только пока делаете игру, но и позднее, по прошествии некоторого количества времени, т.е. код должен быть понятен и легко читаем. Комментарии к коду также должны быть кратки, исчерпывающи и понятны. Это означает, что код сам по себе является описанием того, что происходит и по большому счету в комментариях не нуждается. Однако комментарии должны дополнять и пояснять не совсем ясные участки. Важно также выбирать для идентификаторов такие названия, которые бы как-то намекали на то, для чего используется данный идентификатор. Об этом Вы конечно же уже должны знать если имеете хоть какой-то, даже небольшой опыт программирования. |
|||||||||
Теперь рассмотрим конкретные примеры того, что имеет место в коде игры "Ну, Погоди!". Замечу, что всё описанное ни в коем случае не является и не должно являться для Вас догмой. Поработав с примером и над созданием собственной игры Вы обязательно уясните для себя что-то свое и будете делать то, что Вам потребуется по-своему, а не так как описано здесь один в один. Другими словами по мере приобретения Вами опыта Вы сами решите что и как должно происходить в Вашем коде. | |||||||||
Опустим описание реализации кода методов TD3DGameApp.Create, Create_ и Destroy, так как оно за небольшими исключениями полностью похоже на то, что мы рассматривали на протяжении предыдущих 3х уроков. Рассмотрим метод TD3DGameApp.OneTimeSceneInit Внутри данного метода я обычно создаю объекты DirectInput и DirectSound, выполняю первоначальную инициализацию D3D-приложения, вызываю функцию рандомизации рандомизатора и перевожу приложение в состояние начальной инициализации ресурсов. |
|||||||||
Далее действие происходит уже внутри FrameMove и Render. В зависимости от состояния приложения происходит загрузка необходимого минимума ресурсов, начинается опрос действий со стороны пользователя посредством DirectInput. Реакция на события выбора меню TMainMenu реализована вызовом обработчиков пунктов данных меню. Наконец, когда пользователь запустил игру приложение переходит в состояние игры и выполняется игровой процесс. |
|||||||||
Как происходит осуществление игрового процесса? Основные составляющие его это - анимация, вывод графики и рассчет игровой логики. Пользователь реагирует на те или иные игровые ситуации выполняя игровые действия, в соответствии с этим меняется и игровой процесс. | |||||||||
Приложение построено таким образом, что после выполнения OneTimeSceneInit запускается непрерывный процесс выполнения метода TMainForm.ApplicationEventsIdle. Этот метод вызывается всегда, когда приложение находится в состоянии бездействия, а поскольку кроме данного метода приложение больше не выполняет никакую работу (помимо отрисовки и рассчетов игровой логики, выполняемых именно внутри данного метода), то всё процессорное время выделенное приложению уходит именно на выполнение данного метода. Внутри данного метода исполняется g_d3dApp.Render3DEnvironment; в котором и реализовано выполнение упомянутых выше методов FrameMove и Render. Если заглянуть в код этих методов, то Вы увидите, что действия которые там выполняются зависят от состояния, в котором находится приложение. asBeginInit - в этом состоянии которое приложение принимает после успешного старта, происходит загрузка текстур и восстановление зависимых от устройства параметов ресурсов (в данном случае моделей полигонов, на поверхности которых происходит отображение нужных текстур); После успешного выполнения данной операции состояние переходит в asInit. Это необходимо, чтобы обеспечить лишь однократную загрузку текстур (вспомним, что метод Render3DEnvironment вызывается периодически). В состоянии asInit происходит лишь смена состояния на новое asEndInit, которое сразу же переключит приложение в состояние готовности - asReady Такие сложности связаны именно с периодической природой Render3DEnvironment, поэтому ОБЯЗАТЕЛЬНО! учитывайте этот момент, иначе будете получать всевозможные ошибки времени выполнения. В состоянии asReady начинается ожидание действий со стороны пользователя (UpdateInput). Назначение клавиш каждому из действий происходит в процедуре DefineDefaultKeys. Обработка этих действий происходит в режимах готовности (asReady) и игры (asGame). Режим паузы в ответ на действие GamePause переключает индикатор паузы m_bPaused на противоположное значение. В коде формирования игровой ситуации FrameMoveGameSituation учитывается состояние данного индикатора. Также проверяется нажатие клавишы выхода из игры - действие GameExit. Нажатие нарисованных на игровой панели клавиш при помощи мыши обрабатывается здесь следующим образом. Если выполняется действие PressButton, то определяются в каком месте находится при этом указатель мыши. Попадание его в определенную область вызывает срабатывание нужной кнопки на игровой панели. GameButtonDownUp применяется для корректной отработки нажатий/отпусканий клавиш игровой панели. В момент отпускания клавиши игровой панели срабатывает привязанное к ней действие. Кроме того, красным клавишам управления волком сопоставлены действия от клавиатуры LeftUpCatch, LeftDownCatch, RightUpCatch, RightDownCatch, т. к. по мере нарастания скорости игры требуется более высокая реакция игрока.
|
|||||||||
В состоянии asGame выполняется метод FrameMoveGameScene. Заглянув в его код Вы увидите несколько различных режимов, в которых может находиться игра:
gmRestart, gmGameA, gmGameB, gmTimer, gmSetAlarm, gmEndSetAlarm, gmStartGameOver,
gmGameOver, gmStartLoadWinMultic, gmShowWinText, gmWinMultic, gmShowGameAMaxScore,
|
|||||||||
Перечислим их назначение. gmRestart - этот режим выполняет перезапуск игры независимо от текущего режима и переход в состояние готовности. Этот режим эмулирует поведение электронной игры "Ну, Погоди!" сразу же после ее включения. gmGameA - запускает игру А, при этом яйца скатываются одновременно только с 3х лотков, прервать игру можно путем рестарта, паузы или закрытия приложения gmGameB - аналогично, но яйца катятся с 4х лотков gmTimer - эмуляция поведения электронной игры "Ну, Погоди!" в режиме отсчета времени. Отображается реальное время системных часов аналогичное тому, что имеется в правом нижнем углу экрана Windwows (в трее). gmSetAlarm, gmEndSetAlarm - эмуляция режима установки времени подачи сигнала будильника, при этом если игра запущена, то в режимах "игра А", "игра Б" или отсчет времени в заданное время будет подан сигнал будильника gmStartGameOver, gmGameOver - проигрыш, игра находится в состоянии ожидания дальнейших действий пользователя gmStartLoadWinMultic, gmShowWinText, gmWinMultic - победа! игрок набрал трижды 999 очков. при этом будет показан поздравительный текст, а затем небольшой анимированный мультфильм с участием волка, зайца и других персонажей gmShowGameAMaxScore,
gmShowGameBMaxScore -
режим показа максимального набранного в данном режиме количества очков
- срабатывает в момент нажатия и удержания клавиш "игра А" или
"игра Б" на игровой панели |
|||||||||
Вам наверное интересно как осуществляется отображение графики в игре? Начнём с того, что заглянем внутрь методов LoadGameTextures, RestoreGameTextures, InvalidateGameTextures, FreeGameTextures. В этих методах показано, как имена текстур из текстового файла загружаются сначала в список имен, а затем по этому списку производится загрузка и построение списка текстур (объектов класса TD3DImage2D). Из списка имен также считываются параметры размещения и масштабирования изображений. В режиме игры А или Б сначала происходит вызов FrameMoveGameSituation; В реализации данного метода присутствуют несколько важных и интересных моментов. Исходя из названия данный метод отвечает за формирование игровой ситуации. 1) Если индикатор паузы переключен в True, то DXTimer сбрасывается, а метод завершает работу; 2) Формируется набор нескольких положений волка. Это необходимо при больших скоростях игры, чтобы игрок успел поймать яйца катящиеся сразу с нескольких лотков, в противном случае игра становится непроходимой. 3) Определяется текущее положение волка 4) Генерируются новые яйца на лотках, анимируется их качение по лоткам, анимируется выглядывание зайца из окошка, постепенно наращивается темп игры 5) Проверяется и анимируется разбивание яиц 6) Осуществляется мерцание и сброс (если требуется) штрафных очков Вывод графики происходит внутри метода Render также в зависимости от состояния приложения. DrawGameView > DrawGameScene осуществляет собственно рисование в зависимости от режима игры. Внутри DrawGameScene вы увидите, что проблема вывода каждого игрового изображения сводится к вызову метода DrawGameElement с указанием в качестве параметра индекса отображаемого элемента (игровой панели, волка, зайца, яйца и т.д.). Лишь для игрового счета, счета штрафных очков и показаний времени используются отдельные методы, но и они построены на использовании метода DrawGameElement В реализации метода DrawGameElement нет ничего сложного. В зависимости от индекса вызывается нужный объект TD3DImage2D с вызовом его метода Draw2. Параметры вывода (координаты и масштабные коэффициенты извлекаются из параметров объекта PGamePanelElement). |
|||||||||
Вот собственно и весь вывод графики. Вывод звука осуществляется еще проще. Достаточно Вам посмотреть методы function
CreateSoundObjects(h_Wnd: HWND): HRESULT; и то, где и как происходит их вызов. Можете например воспользоваться поиском по заданной фразе или просто просматривая код. |
|||||||||
Конечно простота реализации данной игры обусловлена в большой степени ее особенностями. Большинство объектов статичны, анимация сводится лишь к скрытию одних и показу других картинок. Логика игры также достаточно проста. | |||||||||
Возможно чуть более сложным Вам покажется использование 2D-анимации, которая применяется в призовом мультфильме. Этот процесс также основан на использовании класса TD3DImage2D. Более подробно о нём мы поговорим в 7 уроке. | |||||||||
Вот кажется и всё вкратце, о создании базового класса игрового приложения, который применялся в игре "Ну, Погоди!". Если есть вопросы - милости просим на форум или пишите на мой e-mail - megainformatic@mail.ru | |||||||||
Но думаю, что особых трудностей не будет. Нужно лишь поэкспериментировать над созданием собственного, пусть пока небольшого, но уже полноценного игрового проекта. Удачи Вам!!! | |||||||||
[назад] [страница 2] [далее] [к содержанию] | |||||||||
по всем вопросам пишите на megainformatic@mail.ru или оставьте сообщение на форуме | |||||||||
Обновления
и новости о развитии Delphi DirectX проекта http://www.megainformaticsite.pochta.ru http://www.megainformatic.boom.ru http://www.megainformatic.narod.ru
|
|||||||||
Cвои пожелания, вопросы или заметки отправляйте на: megainformatic@mail.ru или пишите на форуме |
|||||||||
Обмен ссылками | |||||||||
|
|||||||||
(с) МЕГА ИНФОРМАТИК 2006-2009 | |||||||||