Информатика и образование
  Мобильная версия сайта            
               
[Главная] [Новости]
[Статьи]
[Проекты]
[Ссылки]
[Автор]
               
    [Архив новостей]        
               
  [Форум] на форуме можно задать вопрос, посмотреть ответы на часто задаваемые вопросы  
       
  Здравствуйте! Вы попали на информационно-образовательный сайт посвященный информатике, информационным технологиям и компьютерным играм. Подробнее о целях и задачах сайта в разделе Главная. [English version of this page here...]    
       
  [Базовые уроки по DirectX] [Основы DirectMusic на Delphi] [Основы DirectInput8 на Delphi] [Основы DirectSound8 на Delphi]    
  [Разработка компьютерной игры] [Пример игры Donuts3D] [Delphi DirectX]    
       
  Эмулятор электронной игры Электроника ИМ-02 "Ну, Погоди!"    
       
  триал-версия, 1,34 Mb   скачайте полную версию игры, зарегистрируйтесь и получите бесплатно полный исходный код игры для компиляции в delphi 7 или 2006 и уроки delphi directx 8.1 содержащие статьи по созданию собственной 2D/3D игры в среде delphi directx    
       
  Урок 2 Создаем и обрабатываем команды меню. Реализуем вывод текстуры в рабочую область D3D.    
       
  О том, что потребуется для данного урока читайте в основном разделе - уроки delphi directx 8.1    
       
  Далее у читателя подразумевается наличие базовых знаний языка Delphi.    
       
  [назад] [страница 2] [далее] [к содержанию]    
       
 

В качестве основы мы возьмем исходный код шаблона стартового приложения Delphi DirectX 8.1 (или сокращенной D3D-приложения), который мы создали в предыдущем уроке

Но помните, что для его компиляции Вам нужна и сама библиотека Delphi DirectX 8.1 (папка с общим кодом)

или исходный код игры "Ну, Погоди!" с включенной обновленной библиотекой Delphi DirectX 8.1 (поддержка русских букв, 2D анимация и некоторые другие возможности).

   
       
 

Несколько важных замечаний.

Особенности создания и обработки пунктов меню Опции > Подсказка; Опции > Показ FPS

   
       
  Также мы рассмотрим здесь как выводится изображение текстуры в рабочую область окна D3D-приложения, т.е. как появляется и формируется картинка представляющая экран игры Ну, Погоди!    
       
 

Самым простым по реализации является пункт меню Выход (Exit). Вот реализованный код его обработчика -

procedure TMainForm.ExitGameMenuClick(Sender: TObject);
begin

Close;
end;

Как видим здесь вызывается всего лишь стандартный метод Close. Весь код, выполняющий освобождения ресурсов D3D-приложения будет вызываться автоматически из метода FormDestroy при ее разрушении. Так что Вам нужно лишь правильно реализовать методы внутри FormDestroy, тогда никаких ошибок при закрытии приложения не будет возникать.

   
       
 

При создании и реализации пунктов меню Опции > Подсказка; Опции > Показ FPS нужно учесть следующую особенность.

Для данных пунктов меню нужно установить свойство Checked в true во время их создания.

Для обработки данных пунктов меню применяется следующий обработчик:

procedure TMainForm.ShowFPSOptionItemClick(Sender: TObject);
begin
ShowFPSOptionItem.Checked := not ShowFPSOptionItem.Checked;

if g_d3dApp <> nil then
g_d3dApp.m_bShowFPSOn := ShowFPSOptionItem.Checked;
end;

Первая строка кода переключает пункт меню из включенного/выключенного состояния при его выборе.

Вторая строка проверяет наличие объекта d3d-приложения и устанавливает его свойство отвечающее за показ FPS в заданный режим.

Опции > Подсказка реализуется аналогично.

   
       
       
       
  Теперь рассмотрим как формируется картинка представляющая экран игры.    
       
  Для этого Вам нужно обратиться к ее исходному коду. Вспомним схему функционирования D3D-приложения.    
       
     
       
 

Поскольку метод Render3DEnvironment вызывается периодически, формируя следующий кадр анимации и выводя фактическую картинку в окно D3D, то загрузка необходимых текстур (и других ресурсов) должна происходить однократно, иначе это приведет к зацикливанию и ошибкам.

Следовательно, загрузка необходимых ресурсов должна осуществляться не в цикле отрисовки (Render3DEnvironment), а до него. Это происходит внутри метода FormShow > InitD3DApp.

В реальных играх разные уровни игры могут потребовать различных ресурсов, поэтому прежде чем запустить уровень игры приложение должно перейти в режим загрузки необходимых ресурсов игры (причем сделать это однократно), а после перейти к режиму отрисовки и отслеживания действий пользователя (UpdateInput).

   
       
 

В нашем случае игра достаточно проста, поэтому все ресурсы будут загружаться лишь однажды - во время старта приложения и происходить это будет внутри FormShow > InitD3DApp > g_d3dApp.Create_ > OneTimeSceneInit > CreateDisplayObjects

Внутри показанного метода будет происходить создание объектов D3D и загрузка необходимых ресурсов касающихся формирования изображения - моделей, текстур, шейдеров и т.п.

В коде игры "Ну, Погоди!" это сделано еще более изящным образом: приложение переходит в состояние инициализации asBeginInit и в этом состоянии внутри метода FrameMove происходит вызов методов -

LoadGameTextures;
RestoreGameTextures;

и сразу же переход в состояние
m_dwAppState := asInit;

Это Вы можете сами увидеть в исходном коде игры "Ну, Погоди!".

   
       
 

Суть работы при этом сводится к следующему (попробуйте выполнить поиск фразы asBeginInit с начала исходного файла Main.pas в проекте игры "Ну, Погоди!")

Первое найденное - перечисляемый тип TAppStates

Второе - метод constructor TD3DGameApp.Create; - т.е. начальным состоянием во время старта приложения является именно это (asBeginInit)

Наконец третье - это метод OneTimeSceneInit. Вообщем-то, поскольку данное состояние здесь то же самое, что и в методе TD3DGameApp.Create, то его установку можно и опустить в этом методе. Но если Ваша игра будет состоять из нескольких уровней, требующих различных ресурсов, тогда эти состояния Вам надо будет предусмотреть и выполнить их реализацию. Тогда они будут у Вас различаться. Например, в зависимости от текущего уровня игры, считанного из файла конфигурации игра при старте может загружать ресурсы нужного текущего уровня. Именно поэтому внутри метода OneTimeSceneInit приведена эта строка кода, чтобы обратить Ваше внимание на такой вариант.

Четвертое место где будет найдено asBeginInit - уже упомянутый выше метод FrameMove.

Внутри данного метода Вы можете увидеть какие вообще состояния может иметь игра и что при этом происходит.

   
       
 

Исходя из того, что Вы увидели можно сделать определенные выводы и написать код, необходимый для формирования начальной картинки игры "Ну, Погоди!".

Для этого Вам нужно скопировать папку Media из дистрибутива полной версии игры "Ну, Погоди!" и разместить ее внутри папки Вашего текущего проекта (где расположен exe-файл, создаваемый проектом при его компиляции).

Тогда Вы сможете добавить код выполняющий поставленную задачу, а именно:

нам нужно описать и реализовать методы

LoadGameTextures;
RestoreGameTextures;

DrawGameView;

Вы найдете их в исходном коде игры "Ну, Погоди!" и с легкостью сможете перенести в свой код.

   
       
  Если же Вы немного затрудняетесь в этом, то рассмотрим, что нужно сделать.    
       
 

Рассмотрим сначала простейший случай. Вам нужно загрузить текстуру

back.jpg

из папки Media\textures\

В объект класса TD3DImage2D, а затем использовать методы данного объекта для отображения в окне D3D внутри метода Render > DrawGameView > DrawGameScene > DrawGameElement

Как это реализовано в реальном коде игры "Ну, Погоди!" Вы можете увидеть сами.

Мы же рассмотрим здесь более упрощенный способ не отягощенный излишними деталями, характерными для особенностей реализации реальной игры.

В секции интерфейса объявляем константу с именем файла текстуры

interface

{...}

conts

BackTex = 'Media\textures\back.jpg';

В описание класса TD3DGameApp добавляем поле для объекта TD3DImage2D (данный класс реализован в модуле D3DGUI.pas, который присутствует ТОЛЬКО в исходном коде игры "Ну, Погоди!". В общедоступном архиве библиотеки Delphi DirectX 8.1 этого модуля нет!)

предварительно нужно указать ссылку к папке содержащей данный модуль в опциях проекта, а затем подключить его в пункте uses секции interface

uses

{...}, D3DGUI;

backImage: TD3DImage2D;

и описание методов

procedure LoadGameTextures;
procedure RestoreGameTextures;

procedure InvalidateGameTextures;
procedure FreeGameTextures;

procedure DrawGameScene;

В секции реализации добавляем код для этих методов

implementation

{...}

procedure TD3DGameApp.LoadGameTextures;
var
hr: HResult;
begin
backImage := TD3DImage2D.Create(g_d3dApp.m_d3dfmtTexture);
if backImage = nil then begin
CleanUpAndDisplayError(GAME_ERR_NOTEXTURES);
PostMessage( m_hWndMain, WM_CLOSE, 0, 0 );
Exit;
end;

