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

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

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

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

Урок 16. Одеваем предметы из рюкзака, бросаем и подбираем Письма.

Урок 16. Одеваем предметы из рюкзака, бросаем и подбираем Письма.

Основываясь на своем опыте, хотелось бы внести ряд предложений:

Если представить карту в виде массива ссылок, то ограничения на размер в ДОС полностью снимаются. Точнее в ТР6 они составят что-то около 1М (в незащищенном режиме).

Предметы (их свойства), монстров (их хар-ки), описание героев лучше держать во внешних файлах (например, стандартных БД). Это позволит сразу абстрагироваться от данных и сосредоточиться на алгоритмах работы.

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

Рюкзак (торба, баул) героя могут увеличивать размеры, менять форму (в зависимости от потребностей) и т.п. Имеет смысл выделить отдельный объект

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

Вспомним еще раз, что версия, описываемая в данной рассылке - учебная. Я же об этом писал, и в контексте про два слота в частности smile А уж вы сами на базе изученного сможете что угодно сделать свое. И, воспользоваться правильными советами

Так же замечу, что параллельно с Вами делаю РПГ-игру на Visual C++. У меня многое поменялось, в частности, адрес почтового ящика :). Сама же игра тоже обновилась. Монстры научились бегать, типов монстриков стало больше, увеличилось кол-во артефактов, появились ловушки и источники жизни. И захотел все перенести на код текущей версии. Достал со школьного компьютера Borland Pascal, добавил в него Main.pas, и сразу наткнулся на ошибку невозможности найти файл. После удаления всех директив препроцессора, программа заработала smile . Но появились "крякозяблики". Практически сразу стало понятно: все тексты реализованы в win кодировке. Но, как я понимаю, это все-таки программа для dos? Надеюсь в дальнейшем таких казусов не будет smile .

Про кодировку я тоже писал, - в соответствующем месте smile - что она в win-формате, и нужно переделывать. Так что тем, кто хочет просто "посмотреть на "код текущей статьи рекомендуется посмотреть и текст текущей версии рассылки :)

За файл Defines.inc, СПАСИБО! Добавлен этот файл в текущий код. Я обычно архив …

Достаем предметы из рюкзака

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

Procedure ShowHeroItems;

Var I,n:integer;

Begin

  While true do

  Begin

 

  …(1,1);

  …_Hero_Itmes);

  For i:=1 to MaxHeroItems do

  Begin

  …(…, i+2);

  If Heroes[CurHero].Items[i].IType=itemNone then Write(i, ‘ ) ’ , STR_EMPTY_ITEM)

  Else Write (i, ‘ ) ’ , Heroes[CurHero].Items[i].Name);

End;

end;

GoToXY(1,2 0);   Write (   '   >   '   );

ReadLn(n);   if n  =   0   then  Break

end;

ShowGame;

end;

Что надо делать при выборе пользователем определенного элемента рюкзака? Необходимо проверить, как и в случае с ShowHeroSlots, не пустой ли это элемент, а также выяснить, имеются ли подходящие для предмета и свободные слоты. Последнюю задачу будет решать функция GetFreeSlot, параметром которой выступит предмет. Функция определит, есть ли у героя подходящий слот, проверив заодно допустимость перемещения - ведь меч нельзя надеть на голову, а броню использовать как оружие. Разместим функцию в модуле Неrо:

function  GetFreeSlot(   var  H:   THero;   Itm:   TGameltem   ):   Integer;

var  i:   Integer;

begin

GetFreeSlot   :=   0;

for  i   :=   1   to MaxSlots   do

if   (II. Slots [i] .IType   =  itemNone)   and  GoodSlot (i, Itm)   then begin

GetFreeSlot   : =   i; Exit end;

end;

 

В ней происходит перебор слотов персонажа, и при нахождении свободного слота (свойство IType имеет значение, отличное от itemNone) выполняется дополнительная проверка -допустимо ли поместить данный предмет в слот с индексом i (эти индексы мы обозначили константами с префиксом "slot"; так, слот тела имеет значение индекса slotBody, равное единице). Такую проверку в соответствии с принципами проектирования "сверху-вниз" вынесем в новую фуанкцию GoodSlot, размещенную в этом же модуле:

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

begin

GoodSlot := false;

case Slot of slotBody : GoodSlot •= Itm.IType in [itemArmor]; slotHands: GoodSlot := Itm,IType in [itemHandWeapon];

end;

end;

Для каждого значения переменной Slot проверим, подходит ли тип предмета назначению данного слота. На тело героя (slotBody) можно одевать предметы типа "броня" (itemArmor), в руки (slotHands) можно брать ручное оружие (itemHandWeapon). Значения itemArmor и itemHandWeapon вынесены в константы-множества, чтобы данные проверки можно было легко расширять и дополнять. Например, если мы добавим дальнобойное оружие, то соответствующая проверка перепишется так:

slotHands:   GoodSlot   :=   Itm.IType   in   [itemHandWeapon, itemRangedWeapon];

При добавлении предметов-плащей (накидок на тело) изменится другая проверка:

slotBody   :   GoodSlot   :=   Itm.IType  in   [itemArmor,   itemCloack];

И так далее.

Теперь определим, что будет делать программа, когда человек выбрал в рюкзаке предмет для одевания. Этот предмет надо скопировать из массива Items в массив Slots, удалив затем его из рюкзака.

