Михаил Краснов - Графика DirectX в Delphi
- Название:Графика DirectX в Delphi
- Автор:
- Жанр:
- Издательство:неизвестно
- Год:неизвестен
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Михаил Краснов - Графика DirectX в Delphi краткое содержание
Графика DirectX в Delphi - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
Игра "Меткий стрелок"
При написании мало-мальски объемной игры необходимо применять приемы, которыми новички часто пренебрегают, считая их малозначимыми. Знакомясь с примерами настоящей главы, вы легко сможете убедиться, как важно придерживаться некоторых правил, своими глазами вы увидите, как сильно выигрывает в этом случае приложение.
Следующий наш пример, проект каталога Ех03, является уже вполне законченной игрой, хотя и носит своеобразный оттенок любительских творений.
Игра состоит в том, чтобы поразить всех монстров, беспрерывно появляющихся на экране, пока их количество не достигнет какого-то предела. Вооруженный мощным оружием воин располагается в нижней части экрана и способен передвигаться только по горизонтали. Он может стрелять влево, вправо или вверх; с помощью клавиш управления курсором можно передвигать его и задавать направление стрельбы (пробелом осуществляется вертикальное направление стрельбы).
Чудовища мечутся по экрану, отталкиваясь друг от друга и от границ окна (предел нижней границы области перемещений монстров чуть выше нижней границы окна).
Несмотря на свой ужасный вид, монстры вполне безобидны и не приносят никому никакого вреда.
В игре присутствует два вида чудовищ, после попадания в монстра пули на месте трагедии остается огненный сполох (рис. 5.2).

Данный пример иллюстрирует ваше умение создать, в принципе, несложную игру без каких-либо особых ухищрений, опираясь на полученные знания. Игра работает со вполне удовлетворительной скоростью даже на маломощных компьютерах (для достижения этого используется 8-битный режим), хотя имеется значительный запас для оптимизации ее работы.
Код построен на основе примера из предыдущей главы с проверкой столкновений. Класс TBaseSprite является базовым для других классов спрайтов. Следуя логике предыдущих примеров, каждый объект имеет собственную поверхность:
type
TBaseSprite = class
FSpriteSurface г IDirectDrawSurface?; // Поверхность
PosX, PosY : Integer; // Позиция
SpriteWidth : Integer; // Размеры
SpriteHeight. : Integer;
function GetRect : TRect; // Охватывающий прямоугольник
procedure Show; virtual; abstract; // Вывод private
rcRect : TRect; // Прямоугольник кадра
end;
Фон загружается из отдельного растра, все остальные образы берутся из компонентов класса Timage (рис. 5.3).

