Меню сайта
Форма входа

Категории раздела
Уроки по созданию игр [38]
Программирование игр разной сложности
Игровые алгоритмы [24]
Алгоритмы, которые уже реализованы для разных жанров игр
Графика [5]
Учимся работать с графикой в Делфи
Мультимедиа [3]
Работа с мультимедийными возможностями Делфи
Другие статьи [18]
Статьи не вошедшие не в один из разделов
Ошибки [4]
Всевозможные ошибки и пути их решения
Четверг, 09.01.2025, 06:29
Приветствую Вас Гость

Статьи по программированию

Главная » Статьи » Уроки по созданию игр

Создание Ролевой игры РПГ на Паскале и Делфи. Урок 12

Урок 12. Программируем предметы     

Предметы.

На следующем шаге введем в игру концепцию предметов. Мы договаривались, что в нашем учебном варианте их список будет ограничен двумя типами - оружием и броней. Приводимые далее приемы добавления предметов читатель сможет без проблем расширить на свои собственные типы объектов (всевозможное снаряжение, еда, драгоценности, амулеты и т. п.). Подготовим модуль Gameltem: unit Gameltem; interface implementation end. Чем будет характеризоваться предмет? Уникальным идентификатором конкретного объекта, координатами местоположения на карте, типом предмета (броня, оружие), названием и набором дополнительных свойств. Заранее определить все мыслимые свойства очевидно, не удастся, так как мы пока не знаем, какие конкретно типы предметов будут появляться в нашей игре. В то же время желательно описать концепцию предмета так, чтобы в дальнейшем она могла быть свободно расширена под любые объекты, вводимые разработчиком. Поступим так - подготовим два достаточно больших массива целых и вещественных чисел, и в зависимости от типа предмета будем по разному трактовать содержимое этих массивов. Размеры массивов определятся следующими константами: const Maxltemlnt  =   20; MaxReallnt  =   20; Тип предмета (оружие или броня) зададим отдельным типом TGameltemType:

type TGameltemType  =    (itemHandWeapon,    itemArmor); Даее нам потребуется тип, описывающий конкретный игровой предмет: type TGameltem =  record ID:   Integer; x,y:   Integer; IType:   TGameltemType; Name   :   String[20];

Ints   :   array[1..Maxltemlnt]   of   Integer; Reals:   array[1..MaxReallnt]   of  Real; end; Как хранить доступные в локации предметы? Напрашивающийся способ - сделать это по аналогии с хранением монстров. То есть прежде всего нам потребуется массив ItemTypes шаблонов игровых предметов, идеологически схожий с массивом шаблонов монстров MonslerTypes. Первоначально в нем будет два вида оружия и два вида брони: const MaxItemTypes   =   4;

ItemTypes:   array[1..MaxItemTypes]   of TGameltem =

( (ID:1;

x:0;   y:0;

IType:itemHandWeapon;

Name:STR_AXE;

Ints: (0, 0,0, 0,0,0, 0,0, 0, 0,0, 0,0, 0,0, 0,0, 0,0,0) ;

Reals: (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0, 0,0)), (ID:2;

x:0; y:0;

IType:itemHandWeapon;

Name:STR_SWORD;

Ints: (0, 0,0, 0,0, 0,0, 0,0,0, 0,0, 0,0, 0,0, 0,0,0, 0);

Reals (0, 0,0,0,0,0,0, 0,.0,0,0,0,0, О,О, О,О,О,0,0)).,.
IType:itemArmor;
Name:STR_HELM;
Ints: (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
Reals: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0)),
IType:itemArmor;
Name: STR_BODYARMOR;
Ints: (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
Reals: (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0))

);
Значения предметов поместим как обычно в модуль Texts, не забыв сослаться на него в модуля Gameltem:
Const Str_AXE =  '   Топор   '    ;

STR_W0RD =   '   Меч   '    ;
STR_BODYARMOR =   '   Бронежилет   '    ;
STR_HELM  =   '   Шлем   '    ;

Предметы поместим в массив констант Items.
Const NexItems   =   10;

Var      Items: array[1..Maxltems]   of  TGameltem;

Предметы не всегда будут существовать в игре. Они могут по различным причинам лежать, портиться, продаваться, и так далее. Как отличать элементы массива Items, используемые в игре предметы, от "пустых" предметов? Договоримся, что значение координаты х, равное нулю, будет означать незадействоваипый, свободный слот в Items.

Определимся со свойствами разных типов предметов. Оружие будет, очевидно, курироваться величиной наносимого поражения и вероятностью попадания. Броня характеризуется одним параметром - "толщиной", или величиной поглощения удара противника (шкуры монстров). Опишем константы, соответствующие этим свойствам:

Const IntAttack_d1 = 1;

IntAttack_d2 = 2;

IntAttackHit = 3;

IntArmorDefence = 1;

Умения определяют индексы массива Ints, в которых хранятся соответсвующие параметры. Так, параметры виртуального броска кубиков (число кубиков и число граней кубика) будут записываться в первый (IntAttack_d1) и второй (IntAttack_d2), а вероятность опадания в третий (IntAttackHit). Если же тип элемента – броня, то значение защиты будет размещаться в первом (intArmorDefence) элементе. Возможные значения этих параметров занесем в наш массив ItemTypes:

ItemTypes: array [1..MaxItemTypes] of TGameItem =

{

(ID:1;

X:0; y:0;

IType:itemHandWeapon;

Name:STR_AXE;

Ints: (1,6,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);

Reals: (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)),

(ID:2;

ITypei.itemHandVte&pon;      

Name:STR_SWORD;

Ints:    (2, 4, 80, 0,0,0, 0,0, 0,0, 0,0, 0,' 0,0, 0,0,0, 0,0);

Reals: (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)), (ID:3;

x:0;   y:0;

IType:itemArmor;

Name:STR_HELM;

Ints: (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);

Reals: (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)), (ID:4;

x:0; y:0;

IType:itemArmor;

Name:STR_BODYARMOR;

Ints: (5, 0,0, 0,0, 0,0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0);

Reals: (0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0))

);

To есть меч будет наносить поражение, равное значению, выпавшему на двух четырехгранных кубиках, а вероятность попадания составит 80%. А бронежилет сможет погасить пять пунктов удара противника.

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

 

Разбрасываем предметы по локации

Этот процесс схож с распределением по локации ловушек. В силу условной ограниченности числа предметов в игре (десять) продемонстрируем несложный прием расчета вероятности размещения предмета на тайле в процессе генерации карты. Общее число доступных тайлов в игре - 32*32 = 1024 (для ДОС-версии). Разделив эту величину на число предметов, получим 102,4 - это и есть среднее количество тайлов, на которых желательно разместить один предмет. Отсюда получим вероятность размещения предмета на конкретном тайле -она будет примерно равна одной сотой.

Следом за оператором, изредка устанавливающим на свободный таил карты ловушку или источник (процедура MapGeneration), добавим группу операторов, добавляющую в массив Items случайный элемент из массива ItemTypes. Переменная п нужна, чтобы следить за постепенным заполнением массива Items. Правда, наш алгоритм не гарантирует, что все элементы Hems обязательно получат значения. Поэтому оставшиеся не у дел "предметы" сделаем невидимыми - занесем в поле х значение ноль, что, как уже говорилось выше, означает свободный элемент в Items.

 

procedure MapGeneration(MapLevel: Integer);

var n,i,x,y: Integer;

begin

CurMap := MapLevel;

n := 0;

for x := 1 to MAP_WIDTH do

for у := 1 to MAP_HEIGHT do begin if (x <= LOCAL_MAP_WIDTH) or (x >=

MAP_WIDTH-LOCAL_MAPJflIDTH) or

(y <= LOCAL_MAP_HEIGHT) or (y >=

MAP_HEIGHT-LOCAL_MAP_HEIGHT) then

GameMap[CurMap].Cells[x,y].Tile := tileStone else begin

If random(100)<35

then GameMap[CurMap].Cells[x,y].Tile := tileTree else

if random (2) = 0

then     GameMap.Cells [x, y] .Tile := tileGrass

else GameMap[CurMap].Cells[x,y].Tile := tileGround;

if random (100) = 0 then

if random(2) = 0

then GameMap[CurMap].Cells[x,y].Tile := tileTrap

else GameMap[CurMap].Cells[x,y].Tile := tileLive;

if FreeTile(GameMap[CurMap].Cells[x,y].Tile) then

if random (100) = 0 then

begin

if n<MaxItems then begin

Iterns[n] := ItemTypes[random(MaxItemTypes)+1];

Items[n].x := x;

Items[n] . у := у;

end;

end;

end;

GameMap[CurMap].Cells [x, y] . IsVisible := false;

End;

For i:=n+1   to MaxIterns  do

Items[i]. x     =   0 ;

 

Перед попыткой размещения предмета вставлено условие, согласно которому предмет размещается только на проходимом для персонажа тайле (что естественно), когда требуется показывать на экране предметы, расположенные на карте. Как поставим соответствие разным типам предметов разные символы и цвета их представления. Создадим для этого массив ItemRecords:

Const ItemRecords:array[TGameItemType] of TTileRecord=

{

Color: [‘]’; Clr:LightCyan),

Color[‘]’; Clr:LightGreen)

}

