[게임 프로그래밍 패턴] 6. 상태 패턴

WIGWAG·2023년 2월 14일

상태 패턴이란?

객체의 내부 상태에 따라 스스로 행동을 변경할 수 있게 허가하는 패턴으로, 이렇게 하면 객체는 마치 자신의 클래스를 바꾸는 것처럼 보입니다.(GoF의 디자인 패턴 395p)

캐릭터의 상태들을 클래스로 분리해서 특정 이벤트가 발생하면 상태가 전환되어 그 상태를 캐릭터가 가지도록 하는 기법이다.


상태 패턴 예시 코드

#include <iostream>

using namespace std;

enum Input {
	RELEASE_DOWN,
	PRESS_B,
	PRESS_DOWN
};

enum Graphic {
	IMAGE_STAND,
	IMAGE_DUCK
};

class C_Hero_State {
public:
	virtual ~C_Hero_State() {}
	virtual shared_ptr<C_Hero_State> Handle_Input(C_Hero& hero, Input input) {}
	virtual void Update(C_Hero& hero) {}
	virtual void Enter(C_Hero& hero) {}
};

class C_On_Ground_State : public C_Hero_State {
public:
	virtual shared_ptr<C_Hero_State> Handle_Input(C_Hero& hero, Input input) override {
		if (input == PRESS_B) {
			return make_shared<C_Jumping_State>();
		}
		else if (input == PRESS_DOWN) {
			return make_shared<C_Ducking_State>();
		}
	}
};

class C_Standing_State : public C_On_Ground_State {
public:
	virtual void Enter(C_Hero& hero) override {
		hero.Set_Graphics(IMAGE_STAND);
	}

	//다른 코드들
};

class C_Ducking_State : public C_On_Ground_State {
public:
	C_Ducking_State() :charge_time_(0) {}

	virtual void Enter(C_Hero& hero) override {
		hero.Set_Graphics(IMAGE_DUCK);
	}

	virtual shared_ptr<C_Hero_State> Handle_Input(C_Hero& hero, Input input) override{
		if (input == RELEASE_DOWN){
			return make_shared<C_Standing_State>();
		}
		else {
			C_On_Ground_State::Handle_Input(hero, input);
		}
	}

	virtual void Update(C_Hero& hero) override {
		++charge_time_;
		if (charge_time_ > MAX_CHARGE) {
			hero.Super_Bomb();
		}
	}
private:
	static const int MAX_CHARGE = 10;
	int charge_time_;
};

class C_Jumping_State : public C_Hero_State {
	//생략
};

class C_Hero {
public:
	void Handle_Input(Input input);

	void update() {
		state_->Update(*this);
	}

	void Set_Graphics(Graphic graphic) {}
	void Super_Bomb() {}

private:
	shared_ptr<C_Hero_State> state_;
	shared_ptr<C_Hero_State> equipment_;
};

void C_Hero::Handle_Input(Input input)
{
	auto state = state_->Handle_Input(*this, input);
	if (state)
	{
		state.reset();
		state = nullptr;

		state_ = state;
		state_->Enter(*this);
	}

	auto equipment = equipment_->Handle_Input(*this, input);
	if (equipment)
	{
		equipment.reset();
		equipment = nullptr;

		equipment_ = equipment;
		equipment_->Enter(*this);
	}
}
profile
프로그래밍 공부 기록 노트

0개의 댓글