KnigaRead.com/

Михаил Краснов - Графика DirectX в Delphi

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Михаил Краснов, "Графика DirectX в Delphi" бесплатно, без регистрации.
Перейти на страницу:

hRet := FDD.CreateSurface(ddsd, FDDSWork, nil);

if Failed(hRet) then ErrorOut(hRet, 'Create Surface');

// Цветовой ключ для вспомогательной поверхности

hRet := DDSetColorKey (FDDSWork, RGB(0, 0, 0));

if Failed (hRet) then ErrorOut(hRet, 'DDSetColorKey');

При воспроизведении кадра работаем непосредственно с элементами вспомогательного массива:


function TfrmDD.UpdateFrame : HRESULT;

var

i : Integer; hRet : HRESULT;

begin

ThisTickCount := GetTickCount;

if ThisTickCount - LastTickCount > 10 then begin

Angle := Angle +0.05; // Сдвиг синусоиды

if Angle > 2 * Pi then Angle := Angle - 2 * Pi;

LastTickCount := GetTickCount;

end;


// Воспроизводим картинку фона

hRet := FDDSBack.BltFast (0, 0, FDDSBackGround, nil, DDBLTFAST WAIT);

if Failed(hRet) then begin

hRet := RestoreAll;

if Failed (hRet) then begin

Result := hRet;

Exit;

end;


end;


// Обнуляем элементы массива

ZeroMemory (@FrameBuffer, SizeOf (FrameBuffer));

// Заполняем массив для получения синусоиды

for i := 0 to 99 do

FrameBuffer [50 - trunc (sin (Angle + i * 2 * Pi / 100) * 25), i] :=

120;

// Воспроизводим поверхность синусоиды

hRet := FDDSBack.BltFast (0, 0, FDDSWork, nil,

DDBLTFAST_WAIT or DDBLTFAST_SRCCOLORKEY);

if Failed(hRet) then begin hRet := RestoreAll;

if Failed (hRet) then begin

Result := hRet;

Exit;

end;


end;


Result := DD__OK;

end;


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

Проект каталога ЕхЗЗ принципиально ничем не отличается от предыдущего, только используется 16-битный режим, а синусоида выводится на весь экран. Здесь вам надо обратить внимание на изменения в описании массива:


FrameBuffer : Array [0..479, 0..639] of WORD;

Значение ipitch для 16-битной поверхности задаем 640x2 пикселов, как ширина поверхности, умноженная на размер одной ячейки. Синусоида располагается на всем экране, и поверхность фона теперь отсутствует. Для простоты подготовки синусоиду рисуем синим цветом:


// Очистка фона, она же - очистка экрана

ZeroMemory (@FrameBuffer, SizeOf (FrameBuffer));

for i := 0 to 639 do

FrameBuffer [240 - trunc (sin (Angle + i * 2 * Pi / 640) * 100), i] :=

255; // Для синего цвета достаточно поместить в ячейку 255

Result := FDDSBack.BltFast (О, О, FDDSWork, nil, DDBLTFAST WAIT);

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

Отдельный образ загружается из растра, при воспроизведении кадра он копируется на экране 640 раз:


for i := 0 to 639 do begin

hRet := FDDSBack.BltFast (i, 240 -

trunc (sin (Angle + i * 2 * Pi / 640) * 100),

FDDSImage, nil, DDBLTFAST_WAIT or DDBLTFAST_SRCCOLORKEY);

if Failed (hRet) then begin

Result := hRet;

Exit;

end;


end;


Что вы узнали в этой главе

Мы выяснили, что для задания прозрачности участков поверхности используется механизм цветового ключа.

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

Глава 4 Спрайтовая анимация


Спрайты

Хранитель экрана

Проверка столкновений

Спрайты и оконный режим

Что вы узнали в этой главе


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

Примеры располагаются в каталоге ExamplesChapter04.

Спрайты

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

Разработчики восьмой версии этой замечательной библиотеки позаботились о программистах, переработав модуль DDutil и предоставив в наше распоряжение объектно-ориентированную оболочку для использования DirectDraw. Код приложений выглядит удобочитаемым и легко воспринимаемым. Ваш покорный слуга перенес этот модуль на Delphi (назвав DDutil), и мы сможем воспользоваться удобными нововведениями. Однако в рассматриваемых до сих пор примерах эта библиотека не использовалась и во многих последующих примерах также не будет применяться.

