[디자인 패턴] #9_업데이트 패턴, Update Pattern
게임 디자인 패턴 중 "순서 패턴"에 대해 알아보겠습니다.
"게임 프로그래밍 패턴"의 10 항목, "업데이트 메서드"에 해당하는 내용입니다.
업데이트 패턴
1. 개념
* 개념
: 객체 컬렉션에 들어 있는 객체별로 한 프레임 단위의 작업을 진행하라고 "알려줘서" 전체를 시뮬레이션한다.
2. 왜?
// 메인 게임 루프
while(true)
{
//...
// 몬스터 객체의 이동 거리 업데이트
if(bMonsterLeft == true)
{
x--;
if(x == 0) bMosterLeft = false;
}else
{
x++;
if(x == 100) bMonsterLeft = true;
}
// 이동 거리 결과 업데이트
Monster.setPositionX(x);
// 유저 입력
processInput();
// 렌더링
render();
}
* Monster의 이동 거리 업데이트를 예제로 살펴보겠습니다.
1. Monster 객체는 "한 프레임"에 한 걸음씩 이동합니다.
2. 이 와중에도, 게임 루프는 유저 입력에 끊임없이 반응하고, 루프 결과를 렌더링 합니다.
3. Skeleton, Zombie,... etc 다양한 객체들을 추가할수록 각자의 동작들을 제어할 코드들로 가득해집니다!!
4. 각 객체들이 자신들의 동작들을 스스로 캡슐화할 필요가 있어 보이죠?
* 이때, 업데이트 패턴을 활용하여 각 객체들의 동작을 캡슐화할 수 있습니다.
update() 메서드
* update() 메서드?
: 각 객체들은 "update()" 메서드를 정의해 추상 계층을 더하고, 게임 루프는 객체 컬렉션을 쭉 돌면서 "update()"만 호출합니다! 이때, "update()" 메서드는 "한 프레임"에 업데이트할 동작들을 진행합니다!
정리
정리하자면, 게임 월드 즉 메인 게임 루프는 "객체 컬렉션"을 관리합니다. 각 객체는 "한 프레임" 단위의 동작을 시뮬레이션하기 위한 "update()" 추상 메서드를 정의하겠죠! 매 프레임마다 메인 루프는 컬렉션에 들어있는 모든 객체들을 돌면서 "update()" 추상 메서드만 호출하면 업데이트 동작을 완료하는 것입니다!
언제?
1. 동시에 동작하는 객체나 시스템이 게임에 많을 때
2. 각 객체의 동작은 다른 객체와 독립적일 때
3. 시간의 흐름에 따라 객체를 시뮬레이션할 때
주의 사항
1. 다음 프레임 업데이트를 위해 현재 상태를 저장해야 합니다!
* 왜?
현재 프레임에서 이동 중인 Monster의 위치를 다음 프레임에서 반전시켜야 한다면, 현재 Monster의 상태를 다음 프레임까지 저장하고 기억할 수 있어야겠죠! 이처럼, 다음 프레임에서도 객체들의 자연스러운 다음 움직임을 시뮬레이션하기 위해 현재 상태를 충분히 저장해야 합니다!
2. 모든 객체가 동시에 업데이트되는 것은 아닙니다!
* 왜?
게임 루프를 돌면서 모든 객체를 "프레임" 단위로 업데이트합니다. 이때, 한 객체가 다른 객체와 상호작용이 필수적이라면, 서로 다른 객체에 접근하는 코드 작성이 업데이트 중에 발생할 수 있습니다. 따라서, 객체 컬렉션을 돌며 "update()"를 호출하는 순서 또한 중요합니다!
3. 업데이트 도중에 객체 목록을 변경하는 것은 조심해야 합니다!
// 게임 루프
while(true)
{
// Update
size_t NumOfObjects = ObjectsCollection.size();
for(int i=0; i < NumOfObjects; i++)
{
ObjectsCollection[i].update();
}
processInput();
render();
}
* 왜?
업데이트 도중 죽은 객체를 객체 목록에서 삭제하면 문제가 발생할 수 있습니다. 왜냐하면, 의도치 않게 객체 목록이 컨테이너 내부에서 이동하며 특정 객체의 "update()" 호출을 생략하고 점프할 수 있기 때문입니다. 따라서, 객체 목록의 삭제 동작은 모든 객체의 "update()" 호출이 다 끝난 시점에 수행하는 것이 좋아 보입니다!
코드 예제
class Entity
{
public:
Entity() : x(0), y(0), {}
virtual ~Entity();
virtual void Update() = 0;
double getX() const { return x; }
double getY() const { return y; }
void setX(double val) { x = val; }
void setY(double val) { y = val; }
private:
double x;
double y;
};
class Monster : public Entity
{
public:
Monster() : LeftMove(false) {}
virtual void Update()
{
if (LeftMove == true)
{
setX(getX() - 1);
if (getX() == 0) LeftMove = false;
}
else
{
setX(getX() + 1);
if (getX() == 100) LeftMove = true;
}
}
private:
bool LeftMove;
};
class World
{
public:
World() : NumOfEntity(0) {}
void GameLoop();
private:
Entity* entities[MAX_ENTITIES];
int NumOfEntity
};
void World::GameLoop()
{
while (true)
{
processInput();
for (int i = 0; i < NumOfEntity; i++)
{
entities[i]->Update();
}
redner();
}
}
메인 게임 루프에서 각 객체들의 동작들을 하드 코딩하지 않고, "Update()" 추상 메서드를 통해 추상화 계층을 추가해주어 "캡슐화" 했습니다. 이것을 "Update 패턴"이라고 합니다!
'언어 > 디자인 패턴' 카테고리의 다른 글
[디자인 패턴]#11_타입 객체, Type Object (0) | 2022.09.19 |
---|---|
[디자인 패턴]#10_Sandbox Pattern, 샌드박스 패턴 (0) | 2022.09.12 |
[디자인 패턴]#8_게임 루프, Game Loop Pattern (0) | 2022.08.28 |
[디자인 패턴]#7_이중 버퍼, Double Buffer (0) | 2022.08.21 |
[디자인 패턴]#6_상태 패턴, State Pattern (1) | 2022.08.20 |