Значение массива определяется структурой типа TGameItemType.

Рассмотрим для отображения предметов процедуру ShowItem в модуле LowLevel:

Procedure ShowItem(itm:TGameItem);

Begin

… (WINDOW_LEFT+itm.x-GameMap[CurMap].LocalMapLeft,

Window_top+itm.y-GameMap[CurMap].LocalMapTop);

… (itemRecords[itm.IType].Clr);

ItemRecords[itm.IType].C)

End;

 

Вызывается из процедуры ShowItems, которую разместим в модуле Game, так как … кода, зависимого от операционной системы:

 

Procedure ShowItems;

Var …:integer;

begin

for i:=1 to MaxItems do

…IdlePoints[Items[i].x, Items[i].y] then

ShowItem(Items[i]);

End;

 

Показывать предметы станем сразу следом за выводом тайлов карты:

 

procedure ShowGame;

begin

ShowMap;

Showltems;

ShowMonsters;

ShowHero(CurHero);

ShowHeroInfo(CurHero);

end;

 

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

При создании Windows-приложений для современных персональных компьютеров подобные проблемы как правило не возникают. Программист может резервировать в программе практически неограниченные массивы данных - до двух гигабайтов. На практике, конечно приходится исходить из более реалистичных посылок и ориентироваться на доступные объемы ОЗУ порядка 100-200 мегабайтов, что, впрочем, само по себе уже очень и очень много.

Как можно было бы реализовать эффективное хранение предметов на карте? Игровщх предметов на карте может быть довольно много - сотни, а то и тысячи, поэтому процесс перерисовки всех тайлов, связанный с многократным выполнением длинного цикла проверки всех предметов (не находится ли какой-то из них на конкретном месте, как мы сделали в процедуре Showltems), может вызывать серьезную нагрузку на процессор и заметно 'тормозить работу программы. Простым решением этой незадачи выглядит расширение структуры элемента карты TMapCell новым полем, имеющим тип TGameltem. Таким образом мы получаем возможность хранить один предмет на каждом тайле, получать к нему мгновенный доступ и проводить другие манипуляции, не связанные с обработкой массива Items. Однако такой подход накладывает определенные требования к оперативной памяти - не очень высокие, но весьма сложно реализуемые в ДОС-компиляторе. Опытные разработчики в таких ситуациях прибегают к средствам динамического размещения больших массивов в памяти путем запроса соответствующих объемов уже в ходе работы программы. Это возможный путь, но он не снимает ограничений, связанных с невозможностью получения в 16-разрядной операционной системе области памяти, превышающей 64 килобайта. Имеются средства обхода и этого недостатка (запуск программы в защищенном режиме с помощью дополнительных драйверов, предоставляющих виртуальный доступ ко всей оперативной памяти), однако их использование обычно вызывает трудности в настройке у конечных пользователей. ДОС-платформа была нами выбрана в демонстрационных целях, чтобы показать идею и способы создания программ, способных "собираться" и работать в разных операционных системах на основе одного исходного кода. Обход конкретных ограничений, накладываемые ДОС-ом, мы не будем рассматривать, так как это устаревшая система.

Тренировка навыков, инвентарь.

Категория: Уроки по созданию игр | Добавил: Armageddets (22.06.2013)
Просмотров: 908 | Теги: Создание Ролевой игры РПГ на Паскал, Программируем предметы | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Наш опрос
Оцените мой сайт
Всего ответов: 103
Мини-чат
Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz
  • Статистика

    Онлайн всего: 1
    Гостей: 1
    Пользователей: 0