Part 1. 2) Flyweight Pattern
Flyweight Pattern
•
Key Idea: Sharing → efficient memory supporting Find-grained Instances
Example
•
Instanced Rendering :
◦
Suppose we are making the game scene at which thousands of trees, each with detailed geometry containing thousands of polygons, are standing with each different details.
▪
A mesh of polygons taht define the shape of the trunk, branches, and greenery
▪
Textures for the bark and leaves
▪
Its location and orientation in the forest
▪
Tuning parameters like size and tint so that each tree looks different
•
Sketch Code
class Tree
{
private:
Mesh mesh_;
Texture bark_;
Texture leaves_;
Vector position_;
double height_;
double thickness_;
Color barkTint_;
Color leafTint_;
};
C++
복사
•
We can save memory and minimize data if each instance of a tree in the world has a reference to that shared TreeModel
class Tree
{
private:
TreeModel* model_;
Vector position_;
double height_;
double thickness_;
Color barkTint_;
Color leafTint_;
};
C++
복사
•
Both Direct3D and OpenGL offers instanced rendering.
•
In both APIs, you provide two streams of data.
◦
The first is the blob of common data that will be rendered multiple times
◦
The second is the list of instances and their parameters that will be used to vary that first chunk of data each time it’s drawn.
Implement Example:
•
Terrains
•
Before
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;
// Other terrains...
}
}
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;
// Other terrains...
}
}
C++
복사
•
After
class Terrain
{
public:
Terrain(int movementCost,
bool isWater,
Texture texture)
: movementCost_(movementCost),
isWater_(isWater),
texture_(texture)
{}
int getMovementCost() const { return movementCost_; }
bool isWater() const { return isWater_; }
const Texture& getTexture() const { return texture_; }
private:
int movementCost_;
bool isWater_;
Texture texture_;
};
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]; //with Pointer
// Other stuff...
};
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];
}
// Get Movement Cost of the specific Tile
int cost = world.getTile(2, 3).getMovementCost();
C++
복사
Some Issues are here:
•
C# has Pointer but doesn’t recommend to use them.
◦
C# treats the pointer as unsafe codes.
•
Answer: Singleton / Factory Pattern & Static Member !
•
Example
◦
Terrain & World
▪
Case 1: Using Singleton Pattern (Written by Chan)
public class Terrain
{
protected int movementCost;
protected bool isWater;
protected Texture texture;
public Terrain(int cost, bool isWater, Texture texture) {
this.movementCost = cost;
this.isWater = isWater;
this.texture = texture;
}
}
public class World
{
private static Terrain grassTerrain = new Terrain(1,false, GRASS_TEXTURE);
private static Terrain hillTerrain = new Terrain(3, false, HILL_TEXTURE);
private static Terrain riverTerrain = new Terrain(2, true, RIVER_TEXTURE);
private static World world;
Terrain[,] tiles;
public World() {}
public static World GetWorld()
{
if (world == null) {
world = new World();
}
return world;
}
public static Terrain[,] GetTiles()
{
return world.tiles;
}
public void GenerateTerrain(WIDTH, HEIGHT)
{
tiles = new Terrain[WIDTH, HEIGHT];
Random random = new Random();
// Fill the ground with grass.
for (int x = 0; x < WIDTH; x++)
{
for (int y = 0; y < HEIGHT; y++)
{
// Sprinkle some hills.
if (random.Next(10) == 0)
{
tiles[x,y] = hillTerrain;
}
else
{
tiles[x,y] = grassTerrain;
}
}
}
}
public Terrain GetTile(int x, int y)
{
return tiles[x,y];
}
}
//Main
var world = World.GetWorld()
world.GenerateTerrain(4,3);
var tile = world.GetTile(3,2);
C#
복사
▪
Case 2: Factory Pattern + Singleton Pattern (Written by Chan)
public class TerrainFactory
{
private static Terrain grassTerrain = new Terrain(1, false, GRASS_TEXTURE);
private static Terrain hillTerrain = new Terrain(3, false, HILL_TEXTURE);
private static Terrain riverTerrain = new Terrain(2, true, RIVER_TEXTURE);
public static Terrain CreateGrassTerrain()
{
return grassTerrain;
}
public static Terrain CreateHillTerrain()
{
return hillTerrain;
}
public static Terrain CreateRiverTerrain()
{
return riverTerrain;
}
}
public class World
{
private static World world;
private Terrain[,] tiles;
private World() { }
public static World GetWorld()
{
if (world == null)
{
world = new World();
}
return world;
}
public Terrain[,] GetTiles()
{
return tiles;
}
public void GenerateTerrain(int width, int height)
{
tiles = new Terrain[width, height];
Random random = new Random();
// Fill the ground with grass.
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
// Sprinkle some hills.
if (random.Next(10) == 0)
{
tiles[x, y] = TerrainFactory.CreateHillTerrain();
}
else
{
tiles[x, y] = TerrainFactory.CreateGrassTerrain();
}
}
}
}
public Terrain GetTile(int x, int y)
{
return tiles[x, y];
}
}
C#
복사
▪
Static Varialbes: Loaded just once into memory when the Class which has the variables is firstly loaded in runtime.
Summary
•
Flyweight Pattern is an optimization strategy using shared memory for fine-grained objects (instances).
•
C# utilize Singleton / Factory Pattern and static members for implementing the Flyweight Pattern
Reference
This contents are originated from “Game Programming Patterns”, Robert, Hanbit Media Inc. (Korean Version)
The below is Author’s Official Website and it has Web Version of the book.