수많은 나무들이 숲을 이루고 있는 장면은 경량 패턴으로 구현한다.
수천 그루의 나무(각 수천 폴리곤)를 표현하기 위해서는 메모리와 CPU->GPU 전달량이 충분해야 한다.
여기서 나무의 데이터에는 메시, 텍스처, 위치, 높이 등이 있을 것이다.
class TreeModel {
private:
Mesh mesh_;
Texture bark_;
Texture leaves_;
};
class Tree {
private:
TreeModel* model_;
Vector position_;
double height_;
double thickness_;
}
숲의 나무들은 다 비슷해보이므로, 모든 나무를 같은 메시와 텍스처로 표현하도록 하면 나무 객체의 메시, 텍스처 등은 인스턴스마다 동일하게 된다.
각 나무 인스턴스가 TreeModel
객체를 참조하도록 하면 메모리를 아낄 수 있다.
다음으로는 렌더링을 위해 데이터를 CPU->GPU로 보내는 데이터 양을 최소화해야 한다.
TreeModel
)를 딱 한 번만 전달이러한 기능은 이미 인스턴싱으로 지원하고 있다.
경량 패턴은 객체의 개수가 너무 많을 때 가볍게 하기 위해 사용한다.
객체 데이터는 고유 상태(=자유 문맥)과 외부 상태로 나눌 수 있다.
이번엔 땅을 표현해보자!
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;
}
}
위 코드의 문제점
1. 이동 비용, 물 여부 등 지형에 관한 데이터를 하드코딩
2. 지형 종류에 대한 데이터가 여러 메소드(getMovementCost
, isWater
)로 나뉘어 있음
-> 지형 데이터를 캡슐화하자!
class Terrain {
public:
Terrain(int movementCost, bool isWater, Texture texture)
: movementCost_(movementCost),
isWater_(isWater),
texture_(texture) {}
int getMovementCost() {return movementCost_;}
bool isWater() const {return isWater_;}
const Texture& getTexture() const {return texture_;}
private:
// 고유 상태
int movementCost_;
bool isWater_;
Texture texture_;
};
지형 데이터를 캡슐화를 위해 지형 클래스 선언
Terrain grassTerrain_;
Terrain hillTerrain_;
Terrain riverTerrain_;
각 지형별로 객체는 하나씩만 있으면 되므로 World
클래스에 각 지형을 나타내는 Terrain
인스턴스를 만든다.
Terrain* tiles_[WIDTH][HEIGHT];
그리고 각 타일이 해당 지형의 인스턴스 포인터를 갖게 한다.
const Terrain& World::getTile(int x, int y) const {
return *tiles_[x][y];
}
int cost = world.getTile(2, 3).getMovementCost(); // getMovementCost는 Terrain의 메소드
이렇게 해당 타일의 지형 정보를 Terrain
참조자로 리턴하면, 전과 달리 해당 타일의 지형 정보를 World
의 메서드가 아닌 Terrain
메서드에서 얻게 된다.
즉, World
클래스와 지형의 정보가 디커플링되었다.
경량 패턴이 열거형보다 느릴 거란 걱정을 하기 전에,
열거형을 선언해서 수많은 switch문을 만들기보다는 일단 경량 패턴을 사용해보자