Классы воина, монстров и пуль являются дочерними базового класса:
type
TWarrior = class (TBaseSprite) // Класс воина
Direction : (dirLeft, dirRight); // Два направления
constructor Create (const Image : TImage); // Конструктор
function Restore (const Image : TImage) : HRESULT; // Восстановление
// Метод вывода определяется в каждом дочернем классе
procedure Show; override;
end;
Обратите внимание, что каждая пуля в моей игре является отдельным спрайтом:
type
TBullet = class (TBaseSprite)
Delay : DWORD; // Задержка, задает скорость полета пуль
constructor Create (const Image : Tlmage);
function Restore (const Image : Tlmage) : HRESULT;
procedure Show; override; // Вычисление нового положения и вывод
private
Xinc : Integer; // Наращивание по каждой оси
Yinc : Integer;
ThisTickCount : DWORD; // Локальный таймер для каждого спрайта
LastTickCount : DWORD;
end;
Для спрайтов монстров необходимо определять столкновения, их класс унаследовал очень многое от класса спрайтов из примера предыдущей главы:
type
TCollidelnfo = record
X, Y : Integer;
end;
TSprite = class (TBaseSprite)
Delay : DWORD;
AnimFrame : Integer; // Текущий кадр
FrameCount : Integer; // Всего кадров для этого вида монстров
Collide : BOOL;
Live : BOOL; // Флаг, сигнализирующий, не убит ли монстр
constructor Create (const Image : Tlmage; const SprDelay : DWORD;
const FrmCount : Integer);
function GetCenterX : Integer;
function GetCenterY : Integer;
function Restore : HRESULT;
procedure CalcVector;
procedure Hit(S : TSprite);
procedure Show; override; // Вычисление нового положения и вывод private
Xinc : Integer;
Yinc : Integer;
Collidelnfo : TCollidelnfo;
ThisTickCount : DWORD;
LastTickCount : DWORD;
end;
На экране может присутствовать до двухсот спрайтов одновременно (сто монстров и сто пуль), это большая цифра, и вы в состоянии увеличить эту цифру еще больше. Программа будет дольше инициализироваться, но воспроизведение получалось у меня с очень хорошей скоростью даже тогда, когда весь экран был забит спрайтами до отказа. А тестировал я эту игру на очень скромной машине:
const
DelayMonsters = 1000;// Через сколько миллисекунд появится новый монстр
MaxSprites = 100; // Ограничение количества спрайтов
var
Monsters : Array [0..MaxSprites - 1] of TSprite; // Массив чудовищ
Bullets : Array [0..MaxSprites - 1] of TBullet; // Массив пуль
Warrior : TWarrior; // Объект бойца
GlobalThisTickCount : DWORD; // Глобальный таймер
GlobalLastTickCount : DWORD;
NumMonsters : Integer =0; // Текущее количество монстров
NumBullets : Integer =0; // Текущее количество пуль
Создание отдельного спрайта (имеющего собственную поверхность) происходит очень долго, поэтому массивы спрайтов заполняются в начале работы приложения. Если же поступать так, как подсказывает логика, и создавать объекты только непосредственно перед их появлением на экране, картинка в такие моменты будет замирать на долю секунды. Создание двух сотен объектов будет долгим. Чтобы скрасить время ожидания, перед началом этого процесса я вывожу на первичную поверхность картинку фона, но можно было бы использовать и специальную заставку:
FDDSBackGround := DDLoadBitmap(FDD, bkBitmap, 0, 0); // Загружаем фон
if FDDSBackGround = nil then ErrorOut(hRet, 'DDLoadBitmap');
// Палитра предварительно загружена,
// устанавливается для всех поверхностей программы
hRet := FDDSBackGround.SetPalette(FDDPal);
if Failed (hRet) then ErrorOut(hRet, 'SetPalette');
// Прямоугольник, охватывающий весь экран
SetRect(bkRect, 0, 0, ScreenWidth, ScreenHeight);
// Сразу же после загрузки на экран выводится фон
FDDSPrimary.BltFast(0, 0, FDDSBackGround, ObkRect, DDBLTFAST_WAIT;
Randomize;
// Создание объекта воина
Warrior := TWarrior.Create (ImgWarrior);
// Заполняем массив монстров
for wrkl := Low (Monsters) to High (Monsters) do
if random > 0.5
then Monsters [wrkl] := TSprite.Create (ImgMosterl,
40+ random (40), 4)
else Monsters [wrkl] := TSprite.Create (ImgMoster2, 40 + random (20), 6);
// Заполняем массив пуль
for wrkl := Low (Bullets) to High (Bullets) do
Bullets [wrkl] := TBullet.Create (ImgBullet);
Чудовища в игре динамичны, каждый из них со временем меняется: шевелит глазами или раскрывает рот. Заготовки монстров содержат ленту кадров для его отображения. При создании монстра какой-то произвольный из них берется за начало цепочки кадров. Сделано это для того, чтобы не получилось, будто бы все чудовища синхронно меняются в своем обличий:
Constructor TSprite.Create (const Image : TImage; const SprDelay : DWORD;
const FrmCount : Integer);
var
DC : HOC;
ddsd : TDDSurfaceDesc2;
hRet : HResult;
begin
ZeroMemory (@ddsd, SizeOf (ddsd) ) ;
with ddsd do begin
dwSize := SizeOf (ddsd) ;
dwFlags := DDSD_CAPS or DDSD_HEIGHT or DDSD_WIDTH;
dwHeight := Image.Height;
dwWidth := Image.Width;
ddsCaps.dwCaps := DDSCAPS_OFFSCREENPLAIN;
end;
hRet := frmDD.FDD.CreateSurface(ddsd, FSpriteSurface, nil);
if Failed (hRet) then frrr.DD. ErrorOut (hRet, ' CreateSpriteSurface ' ) ;
Читать дальшеИнтервал:
Закладка: