52
Приспособленец (Flyweight) —
Паттерны программирования игр
это объясняется тем, что в приведенном примере мы мо-
жем четко
определить
общее состояние:
TreeModel
.
Мне кажется использование этого паттерна менее
очевидным (и, следовательно, более хитрым) в случаях,
когда для объектов не существует явно определенных
общих свойств. Тогда создается ощущение, что объект
магическим образом находится в нескольких местах од-
новременно. Позвольте мне показать вам еще один при-
мер.
Место, чтобы пустить корни
Землю, на которой растут наши деревья, также нуж-
но отобразить в игре. На ней могут быть клочки травы,
грязь, холмы, озера, реки и любая другая местность, ко-
торую вы только можете себе представить. Мы сделаем
землю состоящей из тайлов (tile — тайл, плитка): по-
верхность мира будет представлять собой огромную сет-
ку из небольших квадратных плиток — тайлов. Каждый
тайл относится к какому-либо одному типу местности.
Каждый тип местности имеет ряд свойств, влияющих
на процесс игры:
• стоимость перемещения, которая определяет, как
быстро игрок движется по нему;
• флаг, определяющий, что это водная местность,
по которой можно передвигаться на лодке;
• текстура, используемая для визуализации.
Поскольку мы, разработчики игр, параноидально от-
носимся к эффективности, мы не можем хранить всю ин-
формацию о состоянии в каждом тайле игрового мира.
Вместо этого обычно используется подход с объявлением
перечисления для типов местности:
enum Terrain
{
TERRAIN_GRASS,
TERRAIN_HILL,
В конце концов, мы уже
усвоили урок с этими
деревьями.
Паттерны программирования игр
— Другой взгляд на паттерны проектирования
53
TERRAIN_RIVER
// …
};
Таким образом, игровой мир состоит из огромной
сетки такого вида:
class World
{
private:
Terrain tiles_[WIDTH][HEIGHT];
};
А чтобы получить полезные данные о тайле, мы дела-
ем следующее:
int World::getMovementCost(int x, int y)
{
switch (tiles_[x][y])
{
case TERRAIN_GRASS: return 1;
case TERRAIN_HILL: return 3;
case TERRAIN_RIVER: return 2;
// '…
}
}
bool World::isWater(int x, int y)
{
switch (tiles_[x][y])
{
case TERRAIN_GRASS: return false;
case TERRAIN_HILL: return false;
case TERRAIN_RIVER: return true;
// …
}
}
Ну вы поняли идею. Работает, но, на мой взгляд, ужас-
но. Я думаю о стоимости перемещения и влажности как
о свойствах ландшафта, но, по сути, сейчас они жест-
ко закодированы («захардкожены»). Хуже того, данные
для одного типа ландшафта размазаны по множеству
Здесь я использую дву-
мерный массив для хра-
нения 2D-сетки. Он эф-
фективен в языках C/
C++, поскольку группи-
рует все элементы вме-
сте. В Java или других
языках, в которых ис-
пользуется иное управ-
ление памятью, такой
прием даст вам фактиче-
ски массив строк, где
каждый элемент явля-
ется
ссылкой
на массив
столбцов, что может
быть не столь эффек-
тивно в плане использо-
вания памяти, как вам
хотелось бы.
В любом случае в коде
реального проекта
лучше скрыть эту деталь
реализации за хорошей
структурой данных
2D-сетки. Здесь я делаю
так, исключительно же-
лая сохранить код про-
стым.
Do'stlaringiz bilan baham: |