Во-первых, использование такой, как и любой другой объектно-ориентированной библиотеки в Delphi приводит к значительным накладным расходам, потерям драгоценного времени, поэтому указанные библиотеки лучше включать лишь в простые примеры.

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

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

Я надеюсь, что ознакомление с предыдущим материалом книги прошло для вас без проблем, и вы теперь можете свободно ориентироваться в этих программах с длинным и громоздким кодом. Если это так, вы будете легко разбираться и в чужих программах, написанных на другом языке. Вы можете встретить массу примеров по использованию DirectX в книгах, ориентированных на С-программиста в DirectX SDK или Сети. Код таких примеров вами должен легко пониматься, поскольку код наших предыдущих примеров был к нему очень близок.

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

Код теперь выглядит проще, но я подчеркну, что ваши программы только выиграют, если вы будете создавать их так, как мы делали это в предыдущих примерах.

Ну что же, после такого вступления можно переходить к рассмотрению первого примера, проекта каталога Ex01. Выглядит его работа несложной: по экрану времени перемещаются образы логотипа DirectX, отскакивая от стенок. Пример является моей трансляцией одного из примеров, входящих в DirectX 8.0 SDK, я внес в код минимум изменений по сравнению с первоисточником.

Поведение спрайтов не будем подробно рассматривать, проанализируем голько то, что связано непосредственно с DirectDraw.

В коде отсутствуют многие знакомые нам типы, вместо них появились новые:


g_pDisplay : CDisplay; // Главный объект

g_J?LogoSurface : CSurface; // Поверхность образа

g_pTextSurface : CSurface; // Поверхность текста

Я долго думал, изменять ли префикс таких типов на префикс "т", принятый для Delphi, и решил оставить все-таки его таким же, как и в первоисточнике.

лавный объект инкапсулирует методы и свойства, связанные с созданием и управлением поверхностями. Объекты присоединяемых к главному объекту поверхностей можно создавать пустыми, либо по содержимому растра, либо путем вывода текста:



g_pDisplay := CDisplay.Create; . // Создание главного объекта

// Метод создания полноэкранного дисплея

hr := g_pDisplay.CreateFullScreenDisplay(Handle, ScreenWidth,

ScreenHeight, ScreenBitDepth);

// Анализ успешности действия

if FAILED(hr) then ErrorOut (hr, 'This display card does

not support 640x480x8.');

// Создание внеэкранной поверхности спрайта

hr := g_pDisplay.CreateSurfaceFromBitmap(g_pLogoSurface, imageBmp,

SPRITE_DIAMETER, SPRITEJDIAMETER);

if(FAILED(hr)) then ErrorOut (hr, 'CreateSurfaceFromBitmap');

// Создание внеэкранной поверхности с текстом

hr := g_pDisplay.CreateSurfaceFromText(g_pTextSurface, Font.Handle,

HELPTEXT, RGB(0,0,0>, RGB(255, 255, 0));

if(FAILED(hr)) then ErrorOut (hr, 'CreateSurfaceFromText');

// Метод поверхности для установки цветового ключа

hr := g_pLogoSurface.SetColorKey(0);

// Ключ - черный цвет

if(FAILED(hr)) then ErrorOut (hr, 'SetColorKey');

Как я и обещал, код действительно упростился, нет ни слова о первичной поверхности и вообще о буферах. Вся эта черновая работа скрыта от глаз разработчика. Воспроизведение также значительно упростилось. Основано оно целиком на использовании методов главного объекта:


for iSprite := 0 to NUM_SPRITES - 1 do // Цикл вывода спрайтов

g_pDisplay.ColorKeyBlt(g_Sprite[iSprite].fPosX,

g_Sprite[iSprite].fPosY, g_pLogoSurface.GetDDrawSurface, nil);

// Вывод текста подсказки

g_pDisplay.Blt(10, 10, g_pTextSurface, nil);

// Завершение работы. Выполняем переключение поверхностей

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*