Программирование 3D-игр в DirectX на Delphi
 
         
    [Главная] [Новости] [Статьи] [Игры] [Проекты] [Автор]  
         
  Основы 3D-программирования DirectX8.1 в Delphi 6-7: теоретические и практические основы создания игр.  
     
 
Вывод Заставки
 
     
  Продолжаем серию уроков, посвященных разработке Delphi DirectX игры. В данном уроке показано как вывести 2D-изображение на поверхность 3D-сцены. Дополнительно показан один из способов "затухания" экрана для эффектного вывода фирменной заставки.  
     
  [Все уроки]  
     
  Урок построен в форме упражнений. В упражнениях даются примеры модификаций исходного кода и краткое описание того, что при этом наблюдается и как это объясняется. Выполняя упражнения Вы лучше вникнете в суть проблемы.  
       
  ПОСТАНОВКА ЗАДАЧИ: Требуется организовать вывод 2D-изображения (текстуры) в 3-х мерной сцене. В чём суть проблемы? Суть в том, что при программировании Direct3D для вывода 2D-изображений отсутствуют специальные методы. Как это организовать - решаем вместе.  
     
 

Для выполнения упражнений Вам понадобится:

- архив с исходным кодом; (588 Кб)

- архив с ОБЩИМ КОДОМ; (772 Кб)

Архив с исходным кодом содержит пример решения поставленной задачи, архив с общим кодом - содержит дополнительный общий код необходимый при разработке Delphi DirectX 8.1 - приложений.  
     
 

Для начала откомпилируйте пример и запустите приложение. Убедитесь, что всё работает. (Если нет, то читайте файлы readme.txt приложенные к архивам)

 
     
 

Нормально работающий пример (см. файл game_gui.exe внутри архива game_gui.rar) должен давать следующий результат: создание нормального Windows-окна, постепенное проявление на экране заставки, выдерживание ее некоторое время, затухание, вывод некототорой 3D-сцены (поверхность суши). Выход из приложения - [Escape].

 
     
 

Рассмотрим содержание примера с исходным кодом (game_gui.dpr).

Приложение построено на принципах стандартного WinAPI-приложения. Для лучшего уяснения того, что это такое обратитесь к предыдущим урокам. Хорошим стартом в понимании разработки Delphi DirectX - игр является также пример игры - Donuts3D.

 
     
  Класс приложения - TD3DGameApp. Название класса чисто условное и его легко изменить в своих приложениях. Если Вы заглянете в исходный код (файл Main.pas проекта game_gui.dpr), то увидите что данный класс производится от TD3DAbstractApp. Основа данного класса приложения - из Donuts3D с небольшими изменениями.  
     
 

Лучше уяснить структуру и функционирование данного класса можно рассмотрев пример Donuts3D. В контексте данного урока важны следующие опорные моменты:

SplashGameGUI: TD3DImage2D; //внутри класса объявлено следующее поле

В методе TD3DGameApp.DrawScreenSplash помимо прочего вызывается метод -

SplashGameGUI.DrawScaled(-1.05, 0.55, 0.9, 1.34, 1.34, DrawD3DImage2D_Filtered, Alpha);

Это и есть вывод заставки на экран.

 
     
  Как видим, для вывода 2D-изображения в 3D-сцене используется класс TD3DImage2D. Реализация этого класса находится в модуле D3DGUI.pas. Этот модуль и этот класс могут послужить Вам примером того, как разработать новые классы для выполнения необходимых действий по подготовке игрового процесса. Ссылка на D3DGUI добавлена в uses модуля Main.pas  
     
  Вообще говоря, вывод 2D-изображения в 3D-сцене можно осуществить так, как это делается при выводе 2D-спрайтов (см. Donuts3D). Но тогда обязательно требуется использование камеры (CD3DCamera). Это не составляет никакой проблемы, как раз наоборот, рядом с игровым меню, на заднем плане, может отрисовываться какая-либо анимированная демонстрационная сцена игры, что даже улучшит внешний вид игрового экрана меню. Однако при этом нужно не забывать про то, что методы вывода 2D-изображения методом 2D-спрайтов (технология, известная под названием Billboarding) должны вызываться там же, где используется камера. В противном случае Вы будете ломать голову почему всё написано правильно, а 2D-изображения так и нет в сцене.  
     
 