hr := backImage.InitDeviceObjects(m_pd3dDevice,
backTex);
if Failed(hr) then begin
CleanUpAndDisplayError(GAME_ERR_NOTEXTURES);
PostMessage( m_hWndMain, WM_CLOSE, 0, 0 );
Exit;
end;
end;

procedure TD3DGameApp.RestoreGameTextures;
begin
if backImage <> nil then
backImage.RestoreDeviceObjects;

end;

procedure TD3DGameApp.InvalidateGameTextures;
begin
if backImage <> nil then
backImage.InvalidateDeviceObjects;
end;

procedure TD3DGameApp.FreeGameTextures;
begin
SAFE_DELETE(backImage);
end;

procedure TD3DGameApp.DrawGameScene;
begin
if backImage <> nil then
backImage.Draw2(0, 0, 0, 0.83, 1,
DrawD3DImage2D_Filtered, 255);
end;

   
       
 

А затем останется только расскомментировать или добавить вызов созданных методов внутри -

FrameMove -

function TD3DGameApp.FrameMove: HRESULT;
begin
case m_dwAppState of
asBeginInit: begin
LoadGameTextures;
RestoreGameTextures;
m_dwAppState := asInit;
end;
asInit: m_dwAppState := asEndInit;
asEndInit: m_dwAppState := asReady;

asReady: {UpdateInput};
asGame: {FrameMoveGameScene};
end;

result := S_OK;
end;

и Render > DrawGameView -

procedure TD3DGameApp.DrawGameView;
const
FillColor = $FF58B327;
begin
if not Assigned(m_pd3dDevice) then Exit;

// Begin the scene
if SUCCEEDED(m_pd3dDevice.BeginScene) then
begin
// Erase the screen
m_pd3dDevice.Clear( 0, nil, D3DCLEAR_TARGET or D3DCLEAR_ZBUFFER,
FillColor, 1.0, 0 );

DrawGameScene;


//CountFPS;
// End the scene
m_pd3dDevice.EndScene;
end;


end;

Не забудьте про правильное освобождение созданных ресурсов! - внутри - InvalidateDisplayObjects и DestroyDisplayObjects

function TD3DGameApp.InvalidateDisplayObjects: HRESULT;
begin
result := S_OK;

m_pGameFont.InvalidateDeviceObjects;

InvalidateGameTextures;
end;

function TD3DGameApp.DestroyDisplayObjects: HResult;
begin
FreeGameTextures;

SAFE_DELETE(m_pGameFont);

SAFE_DELETE(m_Camera);

SAFE_RELEASE(m_pd3dDevice);

result := S_OK;
end;

   
       
 

После этого изображение панели игры Ну, Погоди появится в рабочей области окна D3D.

Если оно выводится не целиком, значит Вам нужно увеличить размеры окна формы -

В инспекторе объектов для формы MainForm задайте размеры

MainForm.Width = 637

MainForm.Height = 432

Заметьте, что размеры заданные в для окна формы в инспекторе объектов имеют приоритет перед размерами рабочей области окна заданными внутри TD3DGameApp.Create. Это связано с тем, что рабочую область окна D3D в оконном режиме определяет окно, чей обработчик (Handle) мы передаем объекту DirectD3Device. Таким объектом у нас является панель RenderWindowPanel. Если Вы задавали для неё в инспекторе объектов свойство Align = alClient, то это как раз и объясняет такое поведение приложения.

Получается, что размеры окна формы MainForm определяют размеры панели RenderWindowPanel, а она в свою очередь и служит рабочей областью для вывода D3D-окна.

   
       
  Если D3D-приложение переключается в полноэкранный режим, то рабочая область окна D3D разворачивается во весь экран, а ее размеры определяются не заданными размерами окна, а разрешением, которое будет использоваться D3D-приложением для полноэкранного режима, т.е. - 640х480, 800х600, 1024х768 пиксель или другое доступное разрешение.    
       
  В нашем следующем уроке мы рассмотрим работу D3D-приложения в оконном и полноэкранном режиме. Покажем какой код необходимо написать для этого и какие особенности нужно обязательно учитывать. Несмотря на то, что для игры "Ну, Погоди!" полноэкранный режим не предусмотрен, т.к. она этого не требует из-за своих особенностей - эмуляции экрана электронной игры, тема полноэкранного режима и работы в нём является базовой для всех Delphi DirectX игр, т.к. высокая производительность D3D-приложения достигается именно в этом режиме!    
       
       
       
  [назад] [страница 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
Hosted by uCoz