상태 패턴 인터페이스 정의 (IChacterState)
#pragma once
/*================================
State Pattern
================================*/
/*
상태 패턴은 객체가 가질 수 있는 상태를 추상화 하여 런타임에 유연하게 상태를
변경하고 필요한 경우 상태를 추가하기에도 용이한 패턴이다.
객체의 상태를 클래스로 표현한다.
FSM을 구현하기에 적합한 패턴이다.
FSM(finite-state machine) : 유한한 개수의 상태를 가질 수 있는 추상기계로 어떠한 사건에 의해
한 상태에서 다른 상태로 변화(전이)할 수 있다.
장점
ㄴ 유지보수 : 상태에 따른 행동이 분리 되어 있어 새로운 상태를 추가할 때 기존 코드를 수정하지 않아도 된다.
ㄴ 객체지향적 : 객체 지향 원리 중 단일 책임, 개방 폐쇄 원칙을 준수 할 수 있다.
단점
ㄴ 관리 : 상태 별로 클래스를 생성하므로 관리해야할 클래스 수 가 많아진다.
ㄴ 복잡성: 상태 간의 전환 로직이 복잡해질 수 있으며 각 상태의 관계를 명확히 이해해야 한다.
*/
/*
프로토타입 패턴으로 적용된 Character 클래스 재사용
*/
class Character;
class ICharacterState
{
public:
virtual ~ICharacterState() = default;
public:
virtual void handleInput(Character* character, char input) = 0;
virtual void update(Character* character) = 0;
};
상태 패턴을 상속하는 특정 상태 (Moving)
header file
#pragma once
#include "CharacterState.h"
class MovingState : public ICharacterState
{
public:
void handleInput(Character* character, char direction) override;
void update(Character* character) override;
private:
void move(Character* character, Vector3D position);
};
cpp file
#include "pch.h"
#include "MovingState.h"
#include "IdleState.h"
#include "Character.h"
void MovingState::handleInput(Character* character, char direction)
{
Vector3D position = character->getPosition();
const int speed = character->getSpeed();
switch (direction)
{
case 'w':
position.y += speed;
break;
case 's':
position.y -= speed;
break;
case 'a':
position.x -= speed;
break;
case 'd':
position.x += speed;
break;
default:
character->addState(make_unique<IdleState>());
break;
}
move(character, position);
}
void MovingState::move(Character* character, Vector3D position)
{
character->setPosition(position);
cout << character->getName() << " " << "현재 위치 : " << position.x << ", " << position.y << position.z << "\n";
}
void MovingState::update(Character* character)
{
cout << character->getName() << " : " << "움직이는 상태\n";
}
상태 패턴을 상속하는 특정 상태 (Idle)
header file
#pragma once
#include "CharacterState.h"
class IdleState : public ICharacterState
{
public:
void handleInput(Character* character, char direction) override;
void update(Character* character) override;
};
cpp file
#include "pch.h"
#include "IdleState.h"
#include "MovingState.h"
#include "Character.h"
void IdleState::handleInput(Character* character, char direction)
{
if (direction == 'w' || direction == 'a' || direction == 's' || direction == 'd')
{
cout << "움직임 상태로 전환\n";
character->setState(make_unique<MovingState>());
character->getState()->handleInput(character, direction);
return;
}
update(character);
}
void IdleState::update(Character* character)
{
cout << character->getName() << " : " << "가만히 있는 상태\n";
}
Prototype으로 생성했던 Chracter 재사용
https://mygameprogramming.tistory.com/338
Prototype Pattern
Prototype 예시 (Character)#pragma once/*================================= Prototype Pattern=================================*//*프로토 타입 패턴은 객체 생성 방식 중 하나로 기존의 객체를 복제하여 새로운 객체를 만드는
mygameprogramming.tistory.com
header file
/* 추가 사항
Observer Pattern을 위한 IObserver 상속 추가
State Pattern을 위한 ICharacterState 멤버 변수 추가
*/
#include "Observer.h"
#include "CharacterState.h"
#include "IdleState.h"
class Character : public IObserver
{
public:
Character(const Character&) = delete;
Character& operator=(const Character&) = delete;
virtual ~Character() {}
protected:
Character()
{
cout << "기본 아이들 상태\n";
setState(make_unique<IdleState>());
}
Character(int hp, int mp, int speed, string name)
: _hp(hp), _mp(mp), _speed(speed), _name(name)
{
cout << "기본 아이들 상태\n";
setState(make_unique<IdleState>());
}
public:
int getHP() const
{
return _hp;
}
int getMP() const
{
return _mp;
}
int getSpeed() const
{
return _speed;
}
string getName() const
{
return _name;
}
void setHP(int health)
{
_hp = health;
}
void setMP(int magic)
{
_mp = magic;
}
void setSpeed(int spd)
{
_speed = spd;
}
void setName(const string& name)
{
_name = name;
}
void setPosition(const Vector3D& position)
{
_position = position;
}
Vector3D getPosition() const
{
return _position;
}
unique_ptr<ICharacterState>& getState()
{
return _currentState;
}
public:
virtual unique_ptr<Character> clone() const = 0;
virtual void display() const = 0;
virtual void attack() = 0;
/*공통 기능*/
public:
void update(EEventType event) override;
void setState(unique_ptr<ICharacterState> newState);
void stateUpdate(char input);
private:
void dayUpdate();
void nightUpdate();
private:
string _name;
int _hp = 0;
int _mp = 0;
int _speed = 0;
Vector3D _position;
unique_ptr<ICharacterState> _currentState = make_unique<IdleState>();
};
cpp file
#include "pch.h"
#include "Character.h"
void Character::update(EEventType event)
{
switch (event)
{
case EEventType::DAY:
dayUpdate();
break;
case EEventType::NIGHT:
nightUpdate();
break;
}
}
void Character::setState(unique_ptr<ICharacterState> newState)
{
cout << "새로운 상태 추가\n";
_currentState = move(newState);
}
void Character::stateUpdate(char input)
{
if (_currentState != nullptr)
{
_currentState->handleInput(this, input);
}
}
void Character::dayUpdate()
{
_speed += 5;
if (_speed > 100)
{
_speed = 100;
}
cout << _name << " 현재 이동 속도: " << _speed << " 낮일 때 이동 속도 증가\n";
}
void Character::nightUpdate()
{
_speed -= 10;
if (_speed < 0)
{
_speed = 0;
}
cout << _name << " 현재 이동 속도: " << _speed << " 밤일 때 이동 속도 감소\n";
}
상태 패턴 사용 (키 입력에 따른 상태 변화)
int main()
{
Mage prototypeMage(100, 100, 80, "메이지");
unique_ptr<Character> copyMage = prototypeMage.clone();
bool run = true;
while (run)
{
if (_kbhit())
{
char key = _getch();
copyMage->stateUpdate(key);
}
}
return 0;
}
실행 화면
'Design Pattern' 카테고리의 다른 글
Stategy pattern (0) | 2024.02.07 |
---|---|
Observer Pattern (0) | 2024.02.05 |
Prototype Pattern (0) | 2024.02.04 |
Builder Pattern (0) | 2024.02.03 |
Factory Pattern (0) | 2024.02.02 |