Представление объектов

Материал из Клуб любителей рогаликов
Перейти к: навигация, поиск

Данная статья была написана для RLNews Darren'а Hebden'а

Представление объектов в roguelike-играх. Действительно, трудновыполнимая вещь. Когда я начал War of the Runes, я был не точно уверен как, это сделать. Будет ли всё жёстко закодировано в игру? Будут ли объекты гибкими? Какие типы различных объектов должны быть представлены?

Хорошо, для начала, я знал, что я не хочу, чтобы что-нибудь было жёстко прописано. Одной из особенностей War of the Runes является то, что ВСЁ должно быть способно изменяться. Так что объекты, которые должны сохраняться во внешних файлах и все описания объекта должны сохраняться; и описание, и поведение, и свойства. И это также означает, что все объекты должны быть гибкими, состояние объекта может измениться в любое время множеством любых способов. И какие будут типы объектов? Есть оружие и доспехи, пища и напитки, двери, ящики (клады), мешки, кольца, книги - всё, что может существовать в реальном мире.

Ну и какой наилучший путь представления объектов в roguelike-играх? Хорошо, сначала нам нужно начать с класса объектов:

class Object {
public:

Какой тип данных нам нужен для объектов? Для начала, нам нужно знать что это за объект. Мы можем сделать это с помощью имени и описания;

char *Name, *Desc;

Это не требует разъяснений. Также будет полезна информация о том, где находится объект:

int X, Y;

Во вселенной roguelike-игр есть много других объектов. Доспехи, оружие, книги, кольца, снадобья и т.п. Каждый объект может быть только одного типа.

int ObjType;

Это поле будет установливаться в величину, которую мы определяем с помощью #define.

#OBJ_WEAPON 1
#OBJ_ARMOR 2
#OBJ_POTION 3

У вас есть идея. Каждый определённый тип объекта в игре должен иметь определённый номер. Это поможет во МНОГИХ случаях. Например, персонажи могут надевать на себя только предметы типа 2 (доспехи).

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

Мы должны установить область имени (Name), чтобы указывать на "длинный меч" ("long sword"). Достаточно просто. Область описания (Desc) должна быть "длинный, острый, металлический стержень" ("a long, sharp, metal stick"). Хорошо, вы можете захотеть использовать что-нибудь помимо этого.

Координаты X,Y можно установить... скажем 2,10.

Как насчет типа объекта (object type)? 1 (OBJ_WEAPON) разумеется!

Что теперь? Что делает длинный меч? Игра знает, что это оружие, но игре требуется больше, чем эта информация.

Давайте сделаем класс, который определяет, что делает объект.

class ObjArg {
public:

Каждый ObjArg будет определять один аспект объекта. Нам нужен способ сохранять каждое из определений ObjArg.

int ArgType;

Мы дадим это значение путём использования большего количества определений.

#define OARG_ATTACK 1
#define OARG_DEFEND 2
#define OARG_HEAL 3

Итак, мы знаем, что определяет ObjArg. Теперь нам нужно сохранить данное определение. Мы сделаем это путём определения массива из 5 целых чисел.

int Args[5];

И всё это входит в класс ObjArg. Значение области массива Args будет зависеть от величины ArgType.

Теперь мы хотим, чтобы каждый объект был красивым и разносторонним, поэтому мы сделаем так, что каждый объект имеет 5 классов ObjArg.

} Defines[5];

И это всё, что нам необходимо для базового класса Object

};

Так как работает класс ObjArg? Хорошо, для нашего длинного меча, нам нужен только один аргумент - ArgType, который будет установлен в OARG_WEAPON. Теперь как насчет массива Args? Скажем, для ArgType 1 (оружие), первая область Args является количеством бросков кубика повреждений (damage dice), вторая область - количеством сторон за бросок, третья область является модификатором повреждений и четвертая область является модификатором навыка персонажа. Пятая область будет неиспользованной.

Так, если мы хотим чтобы длинный меч наносил от 1 до 8 повреждений без дополнительных модификаторов повреждения или навыка атаки (attack skill). Итак...

Args[0] = 1
Args[1] = 8
Args[2] = 0
Args[3] = 0

Теперь если персонаж вооружён длинным мечом и атакует, мы сначала проверим, какой тип объекта в руках персонажа. Мы видим, что область ObjType установлена в значение 1 (оружие). OK, он/она может атаковать этим объектом. Теперь мы просмотрим массив Defines, пока не найдем вход ObjArg чей ArgType установлен в значение 1 (атака). Игра видит, что Defines[0].ArgType = 2, так что мы используем этот ObjArg, для того чтобы найти статистику оружия. Игра проверяет Defines[0].Args[3] = 0, так что модификатора навыка нет. Игра сделает это независимо от того, какая боевая система и определяет силу удара персонажа (character hit). Она проверяет ущерб (Args fields 0, 1, 2) и видит что длинный меч наносит повреждения 1d8+0. Игра случайным образом определяет ущерб, ранит цель, и т.п.

Ну вот и всё, что вам нужно для простых объектов. Хотя, вы можете сделать ГОРАЗДО больше, используя образец кода, данный мной здесь как базовый. Например, некоторые ObjArgs будут в силе всякий раз, когда бы предмет не использовался (область атаки длинного меча, или область защиты доспехов). Некоторые объекты, подобно снадобьям, не действуют до тех пор, пока персонаж не использует объект (или в случае объектов с ObjType = 3, пока персонаж не выпьет зелье). Только потом вступят в силу их области ObjArg (подобно лечению (healing), в случае снадобья лечения (potion of healing)). Также вы можете захотеть сохранять сколько раз предмет может быть использован, и сколько раз он использовался.

Полный код для класса Object:

#define OBJ_WEAPON 1
#define OBJ_ARMOR 2
#define OBJ_POTION 3

#define OARG_ATTACK 1
#define OARG_DEFEND 2
#define OARG_HEAL 3

class Object {
public:

char *Name, *Desc;

int X, Y;

int ObjType;

class ObjArg {
public:

   int ArgType;

   int Args[5];
} Defines[5];
};

Если у вас возникли какие-нибудь вопросы, свободно задавайте мне их по e-mail'у sean.middleditch@iname.com

Конец.



Автор: Sean Middleditch.
Источник: Object Representation.
Перевел: Дмитрий О. Бужинский [Bu], 23.05.2005.