Changyu Lee

GPP - Part 1. GoF’s Design Patterns - 2) Flyweight Pattern

Published at
2024/02/10
Last edited time
2024/03/01 10:04
Created
2024/02/10 12:09
Section
Unity
Status
Done
Series
Tags
Theory
AI summary
Keywords
Design Pattern
Game Programming Pattern
SW ENG Theory
Language

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.