Обратите внимание на код внутри методов TD3DGameApp.DrawScreenSplash и TD3DGameApp.DrawDisplayList

Оба они содержат вызов метода Draw2DPictures;

Однако результат появляется только в методе TD3DGameApp.DrawDisplayList. Почему?

Именно по указанной причине: в методе TD3DGameApp.DrawScreenSplash нет установки вида из камеры (CD3DCamera.SetViewParams). В методе DrawDisplayList установка вида из камеры происходит в методе UpdateDisplayList, который вызывается из FrameMove. FrameMove вызывается в методе Run до метода Render. А уже Render содержит соответствующий вызов TD3DGameApp.DrawDisplayList.

Если Вам не совсем понятно что к чему, обратитесь к схеме Структура функционирования типового DirectX-приложения, а также к исходному коду.

 
     
  В модуле D3DGUI.pas применяется более изящное решение. Если Вы хоть немного разбирались с Delphi DirectX, то наверное уже задавались вопросом каким образом осуществляется вывод текста. Для этого служит типовой модуль D3DFont.pas (представляющий собой адаптацию D3DFont.h + D3DFont.cpp из DirectX SKD). Там вы найдете класс CD3DFont. Внимательно посмотрев на реализацию методов DrawText и DrawTextScaled Вы найдете ответ на вопрос.  
     
  В модуле D3DGUI.pas как раз и применяется данное решение, т.е. вывод 2D-изображения осуществляется практически аналогично выводу текста классом CD3DFont. Есть конечно и некоторые отличия, но их Вы найдете в D3DGUI.pas  
     
  Расскажем теперь о правилах использования класса TD3DImage2D (эти правила касаются использования любых Direct3D8-производных объектов сцены - т.е. всего того, что будет отрисовываться на экране через D3D или помогать этому процессу - моделей, текстур, эффектов (шейдеры) и т.п.).  
     
 

- внутри класса приложения или в виде отдельной переменной объявить поле с данным типом -

Some2DImage: TD3DImage2D;

- в методе создания приложения создать экземпляр класса


Some2DImage := TD3DImage2D.Create(TextureFormat); // TextureFormat = формат
// изображения, например
// D3DFMT_A8R8G8B8


- в методе инициализации 3D-сцены приложения (InitDeviceObjects, CreateDeviceObjects)
вызвать метод инициализации экземпляра класса


Some2DImage.InitDeviceObjects(pd3dDevice, TextureFilename);
// TextureFilename - путь и имя файла текстуры изображения

- в методе RestoreDeviceObjects приложения вызвать метод


Some2DImage.RestoreDeviceObjects;

- в методе InvalidateDeviceObjects приложения

Some2DImage.InvalidateDeviceObjects;

- в методе DestroyDeviceObjects приложения
SAFE_DELETE(Some2DImage);

============================================================

Для задания ключевого (прозрачного) цвета служит свойство
ColorKey (read/write)

Some2DImage.ColorKey := $00000000;

Для хранения имени и пути загруженного файла текстуры свойство-
TexFilename (read only)

SomeFilename := Some2DImage.TexFilename;


В методах отрисовки 3D-сцены приложения используются методы отрисовки 2D-изображения в 3D-сцене

Some2DImage.Draw(x, y, Flags, Alpha);Some2DImage.Draw(x, y, Flags, Alpha);Some2DImage.Draw(x, y, Flags, Alpha);
// x, y - координаты (в пикселях) на экране; Flags - дополнительные
// опции отрисовки (DrawD3DImage2D_Filtered - задает линейную фильтрацию при выводе)
// Alpha (0..255) - полупрозрачность изображения - от прозрачного (0) до
// полностью непрозрачного (255).

 

Some2DImage.DrawScaled(x, y, z: Single; fXScale, fYScale: Single;
Flags: Cardinal; Alpha: Byte)