Procedure ShowHeroItems ;

Var I,n:integer;

Begin

While true do

Begin

…_Hero_Items);

For i:=1 to MaxHeroItems do

Begin

..ToXY(I, i+2);

If Heroes[CurHero].Items[i].IType=ItemNonel

then Write(i, ‘ ) ’ , STR_EMPTY_ITEM)

Else Write (i, ‘ ) ’ , Heroes[CurHero].Items[i].Name);

End;

…(1,20);

Write(‘>’);

If n=0 then break;

… FreeSlot(Heroes[CurHero], Heroes[CurHero].Items[n]);

If n>0 then

Begin

Heroes[CurHero].Slots[s]:=Heroes[CurHero].Items[n];

Heroes[CurHero].Items[n]:=IType:=itemNone;

End;

End;

SHowGame;

End;

Пришло время попрактиковаться в перемещении предметов между рюкзаком и слотами героя. ShowHeroItems/ShowHeroSlots вводят команды пользователя с помощью оператора Паскаля RеadLn. При этом введенное в локальную переменную n значение проверяется как на логическую корректность (оно должно укладываться в определенные диапазоны массивов Slots/Items), так и на синтаксическую правильность. Если мы попробуем ввести строку типа "абв", программа аварийно завершится со сопровождающей ошибкой 106 системы Turbo Pascal (Invalid numeric format, неверный формат). Поэтому читателю предлагается самостоятельно укрепить этот слабый участок кода. Можно например, реализовать собственный миниатюрный текстовый редактор, обрабатывающий нажатия клавиш, отображающий их на экране и допускающий простейшие действия.

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

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

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

procedure ShowHeroItems;     

var i,n,s: Integer;

begin

while true do

begin

ClrScr;

GoToXY(l,l);

Write(STR_HERO_ITEMS);

for i := 1 to MaxHeroItems do

begin

GoToXY(l,i+2);

if  Heroes[CurHero].Items[i].IType  =   itemNone

then Write(i,    '   )    '    ,STR_EMPTY_ITEM)

else  Write(i,    '    )    '   ,Heroes[CurHero].Items[i].Name)

end; GoToXY(1,201;   Write(   *   >   '    );

ReadLn(n);  

if  n  =   0   then

break;

if  n  >  0   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

else

begin

s   := GetFreeltemNum; if  s   >   0   then

begin

Items[s]    := Heroes[CurHero].Items[abs(n)];

Items[s].x   :=  Heroes[CurHero].x;

Items[s].y   :=   Heroes[CurHero].y;

Heroes[CurHero].Items[abs(n)].IType   :=   itemNone;

end;

end;

end;

ShowGame;

end;

Если введенное значение положительно, выполняются ранее запрограммированные действия. Если оно отрицательно, значит, нам надо переместить выбранные предмет на землю, то есть убрать его из рюкзака и добавить в глобальный массив Items из модуля Gameltem, откорректировав при этом координаты предмета (поля х и у). Отрисовка положенного на землю предмета на карте выполнится автоматически в процедуре ShowGame (точнее, в процедуре Showltems, вызываемой из нее). Определение свободного места в массиве расположенных на карте предметов происходит в функции GetFreeltemNum. Ее в соответствии с предназначением надо реализовать в модуле Gameltem:

function  GetFreeltemNum:   Integer;

var  i:   Integer;

begin

GetFreeltemNum   :=   0;

for  i   :=   1  to MaxItems  do

if Heroes[i].IType  =   itemNone  then

begin

ItemNum    :=   i;

End;

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

Очевидного выхода из такой ситуации нет. Можно только создавать массив Items с достаточно солидным запасом, что возможно при варианте игры в среде Windows.

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

Создадим процедуру – назовем ее GetltemFromMap, будет вызываться при нажатии на клавишу g. Размещаем процедуру в модуле Main):

While true do

Begin

…;

I:=readkey;

Case I of

‘g’: GetItemFromMap;

Начинается ее реализация (модуль Hero):

Procedure getItemFromMap;

Var I,n:integer;

Begin

…FreeBag(Heroes[CueHero]);

If n=0 then exit;

For i:=1 to MaxItems do

If (Heroes[CurHero].x=Items[i].x)

and (Heroes[CurHero].x=Items[i].x) then

begin

Heroes[CurHero].Items[n]:=items[i];

Items[i].IType:=itemNone;

(//lt)…

End;

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

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

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

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

Первое недоразумение устраним так. Добавим в процедуру GetltemFromMap информационное сообщение, извещающее человека о том, что с земли поднят некий

предмет.Константа STR_GETITEM может быть описана в модуле Texts так:

const  STR_GETITEM =   '   Вы подобрали   '    ;

Второе недоразумение решается не менее просто. Достаточно добавить оператор обнуления поля х освобождаемого элемента массива Items:

procedure  GetltemFromMap;

var  i,   n:   Integer;

begin

n   :=  GetFreeBag(Heroes[CurHero]);

if n =  0   then  Exit;

for  i   :=   1  to Maxltems do

if   (Heroes[CurHero].x  =   Items[i].x)   and (Heroes[CurHero].у =  Items[i].у)   then

begin

Showlnfo(   STR__GETITEM  +   Items [i] . Name   );

Heroes[CurHero].Items[n]    :=   Items[i];

Items[i].IType   :=  itemNone;

Items[i].x   :=  0;

Exit

end;

end;

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

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

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

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