游戏中的享元模式

“使用共享以高效地支持大量地细粒度对象。”

比如森林,有很多树,成千上万个,这些树对象实例有很多共同的内容,比如 材质 纹理,所有树木通用的数据放到一个单独的类中

class TreeModel
{
private:
    Mesh mesh_;
    Texture bark_;
    Texture leaves_;
};

树类

class Tree
{
private:
    TreeModel* model_;
    Vector position_;
    double height_;
    double thickness_;
    Color barkTint_;
    Color leafTint_;
};

这样大量的树公用一个Model对象,节省了非常多的空间。在客户端GPU渲染中,就需要这样配合。

还有比如瓦片地图的地形,可以这样做。

enum Terrain
{
    TERRAIN_GRASS,
    TERRAIN_HILL,
    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;
        // ...
    }
}

封装为地形类

class Terrain
{
public:
 Terrain(int movementCost, bool isWater,
     Texture texture)
 : moveCost_(moveCost),
  isWater_(isWater),
  texture_(texture)
 {}

 int getMoveCost() const { return moveCost_; }
 bool isWater() const { return isWater_; }
 const Texture& getTexture() const 
 { 
 return texture_; 
 }

private:
 int moveCost_;
 bool isWater_;
 Texture texture_;
};

然后在World中存 Terrain 的实例的地址就行了,多个位置公用一个实例

class World
{
public: 
 World()
 : grassTerrain_(1, false, GRASS_TEXTURE),
  hillTerrain_(3, false, HILL_TEXTURE),
  riverTerrain_(2, true, RIVER_TEXTURE)
 {
    //...
  }

private:
 Terrain grassTerrain_;
 Terrain hillTerrain_;
 Terrain riverTerrain_;
  Terrain* tiles_[WIDTH][HEIGHT]; 
};

对World实现一些操作 如生成地形,获取某一位置瓦片,

void World::generateTerrain()
{
 // Fill the ground with grass.


 for (int x = 0; x < WIDTH; x++)
 {
  for (int y = 0; y < HEIGHT; y++)
  {
  // Sprinkle some hills.


   if (random(10) == 0)
   {
    tiles_[x][y] = &hillTerrain_;
   }
   else
   {
    tiles_[x][y] = &grassTerrain_;
   }
  }
 }

 //Lay a river
 int x = random(WIDTH);
 for (int y = 0; y < HEIGHT; y++) {
  tiles_[x][y] = &riverTerrain_;
 }
}


const Terrain& World::getTile(int x, int y) const
{
 return *tiles_[x][y]; 
}

就像这样使用

int cost = world.getTile(2, 3).getMovementCost();

从空间和时间上看,开销都很低。