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

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

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

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

Урок 23. Готовимся к стрельбе из лука

Урок 23. Готовимся к стрельбе из лука

 

Перед выводом статистики немного улучшим существующий код. Пока у нас не реализован момент роста уровня героя при увеличении опыта (процедура IncXP в модуле Него). Вот как мы его запрограммируем:

 

procedure  IncXP(  var  H:   THero;   axp:   Integer   );

begin

inc (   H.Exp,   axp   );

ShowInfo(STR_ADD_EXP + IntToStr(axp));

if H.Exp > H.MaxExp then

begin

H.Exp := 0;

if H.Level < MaxPlayerLevel then

begin

Showlnfo(STR_NEXTLEVEL);

inc(H.Level);

end;

H.MaxExp := ExpLevel_Table[H.Level];

H.MaxHP := HPLevel_Table[H.Level];

H.HP := H.MaxHP;

end;

end;

 

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

Информацию о герое мы будем выводить с помощью процедуры ShowHeroFullInfo, которую расположим конечно в модуле LowLevel, так какзто задача, непосредственно связанная с пользовательским интерфейсом:

 

procedure ShowHeroFullInfo(HeroNum:   Integer);

begin

end;

 

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

Procedure ShowHeroFullInfo;

Begin

…(1,1);

End;

 

При нажатии клавиши будем вызывать ее? Допустим, по нажатию на символ 'с', для чего дополним цикл обработки событий в модуле Main еще одним пунктом:

 

While true do

Begin

…me

I:=readkey;

Case I of

‘ c ’: ShowHeroFullInfo;

g ’: GetItemFromMap;

End;

 

Мы желаем знать, прежде всего, значения всех его базовых параметров и навыков, по здоровью и опыту, уровень и другие дополнительные сведения. Сначала достанем параметры из массива Chars и навыки из Skills (для отображения слотов и предметов у нас уже есть процедуры ShowHеroSlots и ShowHeroItems). Для этого, прийдется подготовить в модуле Texts массив текстовых констант.

Получим название каждого параметра и каждого навыка (в соответствии с порядоком, елементами chr.... skill... в модуле Неrо). Здесь мы вновь столкнемся с проблемой по подготовке массива SlotName с названиями слотов - из-за того, мы будем ссылаться с интерфейсной части одного модуля на интерфейсную часть конструкции подключаемых модулей модуля Неrо уже указан модуль Texts. Перменные MaxChars и MaxSkills надо будет перенести в модуль Texts.
            Обратимся к массивам с названиями соответствующих особенностей героя:

 

… :array[1..MaxChars]   of   string[20]   =

{

‘Ловкость'    ,    '   Тело   '   ,    '   Ум   '    ,    '   Мудрость   '    ,    '

}

…: array[1..MaxSkills] of string[20] =

{

…, ‘Поиск оружия’, ‘Защита

}

 

В.модуле Hero раздел констант немного сократится:

 

const   chrSTR   =   1;

chrDEX   =   2;

chrCON  -  3;

chrlQ  =   4;

chrWIS   =   5;

chrCHA  =   6;

skillHandWeapon  =   1;

skillTrapSearch =   2;

skillDefence  =   3;

 

При этом компилятор нам дополнительно сообщит, что в модуле Tables теперь не определена константа MaxSkills, и поэтому в заголовок надо добавить ссылку и на Texts -новое место этой константы:

 

unit Tables;

interface uses  Hero,   Texts;

 

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

 

procedure   ShowHeroFullInfo;

var  i:   Integer;

begin

ClrScr;

GoToXY(l,1);

WriteLn(STR_HEROFI) ;

for  i   :=  1   to MaxChars   do

WriteLn (   CharsName[i],    '    :    '   ,   Heroes[CurHero] .Chars[i]    );

WriteLn;   WriteLn(STR_HER0FI2);

for  i   :=   1   to MaxSkills   do

WriteLn (   SkillsName[i],    '    :    '    ,   Heroes[CurHero] .Skills[i]    );

ReadLn;

ShowGame;

end; Здесь использована две константы (модуль Texts):

STR_HEROFI   =   '   Параметры героя:    '    ; STR_HEROFI2  =   '   Навыки   героя:    '   ;

 

Что еще будет нас интересовать? Это, без сомнения, уровень героя, текущий набранный опыт и остаток до следующего уровня. Эти данные уже хранятся в структуре ТНего, поэтому итоговый вариант процедуры, не нуждающийся в комментариях, запишется так:

 

procedure   ShowHeroFullInfo;

var  i:   Integer;

begin

ClrScr;

GoToXY(l,1); WriteLn(Heroes[CurHero].Name,',',RaceName[Heroes[CurHero].Race], '    '    ,ClassName[Heroes[CurHero].Class]);

WriteLn(STR_HEROFI_LEVEL,   Heroes[CurHero].Level);

WriteLn(STR_HEROFI_EXP,   Heroes[CurHero].Exp,    '   / '    ,Heroes[CurHero].MaxExp);

WriteLn;

WriteLn(STR_HEROFI);

for  i   :=   1   to MaxChars  do

WriteLn(   CharsName[i],    '    :    '    ,   Heroes[CurHero].Chars[i]    );

Writeln(STR_HER0Fl2);

Fo I:=1 to MaxSkills do

Writeln( SkillsName[i], ' : ' , Heroes[CurHero].Skills[i] );

End;

 

Стрельба из лука

