Письма.
Просьба, если пишете мне письма, указывайте в сабже слово "программирование". В противном случае ваше письмо с вероятностью 99% будет автоматически убито как спам :)
Новости мира разработчиков игр.
На сайте http://www.physicsengine.com/ опубликована общедоступная версия системы Newton Game Dynamics - библиотеки трехмерного моделирования физического мира. От других подобных технологий она отличается тем, что поддерживает не только воспроизведение трехмерных объектов, но и физику их движения - массу, инерцию, эффекты гравитации, столкновения, рассыпания итд. Можно также довольно легко создавать свои объекты - например, человечки или шагающие роботы, автомобильчики
и трассы - с готовой поддержкой физики движения! (на сайте можно найти примеры с исходниками).
Если порыться на этом сайте, то можно также найти опенсорсную поддержку этой библиотеки для Дельфи :)
Магические предметы.
Теперь научим персонажа-мага владеть магическими предметами. Для большего интереса возможность их использования будет доступна только классу магов. Предметы будут копией существющих заклинаний, только для их использования не потребуется маны, что немаловажно. Пусть также некоторые предметы будут представлять собой магические посохи и жезлы, отличающиеся "многозарядностью" - возможностью неоднократного вызова нужного заклинания. То есть если пузырек с волшебной жидкостью может быть выпит один раз, то "жезл исцеления"
позволит выполнить такую процедуру раз пять или десять.
Для реализации этой концепции введем новый тип предметов - "магический предмет".
type TGameItemType = (itemHandWeapon, itemArmor,
itemAmmo, itemRangedWeapon, itemMagik, itemNone);
...
const MaxItemTypes = 7;
ItemTypes: array[1..MaxItemTypes] of TGameItem =
...
А сейчас мы попробуем вместить в одну запись массива ItemTypes описане целой группы игровых предметов. Для этого можно воспользоваться свойством Ints, трактуя его разные элементы как различные смысловые описатели (своеобразный встроенный микроязык программирования). Пусть первый элемент этого массива Ints будет в свою очередь обозначать подтип-идентификатор конкретного магического предмета.
Вот какими могут быть его значения (оформляем их в виде констант):
Константа mintMax - это общее число подтипов магических предметов.
Первые два элемента - это разовые версии заклинаний, два последних - многозарядные. Будем указывать их непосредственно в момент генерации предметов на карте.
Кроме того, надо определить, какие элементы (какие индексы) массива Ints какую информацию хранят:
intMagikType = 1;
intMagikNum = 2;
Первый элемент массива - идентификатор подтипа предмета, второй - число зарядов. Все магические предметы будем обозначать новым символом ';':
Создание магического предмета будет происходить в процедуре генерации карты
if n <= MaxItems then begin
Items[n] := ItemTypes[random(MaxItemTypes)+1];
Items[n].x := x;
Items[n].y := y;
if Items[n].ID = 7 then begin
Items[n].Ints[intMagikType] := random(mintMax)+1;
case Items[n].Ints[intMagikType] of
mintStormStf : Items[n].Ints[intMagikNum] := 5;
mintHealingStf: Items[n].Ints[intMagikNum] := 10;
else Items[n].Ints[intMagikNum] := 1;
end;
end;
То есть если тип предмета - магический (ID=7), то его подтип формируется случайно, а затем определяется число "зарядов" - от 5 до 10 для жезлов и посохов, и единица для разовых предметов.
Кроме того, нам надо будет уточнить функцию GetItemName для нового типа магических предметов, так как одно словосочетание "Магический предмет" будет совершенно неинформативно. Показывать станем название подтипа предмета из массива MagikItemsName, дополняя его оставшимся числом "зарядов" заклинания - числом попыток его использования:
{ ----------------- } function GetItemName(Itm: TGameItem): string; begin case Itm.IType of
Теперь нам надо научиться предмет использовать. Пусть он "используется", когда мы выбираем его в инвентаре. Для этого дополним процедуру ShowHeroItems по работе с инвентарем строчкой вызова пока несуществующей функции UseMagikItem, которая "попробует" предмет на магичность и лишь в противном случае передаст управление дальше:
if n > 0 then begin if Heroes[CurHero].Items[n].IType = itemAmmo then begin if Heroes[CurHero].Slots[slotHands].IType = itemRangedWeapon then begin
Heroes[CurHero].Slots[slotHands].Ints[intRangedAmmo] :=
Heroes[CurHero].Slots[slotHands].Ints[intRangedAmmo] +
Heroes[CurHero].Items[n].Ints[intAmmo];
Heroes[CurHero].Items[n].IType := itemNone; end end else
if not UseMagikItem(n) then
begin
s := GetFreeSlot(Heroes[CurHero],Heroes[CurHero].Items[n]); if s > 0 then begin
Heroes[CurHero].Slots[s] := Heroes[CurHero].Items[n];
Heroes[CurHero].Items[n].IType := itemNone; end; end
...
Эту функцию, к интерфейсу уже напрямую не привязанную, реализуем в модуле Magik.
{ ----------------- } function UseMagikItem(ni: Integer): Boolean; begin
UseMagikItem := false; if Heroes[CurHero].Items[ni].IType <> itemMagik then Exit;
end;
Далее просто вызовем соответствующее заклинание, только не затрагивая запас маны, после чего понизим число "зарядов" предмета. Сейчас заклинания у нас встроены в процедуру ThrowSpell, и по необходимости выделим их в отдельные подпрограммы:
{ ----------------- } procedure ThrowSpell; var n: Integer; begin
... case n of
splFireStorm:
MakeFireStorm;
splSelfHealing:
MakeHealing;
end;
...
Новые процедуры:
{ ----------------- } procedure MakeFireStorm; var n,x,y,dam: Integer;
f: Boolean; begin
f := false; for x := Heroes[CurHero].x-1 to Heroes[CurHero].x+1 do for y := Heroes[CurHero].y-1 to Heroes[CurHero].y+1 do begin
n := IsMonsterOnTile(x,y); if n > 0 then begin
dam := random(4)+1;
HeroAttackFin(Heroes[CurHero],n,dam);
f := true; end; end;
В них просто выделена часть, ответственная за реализацию огненного шторма и исцеления. Эту часть и будем вызывать при выборе соответствующего предмета:
case Heroes[CurHero].Items[ni].Ints[intMagikType] of
mintStorm, mintStormStf : begin
MakeFireStorm; end;
mintHealing, mintHealingStf: begin
MakeHealing; end;
end;
В заключение надо будет снизить число использований предмета и в ряде случаев - удалить сам предмет из инвентаря: