본문 바로가기
IT/Game

게임 프로그래밍 패턴 1장, 2장 (22. 04. 26)

by YEON-DU 2022. 5. 1.
반응형

지식, 정보, 처리능력 ⇒ 코드리딩 시 사용.

지식 (Long Term Memory) → 익히면 된다.

정보 (Short Term Memory) → 한계가 있다. 보통 한 번에 12개의 정보까지만 저장할 수 있다고 한다.

처리능력 → 지식과 정보를 활용한 처리 능력.

왜 구조가 필요한가?

얼마나 쉽게 변경할 수 있는가 = 구조가 좋다는 증거이다.

Component Pattern (디커플링 패턴)

양쪽 코드 중 한쪽이 없으면 다른 한 쪽을 이해할 수 없을 때를 커플링된 상태라고 한다.

디커플링이 된다는 것은 이해해야하는 양, 신경써야할 양을 줄이는 것과 같다.

코드의 유연성 ≠ 최적화

단순함 = 최소한의 코드로 원하는 목표를 이룰 수 있는 것

커맨드(명령) 패턴 → 객체나 함수에 위임

메멘토 패턴 → 현재 상태를 Snapshot 하여 사용한다.

 

Chapter1. 구조, 성능, 게임


좋은 소프트웨어 구조는 변경과 관련이 있다.

얼마나 쉽게 변경할 수 있느냐가 코드 설계를 평가하는 척도가 된다.

 

프로그래밍 흐름도

디커플링은 어떻게 도움이 되는가?

‘어느 한 코드를 변경했을 때 다른 코드를 변경하지 않아도 된다.

좋은 구조는 생산성을 크게 높여준다. 그러나 좋은 구조를 만들기까지는 쉽지 않다. 우리는 보통 작업을 할때 아래와 같은 목표가 있다.

 

1. 프로젝트 개발 기간동안 코드를 쉽게 이해할 수 있도록 구조를 깔끔히 만들고 싶다.
2. 실행 성능을 최적화하고 싶다.
3. 지금 개발 중인 기능을 최대한 빠르게 구현하고 싶다.

그러나 빠르게 구현한 결과물이 최고의 실행 속도를 내는 경우는 드물다.

최적화에는 많은 개발 기간이 있고,

최적화를 하다보면 코드가 고착되는 경향이 있다.

극도로 최적화된 코드는 유연하지 않다.

이러한 목표들은 어느정도 상반되기때문에 목표들 사이에서 균형을 잡는 것이 중요하다.

다양한 제약들을 완화하는 방법의 하나는 ‘단순함’이다.

단순하게 실행 순서대로 알고리즘을 나열하고, 나열된 코드 속에서 일정한 패턴을 찾아서 코드를 단순화하는 것이다.

 

Chapter2. 명령


명령 패턴은 메서드 호출을 실체화한 것이다.

프로그래밍 분야에서는 무엇인가를 일급first-class으로 만든다는 뜻으로 통한다.

어떤 개념을 변수에 저장하거나 함수에 전달할 수 있도록 데이터, 즉 객체로 바꿀 수 있다는 걸 의미한다.

예시는 아래와 같다.

입력 키에서 입력을 받아 특정 행동을 하도록 만드는 코드이다.

 

void InputHandler::handleInput() {
	if (isPressed(BUTTON_X) jump();
	else if (isPressed(BUTTON_Y)) fireGun();
	else if (isPressed(BUTTON_A)) swapWeapon();
	else if (isPressed(BUTTON_B) ) lurchIneffectively();
}

그러나 많은 게임이 키를 바꿀 수 있게 해준다.

키별로 특정한 행동을 유저가 지정할 수 있는 것이다.

따라서 직접 함수를 호출하기보단 교체가 가능하도록 만들어준다.

게임에서 할 수 있는 행동을 실행할 수 있는 공통 상위클래스 Command를 정의한다.

 

class Command {
public:
	virtual ~Command()
	virtual void execute() = 0;
};

각 행동 별로 하위 클래스를 만든다.

 

class JumpCommand : public Command {
public:
	 virtual void execute() { jump(); }
};

class FireCommand : public Command {
public:
	virtual void execute) { fireGun(); }
};

...

기존의 입력 핸들러 코드는 각 버튼 별로 Command 클래스 포인터를 저장한다.

class InputHandler {
public:
	void handleInput();

private:
	Command* buttonX_:
	Command* buttonY_:
	Command* buttonA_;
	Command* buttonB_;
};

입력 처리는 다음 코드로 위임된다.

 

void InputHandler::handleInput() {
	if (isPressed(BUTTON_X)) buttonX_->execute();
	else if (isPressed(BUTTON_Y)) buttonY_->execute();
	else if (isPressed(BUTTON_A)) buttonA_->execute();
	else if (isPressed(BUTTON_B)) buttonB_->execute();
};

하지만 위의 클래스도 한계가 있다.

jump나 fireGun 같은 전역 함수에 따라 행동할 플레이어 캐릭터 객체를 미리 알고 있어야 한다는 점에서 제한이 생긴다. (이미 커플링이 존재하는 상태)

따라서 제어하려는 객체를 함수에서 찾지 말고 밖에서 전달해주게끔 만든다.

직접 객체를 참조로 파라미터를 넘겨주면 된다.

반응형

댓글