Мобильная версия сайта | |||||||||
[Главная] | [Новости] | [Статьи] |
[Проекты] |
[Ссылки] |
[Автор] |
||||
[Архив новостей] | |||||||||
[Форум] | на форуме можно задать вопрос, посмотреть ответы на часто задаваемые вопросы | ||||||||
Здравствуйте! Вы попали на информационно-образовательный сайт посвященный информатике, информационным технологиям и компьютерным играм. Подробнее о целях и задачах сайта в разделе Главная. [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 | |||||||||
Урок 3 Оконный и полноэкранный режимы работы D3D-приложения | |||||||||
О том, что потребуется для данного урока читайте в основном разделе - уроки delphi directx 8.1 | |||||||||
Далее у читателя подразумевается наличие базовых знаний языка Delphi. | |||||||||
[назад] [страница 2] [далее] [к содержанию] | |||||||||
Опираясь на код приложения, который Вы создали в предыдущем уроке рассмотрим особенности, которые Вам нужно учесть при реализации работы в оконном/полноэкранном режимах | |||||||||
В первую очередь для проверки правильности созданного кода управления от DirectInput попробуйте добавить показ/отключение показа FPS. Для этого Вам нужно заглянуть в исходный код игры "Ну, Погоди!" и реализовать работу методов CountFPS, ShowFPS | |||||||||
Обратите внимание, что код метода TD3DGameApp.CreateInputObjects должен выглядеть следующим образом - procedure
TD3DGameApp.CreateInputObjects; В качестве действия ShowFPSTrigger внутри DefineDefaultKeys нужно задать какую-либо клавишу. вызов метода ShowFPS нужно добавить внутри UpdateInput |
|||||||||
Теперь переходим непосредственно к рассмотрению особенностей переключения между оконным/полноэкранным режимами. | |||||||||
Индикатор активности приложения m_bIsActive устанавливается в методе TD3DGameApp.MsgProc при получении системного сообщения WM_ACTIVATEAPP m_bIsActive := BOOL(wParam); |
|||||||||
Однако если Ваше приложение основано на классе TForm и использует для старта класс TApplication (как это имеет место в нашем случае), то данный метод (MsgProc) не получает данного сообщения в момент активации. Вместо этого активацию нужно выполнить реализовав для класса TForm обработчики событий OnActivate и OnDeactivate- procedure
TMainForm.FormActivate(Sender: TObject); procedure
TMainForm.FormDeactivate(Sender: TObject); |
|||||||||
При реализации переключения в полноэкранный режим могут возникнуть некоторые сложности. Мы возьмем за основу пример SwitchScreenModesInVCL, рассмотрим его особенности и попробуем внедрить их в другой пример - FullscreenMode, основанный на коде из предыдущих уроков. |
|||||||||
Прежде всего отметим, что код примера SwitchScreenModesInVCL основывается на примере VCLTex из Delphi DirectX SDK Алексея Баркового (http://www.clootie.ru). Особенности касающиеся работы с текстурами удалены, внимание уделено лишь переключениям режимов Полноэкранный/Оконный в приложении на основе VCL и особенностям использования DX8_DIUtil8.pas (модуль для работы с DirectInput8 из Delphi) с классом CD3DApplication. | |||||||||
Как и в наших предыдущих уроках код приложения построен на основании двух классов. Первый класс производный от - TForm из VCL, второй подобен TD3DGameApp, но происходит от CD3DApplication из модуля D3DApp.pas библиотеки с общим кодом. | |||||||||
Схема работы приложения аналогичная, тому, что имело место в предыдущих уроках. Однако есть ряд особенностей, которые нужно учесть при переносе кода в пример FullscreenMode. Какие же? |
|||||||||
Прежде всего, если Вы заглянете в код SwitchScreenModesInVCL внутри модуля SwitchModesUnit.pas, то обнаружите новый класс - TAbstractApp. Этот класс используется как переходное звено между классом приложения CD3DApplication не являющимся TForm и объектом TDXInput, требующим для своего использования именно такого класса. Происходит всё довольно просто. Внутри класса CMyD3DApplication производного от CD3DApplication объявляется поле соответствующего типа, а в методе OneTimeSceneInit вызывается создание данного поля и задание для него указателя на обработчик окна данного класса. Код внутри самого класса выполняет запоминание ссылки на оконную процедуру класса, а сама она выполняет не что иное, как вызов метода MsgProc класса CMyD3DApplication. Используя объект FAbstractApp при создании объекта TDXInput достигается требуемый эффект. Класс TDXInput извлекает нужные ему параметры из объекта FAbstractApp, а приложение работает как ни в чем не бывало. Если Вы посмотрите на код примеров из предыдущих уроков, то там класс TD3DAbstractApp является базовым для класса TD3DGameApp. Такие сложности были связаны с тем, что модуль DX8_DIUtil8.pas был разработан на основе аналогичного кода из библиотеки DelphiX. Эта библиотека хоть и уже несколько устарела, послужила основой для данного модуля, поскольку не удалось разрешить некоторые проблемы, связанные с использованием оригинальных файлов для DirectInput8 из DirectX SDK на C++ при конверсии примеров на Delphi. Получился компромисс. |
|||||||||
Для примера SwitchScreenModesInVCL была выполнена следующая подготовка: класс формы TAppForm, объект g_AppForm. На форме располагаются MainDisplayPanel: TPanel и ToggleFullscreen: TButton; последняя применяется вместо пункта меню TMainMenu переключения режимов (для простоты). |
|||||||||
Код выполняющий собственно переключение оконного/полноэкранного режимов - это обработчик события по нажатию на кнопку ToggleFullscreen Этот же код вызывается при срабатывании действия DirectInput c именем ChangeWindowModeKey и внутри FullScreenWndProc - для переключения в оконный режим по нажатию [Esc]ape |
|||||||||
Этот метод - CD3DApplication.ToggleFullscreen как видим часть класса CD3DApplication и реализован внутри D3DApp.pas |
|||||||||
Внутри данного метода происходят следующие интересные вещи: получаем информацию о адаптере, устройстве и режиме pAdapterInfo
:= @m_Adapters[m_dwAdapter]; используемом для формирования изображения D3D-приложения. Если устройство не поддерживает оконный режим, то остаемся в полноэкранном режиме Переключаем текущее состояние с оконного на полноэкранное (или наоборот) Выполняем настройку для возможного изменения размеров рабочей области окна Выставляем параметры отображения Учитываем изменившиеся размеры окна Располагаем окно в нужной позиции поверх всех остальных |
|||||||||
Это лишь краткое описание того, что на самом деле происходит в коде (подробнее см. сам код примера) | |||||||||
Сравним это с тем, что имеет место в примере FullscreenMode (для Вас он уже есть в готовом виде, в конце данного урока), а пока нужно рассмотреть особенности внутри метода TD3DGameApp.SwitchDisplayModes | |||||||||
здесь информацию об адаптере, устройстве и режиме мы берем из - полей записанных внутри класса TD3DGameApp, а поскольку это только размеры окна, то информация собственно об адаптере, устройстве и режиме на первый взгляд и не требуется Однако дальше видно, что если режим будет полноэкранный, потребуется знать параметры текущего видеорежима, возможно переход в этот режим дает ошибку из-за несоответствия размеров окна? Какой текущий видеорежим использовался во время старта приложения? Это мы можем узнать из метода TD3DGameApp.CreateDisplayObjects |
|||||||||
Здесь видно, что для оконного режима не заданы размеры для m_d3dpp.BackBufferWidth
:= m_dwScreenWidth; в D3DApp.pas (CD3DApplication.Initialize3DEnvironment) они задаются, как задается и m_d3dpp.hDeviceWindow := m_hWnd; причем как для оконного, так и для полноэкранного |
|||||||||
аналогично поступим и в нашем примере возвращаемся к методу TD3DGameApp.SwitchDisplayModes ошибка происходит в методе m_pd3dDevice.Reset( m_d3dpp ); и ясно почему - не учитывается обработчик окна для оконного и полноэкранного режимов, а также заданные размеры окна в этих режимах. Как это происходит в примере SwitchScreenModesInVCL ? TAppForm.FormShow fMyApp.m_hWnd
:= m_hwndRenderWindow; Далее можно просмотреть где в коде CD3DApplication встречаются вхождения на m_hWnd и m_hWndFocus |
|||||||||
Также интерес вызывает параллельный вопрос: если m_hWnd и m_hWndFocus разные обработчики, а при создании TDXInput указывается лишь один из них, то как это скажется на работе устройств DirectInput? |
|||||||||
Итак, что мы имеем в коде SwitchScreenModesInVCL ? TAppForm.FormShow > CMyD3DApplication.Create - всё предельно просто и ясно. для полноэкранного режима создается отдельное окно - m_hwndRenderFullScreen fMyApp.m_hWnd := m_hwndRenderWindow; |
|||||||||
CD3DApplication.Create_ > BuildDeviceList - сбор данных о дисплейном адаптере и установка режима 640х480 16 бит т. к. m_hWnd уже <> 0, то в качестве окна используется fMyApp.m_hWnd := m_hwndRenderWindow; (см. TAppForm.FormShow) |
|||||||||
FOldWndProc задаем для текущего окна | |||||||||
if
(m_hWndFocus = 0) then окно фокуса также иное |
|||||||||
сохраняем свойства окна, запускаем таймер, инициализируем сцену и 3D-среду (Environment) CD3DApplication.Initialize3DEnvironment - остановимся подробнее также на данном методе здесь мы видим как определяется текущий видеорежим (заданный в BuildDeviceList) проводится настройка изменений размеров настраиваются следующие параметры отображения - будет ли режим оконным m_d3dpp.Windowed := pDeviceInfo^.bWindowed; {...} m_d3dpp.hDeviceWindow := m_hWnd; //независимо от оконный/полноэкранный!!! if
(m_bWindowed) then //размеры
буфера подготовки кадра, его формат устройство создается как //
Create the device |
|||||||||
Пример FullscreenMode (18 Кб) Прежде чем открывать пример из среды Delphi и компилировать Вам понадобится расположить в папке примера файлы D3DX81ab.dll и DXErr81ab.dll (их найдете в дистрибутиве игры "Ну, Погоди!" или в папке с исходным кодом, можно также в архиве с общим кодом) Взять из дистрибутива игры "Ну, Погоди!" папку Media\texures Взять из исходного кода игры "Ну, Погоди!" папку common находящуюся внутри папки projects\2d_games\NuPogodi\source Только после этого пример будет нормально компилироваться и работать!!! Об этом уже неоднократно упоминалось, а также написано внутри readme.txt приложенном к архиву данного примера, но еще раз напоминаю, чтобы не возникало вопросов. |
|||||||||
имеет следующие особенности TMainForm.InitD3DApp - данный метод вызывается при показе формы окна приложения однократно пока g_d3dApp = nil. Внутри него происходит создание объекта g_d3dApp, создание окна для полноэкранного режима Метод TD3DGameApp.Create_ - внутри данного метода лишь задаются размеры окна для структур m_rcWindowBounds и m_rcWindowClient и вызывается метод начальной инициализации сцены Внутри TD3DGameApp.CreateDisplayObjects m_d3dpp.hDeviceWindow := m_hWnd; //указывает на обработчик окна формы приложения но при создании указывается обработчик окна полноэкранного режима hr
:= pD3D.CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, |
|||||||||
TD3DGameApp.SwitchDisplayModes {...} AdjustWindowForChange; //важный метод, если его не использовать (попробуйте закомментировать), то сквозь изображение полноэкранного режима "проблескивают" элементы рабочего стола. m_d3dpp.hDeviceWindow := m_hWnd; //указывает на обработчик окна формы приложения, все сообщения будут посылаться ему даже при полноэкранном режиме m_pd3dDevice.Reset - работает корректно именно при верном использовании обработчиков окон в указателях, особенно важно, что при создании устройства был указан обработчик окна полноэкранного режима (попробуйте заменить на обработчик окна формы с расположенном на нём TPanel, что имеет место в нашем случае и данный метод сразу же будет давать ошибку во время попытки переключения в полноэкранный режим) - приложение просто будет закрываться в связи с ошибкой |
|||||||||
TD3DGameApp.CheckForLostFullscreen - метод ForceWindowed и его реализация опущены для некоторого упрощения кода | |||||||||
FullScreenWndProc - оконная процедура полноэкранного режима, если хотите узнать почему в полноэкранном режиме нет курсора мыши и как его установить - загляните сюда. Здесь же видно по какому сообщению (клавише) осуществляется выход из полноэкранного режима | |||||||||
И еще напоследок ряд замечаний, которые не имеют прямого отношения к теме данного урока, но будут всё же интересны TD3DGameApp.DrawGameView метод //
Erase the screen вызывается вне BeginScene ... EndScene влияет ли это на производительность? |
|||||||||
При попытке использовать код, выводящий изображение текстуры в примере SwitchScreenModes по аналогии с примером FullscreenMode не удается добиться такого же вида текстуры в рабочем окне, как в примере FullscreenMode. Почему?
|
|||||||||
Вот и сам пример SwitchScreenModes. (13 Кб) Если Вы всё поняли и во всём разобрались, а также нашли ответы на поставленные 2 вопроса, значит данную тему можно считать усвоенной и двигаться дальше. |
|||||||||
[ответы на поставленные вопросы] - для самопроверки | |||||||||
[назад] [страница 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 | |||||||||