Следующим шагом по улучшению нашей игры станет реализация дальнобойного оружия. Что позволит герою вести огонь по противнику с расстояния, однако такая возможность давала бы персонажу слишком большие преимущества перед монстрами, которые сражаются в рукопашную, поэтому на стрельбу нам придется наложить ограничения. Какими они могут быть?

Нам нужны патроны, стрелы, камни, - другими словами, боеприпасы. Для этого создаются два новых типа предметов, назовем их itemAmmo (боеприпасы) и IWeapon (дальнобойное оружие):

 

WeaponItemType  =   (itemHandWeapon,   itemArmor,

itemAmmo,   itemRangedWeapon,   itemNone);

item)

 

Сделаем код таким, чтобы дополнение тех или иных понятий новыми сущностями имело минимальные сообщения об отсутствии их реализации автоматически. Теперь добавим две новые константы в описание типа TGameltemTypc, мы если будем компелировать программу, то сразу получим сообщение об ошибке. В …Level имеется массив констант ItemRecords, содержащих символы- соотеветвующих предметов. Расширим его двумя новыми позициями. Пусть они отделяются символом '|', а дальнобойное оружие (лук) - символом '}'.

 

ItemRacords:   array[TGameltemType]   of TTileRecord =

{

‘ | ’ , Clr:laghtCyan), 

‘ | ’ , Clr:LightGreen),

 ‘ | ’ , Clr: lightCyan) ,

‘ | ’ , Clr:LihtGreen) ,

‘ | ’ , Clr:Black)

}

 

Пускай они разбрасываются по карте равномерно и автоматически, так что в нашем мире можно будет найти и стрелы, и луки.

            Данные предметов добавляются в массив Item Types. Прежде всего увеличим на два MaxItmeTypes – до 6.

 

MaxItemTypes:=6;

 …Types:array[1..MaxItemTypes]   of TGameltem =

{

…ItemAmmo;

…ItemAmmo;

…(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);

…(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);

…RangeWeapon;

…(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,0))

}

 

Константы в модуле Texts описывают название новых типов предметов:

 

STR_AMMO =   '   Стрелы   '    ;

STR_CROSS  =   '   Лук   '    ;

 

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

 

const   

intAmmo =   1; intRangedAmmo  -   1;

 

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

 

function  GoodSlot(Slot:   Integer;   Itm:   TGameltem):   Boolean;

begin

GoodSlot := false;

case Slot of slotBody : GoodSlot := Itm.TType in [itemArmor];

slotHands: GoodSlot := Itm.IType in [itemHandWeapon,

itemRangedWeapon];

end;

end;

 

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

if Heroes[CurHero].Class =  classRanger  then

begin

Heroes[CurHero].Items[1]    :=   ItemTypes[6];

end;

end;

 

Здесь мы перезаписываем уже размещенный первым топор на лук (6-й в массиве типов предметов). Кроме того, этому луку мы придаем 10 стрел, используя константу intRangedAmmo.

С перемещением из инвентаря "в руки" боеприпасов придется поступить по другому. Нам потребуется дополнительно проверить, находится ли в руках дальнобойное оружие, после чего загрузить в него нужное количество стрел, а сам предмет удалить. В перспективе вероятна необходимость дополнительного анализа соответствия типа боеприпасов типу оружия - ведь из пращи нельзя стрелять стрелами, а стрелы для легкого лука, возможно, будут отличаться отстрел к тяжелому арбалету.

Вводя данную дополнительную возможность в игру, мы рано или поздно столкнемся с необходимостью отображения более подробной информации о предметах, хранимых в инвентаре или весомых на теле. Пока для этого мы просто выводим название предмета, однако уже сейчас есть необходимость как минимум отображения числа стрел для двух новых типов предметов.

В модуле GameItem добавим функцию, которая будет выдавать значение предмета. В ней будут собраны все сведения о всех предметах, и в процедурах, наподобие ShowHeroitems достаточно будет внести обращения к программной функции генерации описания.

 

Procedure GetItemName(itm:TGameItem): String;

Begin

  Case Item.Type of

  Writeln( GetItemName: itm.Name+

‘ | ’ + inttostr(Itm.Ints[intAmmo])+ ‘)’;

                        GetItemName:=itm.Name+’|’+inttostr(Itm.Ints[intRangerAmmo])+’)’;

… GetItemName:=Itm.Name

End;

End;

 

Добавим заголовок функции в раздел интерфейса, а в раздел реализации подлючим модуль Iowlумуд для доступа к функции IntToStr. Теперь следом за названим программа будет сообщать число стрел, в круглых скобочках.

… данной функции разместим в процедурах работы с инвентарем и экипировкой, … старых выводов названий предметов напрямую.

 

Procedure ShowHeroSlots:

If Heroes[CurHero].Slots [i] .IType   =   itemNone

Then Write(STR_EMPTY_ITEM)

Else Write(GetItemName (Heroes [CurHero] .Slots [i] ) )

 

Procedure ShowHeroItems:

If Heroes[CurHero].Slots [i] .IType   =   itemNone

Then Write(i, ‘)’, STR_EMPTY_ITEM)

Else Write(i, ‘)’, GetItemName (Heroes [CurHero] .Slots [i] ) )

 

Теперь лук находится в руках, и для него приготовлены стрелы, герой должен стрелять из него и поражать противника на расстоянии.

В зависимости от меткости и силы стрельбы.


Источник: delgame.at.ua

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

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