Паттерны программирования игр
— Паттерны оптимизации
417
Код объемный, но довольно примитивный. Первая
часть проверяет, пересек ли юнит границу ячейки. Если
нет, то нужно только обновить его позицию.
Если он покинул текущую ячейку, мы удаляем его
из связанного списка ячейки и добавляем обратно в сет-
ку. Как при добавлении нового юнита, он добавится
в начало связанного списка своей новой ячейки.
Вот почему мы используем двусвязный список — мы
можем очень быстро добавлять и удалять предметы
из списка, просто переназначая указатели. Если каждый
кадр перемещается большое количество юнитов, это мо-
жет быть важно.
На расстоянии вытянутой руки
Кажется довольно просто, но в одном месте я сжульни-
чал. В примере я демонстрировал взаимодействие юни-
тов только в одной ячейке. Это сработает для шашек
и шахмат, но не для более реалистичных игр. Там обыч-
но надо учитывать
дальность
атаки.
Паттерн все еще подходит. Но вместо проверки на со-
впадение положения, мы сделаем иначе:
if (distance(unit, other) < ATTACK_DISTANCE)
{
handleAttack(unit, other);
}
Когда мы учитываем дальность атаки, появляется
пограничный случай, который надо рассмотреть: юни-
ты из разных ячеек находятся достаточно близко, чтобы
взаимодействовать.
Рис. 20.4.
Так близко, но так далеко
418
Пространственное разбиение (Spatial Partition) —
Паттерны программирования игр
Здесь В находится в радиусе поражения А, хотя их
центры расположены в разных ячейках. Чтобы решить
эту проблему, нам надо сравнивать юниты не только
в пределах одной ячейки, но и в соседних ячейках тоже.
Вынесем метод
handleCell()
из внутреннего цикла:
void Grid::handleUnit(Unit* unit, Unit* other)
{
while (other != NULL)
{
if (distance(unit, other) < ATTACK_DISTANCE)
{
handleAttack(unit, other);
}
other = other->next_;
}
}
Сейчас у нас есть функция, которая берет юнит из од-
ной ячейки и список юнитов из других и смотрит, есть ли
кто-то в радиусе поражения. Затем мы заставим метод
handleCell()
использовать следующее:
void Grid::handleCell(int x, int y)
{
Unit* unit = cells_[x][y];
while (unit != NULL)
{
// 733 6.
handleUnit(unit, unit->next_);
unit = unit->next_;
}
}
Обратите внимание: мы передаем координаты ячей-
ки, а не только список юнитов. Прямо сейчас не проис-
ходит ничего нового по сравнению с предыдущим при-
мером, так что мы немного его расширим:
void Grid::handleCell(int x, int y)
{
Unit* unit = cells_[x][y];
while (unit!= NULL)
Do'stlaringiz bilan baham: |