Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Создание ролевой компьютерной игры 27) Магические предметы


Информационный Канал Subscribe.Ru

Разработка ролевой игры

27) Магические предметы

Письма.
Просьба, если пишете мне письма, указывайте в сабже слово "программирование". В противном случае ваше письмо с вероятностью 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 =
  ...

  (ID:7;
   x:0; y:0;
   IType:itemMagik;
   Name:STR_MAGIKITEM;
   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))
  );

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

Вот какими могут быть его значения (оформляем их в виде констант):

  const
  ...
  mintStorm = 1;
  mintHealing = 2;
  mintStormStf = 3;
  mintHealingStf = 4;
  mintMax = 4;

Чтобы стало понятнее, что же эти константы обозначают, введем в модуле Texts их описание:

   mintMax = 4;
   MagikItemsName: array[1..mintMax] of string[40] =
   (
   ' Кристалл вызова Огненного Шторма ' , ' Зелье Лечения ' ,
   ' Жезл Огненного Шторма ' , ' Посох Исцеления '
   );

Константа mintMax - это общее число подтипов магических предметов.

Первые два элемента - это разовые версии заклинаний, два последних - многозарядные. Будем указывать их непосредственно в момент генерации предметов на карте.

Кроме того, надо определить, какие элементы (какие индексы) массива Ints какую информацию хранят:

   intMagikType = 1;
   intMagikNum = 2;

Первый элемент массива - идентификатор подтипа предмета, второй - число зарядов. Все магические предметы будем обозначать новым символом ';':

  const ItemRecords: array[TGameItemType] of TTileRecord =
     (
     (C: ' + ' ; Clr:LightCyan),
     (C: ' [ ' ; Clr:LightGreen),
     (C: ' | ' ; Clr:LightCyan),
     (C: ' { ' ; Clr:LightGreen),
     (C: ' ; ' ; Clr:LightCyan),
     (C: ' ' ; Clr:Black)
     );

Создание магического предмета будет происходить в процедуре генерации карты

  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

    itemAmmo: GetItemName := Itm.Name + ' ( ' +IntToStr(Itm.Ints[intAmmo])+ ' ) ' ;

    itemRangedWeapon:
              GetItemName := Itm.Name +
  ' ( ' +IntToStr(Itm.Ints[intRangedAmmo])+ ' ) ' ;

   itemMagik: begin
              GetItemName := MagikItemsName[ Itm.Ints[intMagikType] ] + '
  ( ' +IntToStr(Itm.Ints[intMagikNum])+ ' ) ' ;
              end;

  else GetItemName := Itm.Name
  end;
  end;

Теперь нам надо научиться предмет использовать. Пусть он "используется", когда мы выбираем его в инвентаре. Для этого дополним процедуру 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;

      if f then
         MonstersStep;
  end;

  { ----------------- }
  procedure MakeHealing;
  begin
   dec(Heroes[CurHero].Mana);
   IncHP(Heroes[CurHero], +1);
   ShowInfo(STR_SELFHEALING);
  end;

В них просто выделена часть, ответственная за реализацию огненного шторма и исцеления. Эту часть и будем вызывать при выборе соответствующего предмета:

  case Heroes[CurHero].Items[ni].Ints[intMagikType] of

    mintStorm, mintStormStf :
       begin
       MakeFireStorm;
       end;

    mintHealing, mintHealingStf:
       begin
       MakeHealing;
       end;

  end;

В заключение надо будет снизить число использований предмета и в ряде случаев - удалить сам предмет из инвентаря:

  ...
  dec(Heroes[CurHero].Items[ni].Ints[intMagikNum]);

  if Heroes[CurHero].Items[ni].Ints[intMagikNum] <= 0 then
     Heroes[CurHero].Items[ni].IType := itemNone;

  end;

На этом часть механизма игры, ответственную за магию, будем считать законченной.

Что дальше? Торговля!


Исходный код текущей версии для Turbo Pascal (всегда проверен и работоспособен, главный файл - main.pas):

http://russianenterprisesolutions.com/sbo/download/3116.zip 13661 байтов


(c) 2004-2006 Сергей Бобровский bobrovsky@russianenterprisesolutions.com

Школа программирования с нуля
Все предыдущие выпуски базового курса тут:
http://russianenterprisesolutions.com/sbo/

Дизайн рассылки: Алексей Голубев - Web-дизайн и web-программирование


Subscribe.Ru
Поддержка подписчиков
Другие рассылки этой тематики
Другие рассылки этого автора
Подписан адрес:
Код этой рассылки: comp.soft.prog.prognull.game
Архив рассылки
Отписаться Вебом Почтой
Вспомнить пароль

В избранное