Создание карты в игре методом спрайтовDelphi , Графика и Игры , Создание игрСоздание карты в игре методом спрайтовАвтор: Мироводин Д.А. В играх, где используется простая 2D проекция, используется наверное два способа построения игрового пространства (карт). Первый о котором и будет рассказ, заключается в построение карты из спрайтов одинакового размера. А второй из уже готовых больших изображений, но об этом в другой главе. Преимущества этого способа - малый объем ресурсов графики, следовательно не требовательность к ресурсам. Практически любой размер карты - он ограничен лишь массивом и т.д. К минусам можно отнести сложность подгона текстур друг к другу. Этот способ построения карт применялся в таких БОЕВИКАХ ( не побоюсь этого слова ) игрового фронта как : WARCRAFT, DUNE и т.д. С помощью этого типа карт можно написать неплохую RPG или стратегия. Ну приступим. Первое что нам нужно это спрайты: Преимущества этого способа - малый объем ресурсов графики, следовательно не требовательность к ресурсам. Практически любой размер карты - он ограничен лишь массивом и т.д. К минусам можно отнести сложность подгона текстур друг к другу. Этот способ построения карт применялся в таких БОЕВИКАХ ( не побоюсь этого слова ) игрового фронта как : WARCRAFT, DUNE и т.д. С помощью этого типа карт можно написать неплохую RPG или стратегия. Ну приступим. Первое что нам нужно это спрайты : В примере я сделал файл Flur1.bmp там 20 спрайтов размером 32 x 32 / при создании старайтесь делать спрайты квадратные - упрощается вычисление/. Спрайты индексируются 0 ... 19; Что представляет из себя карта - это двух мерный массив , элементы которого - индексы спрайтов. Например: MAP: Array [0..100,0..10]of integer; Это означает, что мы хоти создать карту размером 100 x 100 спрайтов, допустим размер спрайта 32 x 32 тогда общая длина/ширина карты в пикселях будет 3200 x 3200. Но что вам мешает создавать карты, 1000 x 1000 клеток. ( Пример в HMM2 максимальная карта 128 x 128 при размере спрайта 32 пикселя ) Я советую создать класс для карты, вот как сделал бы я : type TFlur= class private SpriteLastIndex, // Кол-во спрайтов в Resource SpriteWH:integer;// Размер спрайта, должен быть квадрат Resource:TBitmap;// Ресурсы графики public Table:Tlist; // Массив карты развернутый в список Width,Heigth:Integer;// Ширина и высота карты в спрайтах Constructor Create(Const X,Y,Sprite:integer);// ширина, высота, размер спрайта Procedure LoadResource(FileName:String); // путь к BMP ресурсу Procedure RandomGenerator; // случайное заполнение Table Procedure Draw(DestHandle:TCanvas;X,Y:Integer;SourceRect:TRect); // Canvas для вывода, // Смещение X и Y относительно начала DestHandle // SourceRect - какой кусок карты Table выводить на экран, В КОЛ-ВАХ СПРАЙТОВ Destructor Destroy; override; end; По поводу Table - я использовал TList вместо Array т.к. при создании мы можем не знаем, какого размера карту будем делать. В игре создавая один TFlur можно подгружать туда новые карты динамически, при переходе на новый уровень ( зону, город ... ), без замедления. Рассмотрим процедуру Draw, т.к. все остальное достаточно понятно : Procedure TFlur.Draw(DestHandle:TCanvas;X,Y:Integer;SourceRect:TRect); var I,J:integer; dx,dy:integer; // для смещений в пикселях TableIndex:^integer; // указатель на элемент Table begin // Делаем проверку if SourceRect.Left<0 then exit; if SourceRect.Top<0 then exit; if SourceRect.Left+SourceRect.Right>Heigth-1 then exit; if SourceRect.Top+SourceRect.Bottom>Width-1 then exit; dx:=0;dy:=0;// обнуляем смещение // зададим цикл по области карты для показа for I:=SourceRect.Left to SourceRect.Left+SourceRect.Right do begin for J:=SourceRect.Top to SourceRect.Top+SourceRect.Bottom do begin TableIndex:=(Table.Items[Width*J+I]); // Уже знакомой прцедурой копируем один спрайт на экран BitBlt(DestHandle.Handle,dx+X,dy+Y,SpriteWH, SpriteWh,Resource.Canvas.Handle,TableIndex^*SpriteWh, 0,SRCCopy); inc(dy,SpriteWH);// увеличиваем смещение dy на SpriteWH end; Inc(dx,SpriteWH);dy:=0;// увеличиваем смещение dx на SpriteWH, обнуляем dy end; end; Достанем элемент из списка с координатами I,J
Хранить спрайты можно не только в BMP, но и в TImageList. При этом появляется множество удобств:
Итак, что я переписал в TFlur : коструктор и Draw constructor TFlur.Create(ConstMapX,MapY,SpriteW,SpriteH:integer;ResFileName:String); // MapX,MapY - размер карты в спрайтах // SpriteW,SpriteH - размер спрайта // ResFileNama - путь к BMP var Resource:Tbitmap; // BMP с ресурсами begin Resource:=Tbitmap.Create; // Грузим ресурсы из ResFileName Resource.LoadFromFile(ResFileName); ImageList:=TImageList.CreateSize(SpriteW,SpriteH); // Создаем лист под спрайты ImageList.DrawingStyle :=dsNormal; // Устанавливаем параметры ImageList.Masked := False; ImageList.Add(Resource,Resource); .... end; И изменения в TFlur.Draw : .... for J:=SourceRect.Top to SourceRect.Top+SourceRect.Bottom do begin TableIndex:=(Table.Items[Width*J+I]); ImageList.Draw(DestCanvas,dx+X,dy+Y,TableIndex^); Inc(dy,32); end; Inc(dx,32); .... При компиляции использовал компонент THeadedTimer ( инсталируйте его из директории THeadedTimer, как установить компоненты Вы надеюсь знаете ). Этот компонент аналог стандартного TTimer, но использованы потоки - высокая скорость работы. И последнее - если вы будете совместно использовать Flur и спрайты то копируйте все в БУФЕР. Т.е. карту в буфер, спрайты и курсор в буфер, буфер на экран. Если есть у кого ссылки на ресурсы с графикой от игр ( лучше стратегий и RPG ) или вообще текстуры, но текстуры к ИГРАМ, а не web ( формат BMP, DIB, PSD) то прошу присылать ссылки. Кто напишет что что-нибудь дельное используя эти методы обязательно размещу. Если ВЫ знаете другие методы построения карт в играх прошу присылать идеи. Прежде чем читать данную статью, настоятельно рекомендую прочесть ее первую часть. В первой части я показал как можно создать карту из набора спрайтов и вывести ее на любой TCanvas. При этом карта создавалась как таблица из наборов номеров спрайтов, этот способ удобен там, где все объекты привязаны к координатам спрайтов. Чтобы было более понятно, приведу простой пример: Игра шахматы. Все фигурки привязаны к координатам доски ( у нас к координатам карты), и их передвижение возможно только в этих координатах. Но при переносе фигуры появляются другие координаты - промежуточные. И если ограничиваться координатами доски не возможно создать плавного перемещения, анимации. Для достижения плавного скроллинга карты, анимации объектов приходится вводить координаты пиксельные. Изменению подверглись только выделенные красным строчки. type TFlur2= class private SpriteLastIndex, // Кол-во спрайтов в Resource SpriteWH:integer;// Размер спрайта, должен быть квадрат Resource:TBitmap;// Ресурсы графики Width1,Heigth1:Integer;// Ширина и высота карты в спрайтах public Table:TList; // Массив карты развернутый в список Width,Heigth:Integer;// Ширина и высота карты в пикселях Constructor Create(Const X,Y,Sprite:integer);// ширина, высота карты , размер спрайта в пикселях Procedure LoadResource(FileName:String); // путь к BMP ресурсу Procedure RandomGenerator; // случайное заполнение Table Procedure Draw(DestHandle:TCanvas;X,Y:Integer;SourceRect:TRect); // Canvas для вывода, // Смещение X и Y относительно начала DestHandle // SourceRect - какой кусок карты Table выводить на экран, в пикселях Destructor Destroy; override; end; Как Вы видите изменений произошло не очень много, но зато пришлось полностью переписать процедуру вывода готовой карты - Draw. При вызове конструктора, в качестве параметров X и Y передается размер карты в пикселях ( ранее в количествах спрайтов ). Как и в TFlur значения X и Y должны быть равны - только квадратная карта, это связано с особенностью хранения массива со значениями спрайтов. Еще одно условие X должен делиться на Sprite без остатка :) Если подробно рассматривать, что происходит в процедуре Draw, то вот основные моменты.
В принципе на словах, это не очень понятно, но просто попробуйте нарисовать на бумаге и я думаю Вы разберетесь. Теперь можно задаться вопросом: а за чем все это было нужно, и чем TFlur хуже? Все очень просто, теперь появилась возможность скроллировать карту хоть по 1 пикселю, а раньше только по 32 ( т.е. по ширине спрайта карты ). При этом будет достигаться плавность перемещения. Чтобы поместить на нашу карту анимированные спрайты я написал небольшой класс TSprite. Замечу что он не универсальный и далеко не совершенный. Просто для своих целей Вы можете дописать необходимые вам пункты, но я остановлюсь на этом далее. Вот заголовок класса TSprite: type TSprite=Class // Внутренние координаты спрайта, real по тому, что // вычисление ведется через sin и cos - достигается // более плавное перемещение. Возможность поворота по // любому углу. FCoordXFl, FCoordYFl:Real; // "Экранные" координаты FCoordX, FCoordY, FAngle:Integer; // FAngle - вектор направления скорости спрайта, может // принимать значения от 0 до 360 ( 0,45,90,135 ... 360 для данной программы) FSpeed:Integer; // "скорость" FCount:Integer; // Счетчик движений - всего 4 изображения анимации на каждое движение FGo:boolean; // Стоим или идем Imagelist:TImagelist; constructor Create(AX,AY,AAngle:integer); Procedure DrawNext(AСanvas:TCanvas;Dest:TRect); Procedure Rotate(AAngle:integer); end; Я думаю тут должно быть все понятно, но все же остановлюсь на некоторых моментах. При выполнении процедуры DrawNext передается параметр Dest:TRect - это видимая область карты, она изображена на рисунке розовым цветом. Если координаты спрайта не попадают в нее, то он не выводится. Теперь остановимся на возможностях модернизации данного класса и других тонкостях.
Оптимизация - как много в этом слове ! Конечно Вас не устроила скорость работы данного примера. Но я и не старался это сделать - 320x320 при 10-15 кадрах это мало. Если Вы собираетесь делать игру с разрешением 640x480 то вот способы оптимизации. Вся загвоздка в тормознутости TCanvas - по этому обойдемся без него. Самое лучшее использовать DirectX - смотрите раздел Lib и компонент DelphiX. И еще один вариант - Dib, так же смотрите в разделе Lib есть пара компонентов для работы, получается вполне приличная скорость с поддержкой всевозможных эффектов. Дерзайте ! Исходники можна взять здесь Создание карты в игре методом спрайтов - создать карту в игре методом спрайтов, размером 100x100 спрайтов, каждый из которых имеет размер 32x32 пикселов. Комментарии и вопросыПолучайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта. :: Главная :: Создание игр ::
|
||||
©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007 |