[TIL] 게임 프로그래밍 패턴 (1)

MINO·2024년 9월 14일
post-thumbnail

2024-09-14


참고 문헌

더 빠르고 깔끔한 게임 코드를 구현하는 13가지 디자인 패턴
게임 프로그래밍 패턴



1장. 구조, 성능, 게임


좋은 소프트웨어 구조란?

뭔가를 고쳐야 할 때 그럴 줄 알았다는 듯이 코드가 준비되어 있는 것


코드를 고치는 방법

업무 할당 → 코드 파악 → 문제 해결 코드 작성 → 코드 정리 → 반복..


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

커플링 : 양쪽 코드 중에서 한쪽이 없으면 코드를 이해할 수 없는 상태
디커플링 : 어느 한 코드를 변경했을 때 다른 코드를 변경하지 않아도 되는 상태

두 코드를 디커플링하여, 각각을 따로 이해할 수 있게 된다.

작업에 관련된 코드가 두 코드 중에서 하나에만 연관되어 있다면,
한쪽 코드만 머리에 집어넣으면 된다.


비용

좋은 구조는 생산성을 크게 높여주지만, 많은 노력과 원칙이 필요하다.
유연성이 필요할 것이라고 예측했지만, 써먹지 못한다면 작업량만 늘어난 셈이다.


성능과 속도

코드를 유연하게 만드는 많은 패턴은 가상 함수, 인터페이스, 포인터, 메시지 같은 메커니즘에 의존하고, 이는 런타임 비용을 요구한다.

인터페이스를 쓰는 이유 : 클래스뿐만 아니라 같은 인터페이스를 구현하는 어떤 클래스가 와도 코드가 문제 없이 작동하게 만들기 위해서
관찰자, 이벤트 큐 를 쓰는 이유는 당장은 서로 통신하는 부분이 둘밖에 없더라도 나중에 셋, 넷으로 쉽게 늘리고 싶기 때문.

최적화 기법은 구체적인 제한을 선호한다.
Ex ) 적이 256개 이하라고 확신한다 → ID 를 1Byte 로 압축할 수 있다.
Ex ) 한 자료형의 한 메서드만 호출한다고 확신한다 → 가상 함수 없이 정적으로 바인딩된 함수를 바로 호출하거나 인라인 함수로 작성할 수 있다.
Ex ) 모든 개체가 같은 클래스라고 확신한다 → 배열에 전부 집어넣을 수 있다.

처음에는 코드를 유연하게 유지하다가 기획이 확실해진 다음에 추상 계층을 제거해 성능을 높이는 타협안도 있다.


균형 잡기

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

→ 좋은 구조는 장기적으로 생산성을 높여주지만,
구조를 좋게 유지하려면 코드를 변경할 때마다 노력을 더 들여야 한다.

셋 다 각각 장단점이 있기 때문에 TradeOff 외에는 명쾌한 정답이 없다.


단순함

  1. 코드를 최대한 간결하게, 문제를 직접 해결하는 방향으로 작성한다.
  2. 자료구조와 알고리즘을 먼저 잡아놓고 여기서부터 다른 방법을 찾아나간다.
  3. 좋은 해결책은 코드를 덧붙이는 게 아니라 필요 없는 코드를 최대한 빼는 것

1장 마무리

  • 추상화와 디커플링을 잘 활용하면 코드를 점차 쉽고 빠르게 만들 수 있다.

    • 그러나 지금 고민 중인 코드에 유연함이 필요하다는 확신이 없다면
      추상화와 디커플링은 잠시 미뤄두자.
  • 개발 내내 성능을 고민하고, 최적화에 맞게 설계해야 한다.



2장. 명령

요청 자체를 캡슐화하는 것을 명령이라고 한다.


명령(Command) 패턴

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

요청을 객체로 캡슐화하여 요청을 전송하는 객체와 요청을 처리하는 객체를 분리하는 방식이다.

// 게임에서 할 수 있는 행동을 실행할 수 있는 공통 상위 클래스 Command
public abstract class Command {
    public abstract void execute();
}

// 각 행동별 하위 클래스 JumpCommand, FireCommand 등
public class JumpCommand : Command {
    public override void execute() { jump(); }
}

public class FireCommand : Command {
    public override void execute() { fire(); }
}

// 입력 핸들러 코드
public class InputHandler {
    private Command buttonX;
    private Command buttonY;
    private Command buttonA;
    private Command buttonB;

    public void 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();
    }
}

버튼이 입력돼어 직접 함수를 호출하지 않고, 한 겹 우회하는 계층을 통해 호출한다.


액터에게 지시하기

profile
안녕하세요 게임 개발하는 MINO 입니다.

0개의 댓글