Direct Draw по русски
Эффекты мультипликации
Теперь мы с Вами перейдем к тому, ради чего собственно и затеяли всю эту бодягу с программированием при помощи DirectDraw. Мы с Вами рассмотрим основы эффекта мультипликации. Как Вам (я надеюсь) известно сам эффект мультипликации состоит в быстрой смене кадров. Все движения персонажа заранее нарисованы, расположены в определенном порядке и сохранены в растровом файле. При создании спрайтов можно поступить по разному. Можно создать один файл (большой) в котором сверху нарисовать фон, а внизу расположить все спрайты. Мы, для удобства поступим так. Чтобы нам не загружать несколько файлов, а следовательно экономить время, создадим файл, размером 640х544 в котором верхняя часть размером 640х480 будет представлять собой некий фон, а оставшаяся часть вполне пригодна для размещения 10 кадров, размером 64х64 - это и буду спрайты. Далее должны создать третью поверхность, которая содержала бы нашу картинку вместе с фоном и спрайтами. Для этого нужно опять же в разделе объявления переменных var объявить её родную.
var
. . . . .
SpriteSurface : IDirectDrawSurface;
. . . .
С этой самой поверхности мы будем копировать нужные участки (rectangle) изображения на вторичную поверхность в определенном порядке. Порядок прост. Сначала мы копируем фоновое изображение, а затем накладываем поверх него спрайтовое изображение. Из этого делаем вывод, что нам также потребуется переменная типа TRect. Мы не долго думая объявляем таковую.
. . .
Rect: TRect;
. . .
Что же нам нужно ещё, для того, чтобы получить эффект мультипликации? Конечно же счетчик кадров, который будет гонять по кругу наши 10 картинок. Чтобы гонять с определенной скоростью, можно процедуру обновления экрана RedrawScreen (так мы её назовем) обрабатывать в событии OnTimer стандартного таймера Delphi, создав его предварительно. Но по моему лучше воспользоваться функцией GetTickCount, так как она работает стабильнее. Исходя из этого нам потребуются еще две переменные, типа DWORD. Обзовем их CurrentTick и LastTick. Время задержки обновления экрана будем находить из разницы между CurrentTick - LastTick. Каждый тик происходит примерно за 55 мс, что достаточно быстро для нас. Вот тут-то мы и введем еще одну переменную, которая будет определять скорость, или задержку смены экрана. Обзовем её Delay (задержка). Эта переменная имеет простой тип Integer. Так давайте сделаем это.
var
. . . .
CurrentTick, LastTick : DWord;
Delay, Frame: Integer;
. . .
Давайте теперь создадим поверхность SpriteSurface.
begin
. . . . .
with SurfaceDescription do begin
dwSize := sizeof(SurfaceDescription);
dwFlags := ddsd_caps or ddsd_height or ddsd_width;
ddsCaps.dwCaps:=ddscaps_offscreenplain;
dwwidth:=640;
dwheight:=544;
end;
DDResult:=DDrawObject.CreateSurface(SurfaceDescription,SpriteSurface, nil);
. . . . .
end.
Теперь попробуем написать процедуру перерисовки экрана.
procedure RedrawScreen;
begin
CurrentTick :=GetTickCount;
if CurrentTick - LastTick > Delay then begin
LastTick := CurrentTick;
Rect.Top :=0;
Rect.Left :=0;
Rect.Right :=640;
Rect.Bottom :=480;
DDResult:=SecondarySurface.BltFast(0,0,SpriteSurface,Rect,DDBLTFAST_NOCOLORKEY+DDBLTFAST_WAIT);
Rect.Top :=480;
Rect.Left :=Frame;
Rect.Right :=Frame+64;
Rect.Bottom :=Rect.Top+64;
DDResult:=SecondarySurface.BltFast(288,208,SpriteSurface,Rect,DDBLTFAST_NOCOLORKEY+DDBLTFAST_WAIT);
Frame := Frame+64;
if Frame >=576 then Frame :=0;
DDResult:=PrimarySurface.Flip(nil,ddFlip_Wait);
end;
end;
Самое главное - не забыть включить в процедуру FreeAll еще две строчки.
procedure FreeAll;
begin
DDrawObject.RestoreDisplayMode;
SecondarySurface._Release;
pointer(SecondarySurface):=nil;
PrimarySurface._Release;
pointer(PrimarySurface):=nil;
SpriteSurface._Release;
pointer(SpriteSurface):=nil;
DDrawObject._Release;
pointer(DDrawObject):=nil;
end;
Добавьте эту процедуру в цикл опроса сообщений от системы, что в самом конце программы.
Теперь запустите программку. И посмотрите, что у Вас получилось...
Продолжение здесь. |