// то же, что и предыдущий метод, но x, y, z - не в пикселях, а в координатной системе Viewport (-1..+1). fXScale, fYScale задают масштаб в долях от окна Viewport (1 - во весь Viewport, 0.5 - в 1/2 от Viewport и т.д.). Такая система задания масштаба удобна тем, что не зависит от размеров окна 3D-сцены. Размеры окна в пикселях могут быть любые. Параметры Flags и Alpha - те же, что и в предыдущем методе.

 

 
     
  Чтобы лучше уяснить себе использование данного класса переходим к упражнениям.  
     
 

В методе TD3DGameApp.DrawScreenSplash происходит вывод заставки -

SplashGameGUI.DrawScaled(-1.05, 0.55, 0.9, 1.34, 1.34, DrawD3DImage2D_Filtered, Alpha);

Попробуйте в качестве флага указать 0, т.е. -

SplashGameGUI.DrawScaled(-1.05, 0.55, 0.9, 1.34, 1.34, 0, Alpha);

Результатом будет вывод более четкого, но без плавного перехода (antialiasing) по краям изображения.

Замечание: после внесения изменений в код не забывайте перекомпилировать приложение, а уж после запускать и смотреть что получилось!

 
     
 

Каким образом реализуется плавное появление, а затем затухание для заставки?

Сначала попробуйте изменить строчку -

SplashGameGUI.DrawScaled(-1.05, 0.55, 0.9, 1.34, 1.34, DrawD3DImage2D_Filtered, Alpha);

вместо Alpha введите 255 -

SplashGameGUI.DrawScaled(-1.05, 0.55, 0.9, 1.34, 1.34, DrawD3DImage2D_Filtered, 255);

указанная особенность вывода заставки пропала. Заставка просто отображается в течении 9 секунд (SplashDelay).

Выше данной строки расположен следующий код -

Period := SplashDelay/3;
Phase := D3DX_PI/2*DXUtil_Timer(TIMER_GETAPPTIME)/Period;

if DXUtil_Timer(TIMER_GETAPPTIME) < Period then
Alpha := 255 - Round(Abs(255*(cos(Phase))));
if (DXUtil_Timer(TIMER_GETAPPTIME) > Period) and (DXUtil_Timer(TIMER_GETAPPTIME) < 2*Period) then
Alpha := 255;
if DXUtil_Timer(TIMER_GETAPPTIME) > 2*Period then
Alpha := 255 - Round(Abs(255*(sin(Phase))));

 
     
  Как вы уже наверное догадались проявление и затухание заставки организовано за счет изменения значения Alpha - полупрозрачности полигона, на котором рисуется текстура заставки.  
     
  Прокомментируем указанные строки. Все время отображения заставки (SplashDelay) делится на 3 части и называется период. Момент изменения (фаза) вычисляется по указанной формуле.  
     
  Далее всё еще проще - за промежуток времени меньше, чем Период значение Alpha изменяется по косинусоидальной кривой, т.е. от 0 до 255 (см. формулу).  
     
  За промежуток времени от Период до 2 Периода значение Alpha остается постоянным. И, наконец, в промежуток времени от 2 Периодов до SplashDelay значение Alpha изменяется по синусоиде - от 255 до 0.  
     
  Т.к. во время показа заставки никаких полезных действий не производится, то в дальнейшем цикле разработки игрового проекта, можно использовать эту стадию начала работы игры для параллельного выполнения каких-либо полезных, но скрытых от пользователя действий: загрузка игровых моделей, подготовка сцены и т.п.  
     
 

Это было лишь краткое знакомство с выводом титульной фирменной заставки. Для лучшего уяснения данного материала нужно обязательно написать собственное приложение и тщательно проработать все показанные особенности.

Для разработки действительного игрового проекта дополнительно потребуется решение следующих вопросов:

- создание и использование анимированных 2D-изображений для вывода меню и анимированных заставок (это касается расширения возможностей класса TD3DImage2D);

- создание и использование игрового меню;

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

 
     
  [Назад] [Все уроки]  
     
    [Главная] [Новости] [Статьи] [Игры]    
         
(c) Мега Информатик 2006-2007    
Hosted by uCoz