이론/디자인패턴 12

객체 풀

왜써야댐 객체를 생성하기 위해 힙 메모리를 할당/해제하다보면 메모리 단편화가 생긴다. 메모리 단편화는 특히 메모리가 부족한 모바일 환경에서 치명적이다. 객체 풀은 사용될 객체들을 위한 메모리를 미리 크게 잡아놓음으로써 메모리 단편화를 예방한다. 게다가 일부 관리 언어에서 GC호출 빈도를 줄여주는 효과도 있다. 그럼 언제씀 객체 풀 패턴은 다음과 같을 때 사용하면 좋다. 객체를 빈번하게 생성/삭제한다. 객체들의 크기가 비슷하다(같다). 객체를 힙에 생성하는 게 느리거나 메모리 단편화가 우려된다. DB나 네트워크 연결같이 접근 비용이 비싸면서 재사용 가능한 자원을 객체가 캡슐화하고 있다. 구현 아래와 같은 파티클 객체가 있다. class Particle { public: Particle() : frame_(..

데이터 지역성

https://tsyang.tistory.com/68 Data-oriented Design (데이터 지향 설계, DoD) CppCon 2014 - Mike Acton의 "Data-Oriented Design and C++"을 주로 참고해서 씀. https://www.youtube.com/watch?v=rX0ItVEVjHc 인트로 1. 소프트웨어는 플랫폼이다. 2. 코드는 실제 세계의 모델을 중심으로 설.. tsyang.tistory.com 데이터 지역성을 활용해야 하는 이유와 아이디어는 위 글에 써있다. 이 글에서는 구현에 대해 다룬다. 데이터 지역성 패턴 데이터 지역성 패턴은 성능 문제가 있을 때 써야한다. 필요 없는 곳에 적용해봐야 코드만 복잡해지고 유연성만 떨어진다. 특히 데이터 지역성 패턴은 성능..

업데이트 메서드

2022.01.31 - [이론/디자인패턴] - 게임 루프 게임 루프 게임 루프 게임 루프는 게임 시간 진행을 유저 입력, 프로세서 속도(!)와 디커플링 한다. 유저 입력은 알겠는데 프로세서 속도와 디커플링 한다는게 무슨 말일까? 굉장히 간단한 게임 루프를 보 tsyang.tistory.com 업데이트는 어떻게 게임 루프에 루프는 간략하게 다음과 같다. while(true) { processInput(); update(); render(); } update() 안에서는 게임의 개체들을 시뮬레이션한다. 그런데 어떻게? update() 안에 직접 각각의 개체들을 움직이는 코드를 작성해야 할까? 만약에 개체의 종류가 수백 가지라면? 코드가 점점 유지 보수하기 어려워질 것이다. 당연히 이런 경우 해결책은 간단하다..

타입 객체

왜 씀? 타입 객체 패턴은 다양한 '종류'를 정의할 때 컴파일이나 코드 변경 없이 새로운 타입을 추가하거나 변경할 수 있도록 해준다. 판타지 배경의 RPG 게임을 만든다고 하자. 이 게임의 몬스터는 여러 종족으로 나뉜다. 종족에 따라 최대 체력, 공격 속성 등이 달라진다. OOP 방식으로 구현 고블린, 오크, 용 등은 모두 몬스터의 일종이다. 따라서 몬스터라는 상위 클래스를 만드는 게 자연스럽다. (IS-A 관계) class Monster { public: virtual ~Monster(){} //공격 문구를 받아온다. virtual std::string attack() = 0; }; 하위 몬스터는 다음과 같이 구현될 것이다. class Goblin : public Monster { public: std..

게임 루프

게임 루프 게임 루프는 게임 시간 진행을 유저 입력, 프로세서 속도(!)와 디커플링 한다. 유저 입력은 알겠는데 프로세서 속도와 디커플링 한다는게 무슨 말일까? 굉장히 간단한 게임 루프를 보자. while(true) { processInput(); update(); render(); } processInput에서 유저의 입력을 처리하고, update에서 게임을 시뮬레이션 하고, render에서는 화면을 그린다. 당연한 얘기지만, 컴퓨터가 좋을 수록 1초에 돌릴 수 있는 루프의 횟수가 증가한다. 즉, 게임이 빨리 돌아가게 된다. 즉, 게임의 속도가 프로세서의 속도와 커플링 되어있는 것이다. https://youtu.be/r4EHjFkVw-s 144hz로 게임을 플레이하면 속도가 빨라지는 폴아웃4 어떻게 디..

이중 버퍼

왜쓰나? 여러 순차 작업의 결과를 한 번에 보여주고 싶을 때. 변경 중인 상태에 접근할 수 없게 하고 싶을 때. 코드가 변경하려는 상태를 다시 읽는 경우. 이중 버퍼를 사용하는 가장 대표적인 예는 게임 렌더링이다. class FrameBuffer { public: void clear();//픽셀을 모두 하얀색으로 채운다. void draw(int x, int y);//x,y 픽셀을 검은색으로 바꾼다. }; class Scene { public: void draw(); FrameBuffer& getBuffer(); private: FrameBuffer buffer_; }; 이처럼 FrameBuffer와 화면에 흑백 그림을 그려주는 Scene이 있다고 하자. Scene은 화면에 곰돌이 한 마리를 그린다. v..

서비스 중개자

개요 중개자 패턴은 서비스를 구현한 구체 클래스를 숨긴 채로 어디에서나 서비스에 접근할 수 있게 해 준다. 프로그램에서 메모리 할당, 로그, 난수 생성 등의 시스템은 프로그램 전체에서 사용하는 서비스라고 볼 수 있다. 게임의 경우 오디오 시스템 역시 일종의 서비스일 것이다. UI, 물리엔진, 캐릭터 등 여러 곳에서 오디오를 호출한다. 이러한 경우 정적 클래스나 싱글턴을 사용할 수 있는데 이런 방법은 편한 대신 강한 커플링이 생긴다. (커플링이 생기는 것을 피할 수 없기는 하다.) 전화번호부를 생각해보자. 자신이 전화번호를 바꿨다고 해서 내 번호를 사용하는 모든 사람들에게 전화번호가 바뀌었다고 알리는 편보다 전화번호부에서 자신의 전화번호를 수정하는 편이 훨씬 더 간단하다. 호출하는 쪽에서는 전화번호부에서 ..

이벤트 큐 패턴

이게머임? 이벤트 큐 패턴은 메시지나 이벤트를 보내고 처리하는 시점을 분리하는 패턴이다. (시점의 디커플링) 또한 관찰자 패턴을 멀티 쓰레딩 환경에서 사용할 때 클래스끼리 서로 비동기적으로 상호작용 하도록 할 때 쓸 수 있다. https://tsyang.tistory.com/83?category=1006818#%EA%B4%80%EC%B0%B0%EC%9E%90 디자인 패턴 - 행동패턴 개요 행동 패턴에는 다음 패턴들이 포함되어 있다. (취소선은 다루지 않음) 전략(Strategy) 상태(State) 탬플릿 메서드(Template Method) 명령(Command) 책임 연쇄(Chain of Responsibility) 관찰자 (Observer) 메.. tsyang.tistory.com 기본적으로 관찰차 패..

컴포넌트 패턴

컴포넌트 패턴 컴포넌트 패턴은 한 개체가 여러 분야의 코드를 커플링 없이 다룰 수 있게 해준다. 문제 1 매 업데이트마다 인풋을 받아서 위치를 계산하고 바뀐 위치로 스프라이트를 그리는 Player 클래스가 있다고 하자. void Player::update() { //인풋으로 플레이어의 속도를 결정함. //속도를 이용해 위치를 바꿈 //옮겨진 위치로 플레이어의 스프라이트를 그림. } Player에는 앞으로 여러 기능들이 더 추가 될탠데 그때마다 update가 수정된다. 딱 봐도 코드가 더러워 질 것이라는 예감이 든다. 심지어 각 분야의 작업자들은 다른 분야의 코드를 보게된다. 2 이번에는 GameObject를 상속하는 Zone, Decoration, Prop 오브젝트가 있다고 해보자. Zone은 충돌하지만..

디자인 패턴 - 행동패턴

개요 행동 패턴에는 다음 패턴들이 포함되어 있다. (취소선은 다루지 않음) 전략(Strategy) 상태(State) 탬플릿 메서드(Template Method) 명령(Command) 책임 연쇄(Chain of Responsibility) 관찰자 (Observer) 메멘토 (Memento) 중재자 (Mediator) 방문자 (Visitor) 반복자 (Iterator) 인터프리터 (Interpreter) 전략패턴, 반복자패턴은 이미 익숙한 개념이므로 패스, Interpreter는 특정 상황(ex. 문자열 명령어 파싱)에 한정적으로 쓰여서 패스. 상태패턴 2D 횡스크롤 게임이 있다고 가정하다. 캐릭터는 점프, 앉기, 달리기... 등의 여러 동작이 가능하다. 이런 동작들을 구현할 때 많은 예외에 부딪힐 것이다...