Паттерны программирования игр
— Паттерны поведения
259
гарантируем, что все монстры пройдут через нужную
нам схему управления памятью.
Разделение данных через наследование
На данный момент у нас на руках весьма пригодная си-
стема типов объектов, но все же достаточно простая.
В конце концов в нашей игре будут
сотни
родов, а в каж-
дом — десятки свойств. И если геймдизайнеру захочется
изменить все тридцать разновидностей троллей, сделать
их чуть сильнее, придется убить уйму времени на ввод
новых данных.
Нам могла бы помочь возможность совместного вла-
дения некоторыми свойствами для нескольких
родов
,
как род позволяет нам использовать совместное владе-
ние свойствами для разных
монстров
. Решить эту за-
дачу можно с помощью наследования. Только вместо
использования встроенного в язык механизма наследо-
вания мы реализуем собственный через наши объекты
типов.
Для простоты в нашей игре будет поддержка только
одного уровня наследования. У класса может быть роди-
тельский класс, а у рода — родительский род:
class Breed
{
public:
Breed(Breed* parent, int health,
const char* attack)
: parent_(parent),
health_(health),
attack_(attack)
{}
int getHealth();
const char* getAttack();
private:
Breed* parent_;
int health_; // 6 .
const char* attack_;
};
260
Объект типа (Type Object) —
Паттерны программирования игр
Когда мы конструируем род, мы указываем его роди-
теля, от которого он наследует. Мы можем указать зна-
чение
NULL
для базового рода, не имеющего предков.
Чтобы извлечь из ситуации максимум пользы, дочер-
ний элемент рода должен иметь выбор, какие свойства
наследовать от родителя, а какие — переопределять или
задавать самостоятельно. Пусть в нашей системе род
переопределяет показатель здоровья, если он не равен
нулю, и строку атаки, если она имеет значение не
NULL
.
Иначе он будет наследовать эти значения.
Существует два способа. Первый — обрабатывать на-
следование динамически, каждый раз, когда происхо-
дит обращение к свойству. Примерно так:
int Breed::getHealth()
{
// .
if (health_ != 0 || parent_ == NULL)
{
return health_;
}
// ? .
return parent_->getHealth();
}
const char* Breed::getAttack()
{
// .
if (attack_ != NULL || parent_ == NULL)
{
return attack_;
}
// ? .
return parent_->getAttack();
}
Способ будет работать корректно, даже если во время
выполнения род был изменен так, чтобы больше не на-
следовать или не переопределять какое-то свойство. Од-
нако он требует немного больше памяти (необходимо
Do'stlaringiz bilan baham: |