[유니티/C#] 게임 디자인 패턴(Design Pattern)과 리팩토링(Refactoring)

728x90

게임 최적화란?

게임 프로그래밍 디자인 패턴을 이해하려면 먼저 좋은 소프트웨어 구조에 대해 알아야 한다.

좋은 소프트웨어 구조는 코드를 거의 건드리지 않고도, 적당한 함수 몇 개만 호출하면 원하는 작업을 할 수 있도록 '범용성' 있게 설계한 구조를 말한다. 해당 코드를 얼마나 쉽게 변경할 수 있는지, 얼마나 다양한 방식으로 활용할 수 있는지 여부가 '좋은' 코드 설계를 평가하는 척도가 된다.

 

비용 발생

생산성이 높은 소프트웨어 구조를 설계하는 과정에서 일반적으로 '추상화'와 '모듈화' 다음 2가지 방법을 채택한다. 하지만 기능을 추가하거나, 코드를 조금씩 변경할 때 마다 나머지 코드들과 통합되어야 하는데, 그 과정에서 잦은 디버깅으로 인해 유지 비용이 발생한다.

 

가령, 확장성을 위해 기존 코드에 인터페이스, 추상화, 플러그인 시스템, 추상 클래스 및 가상 메서드를 추가하는 등 복잡성이 더해지면 개발, 디버깅, 유지보수에 많은 시간과 노력이 소요되 오히려 생산성이 떨어트리는 역효과가 발생할 수 있다.

 

성능 저하

추상화가 많아질수록 게임 성능을 저하시킬 수도 있다. 코드의 유연성을 위한 패턴은 가상 메서드, 인터페이스, 포인터, 메시지와 같은 메커니즘에 의존하는데 이들은 각각 런타임(Runtime) 비용을 요구한다. 따라서 소프트웨어 구조를 설계할 때 각각의 상황과 목적에 맞는 방식을 채택해야 한다. 

 

예를 들어, 빠르게 기능을 구현하고 테스트해야하는 경우 최소한의 기능만 돌아가고, 필요 없는 코드는 바로 버릴 수 있는 '프로토타이핑 기법'을 사용해 상황에 맞는 코딩 스타일을 찾아내야 한다.

 

개발자가 반드시 세워야하는 목표

프로그래머들이 코딩을 할때는 다음 3가지를 반드시 유념해야 한다. 
1. 프로젝트 개발 기간 동안 코드를 쉽게 이해할 수 있도록 구조를 깔끔하게 만든다

2. 실행 성능을 최적화한다.

3. 지금 개발 중인 기능을 최대한 빠르게 구현한다.

디자인 패턴(Design Pattern) 개요 및 종류

비용 발생/성능 저하 등의 이슈를 해결하고, 확장성 있는 코드를 작성하여 생산성 높은 소프트웨어 구조를 설계하기 위한 프로그래머들의 노력이 바로 '디자인 패턴'에 담겨있다. 

 

디자인 패턴이란 반복적으로 일어나는 문제에 대해 재사용이 가능한 코드 형태로 작성하는 방식을 의미한다. 기존의 많은 개발자들이 고민했던 문제들을 쉽고 빠르게 해결할 수 있는 장점이 있고, 이미 정리된 패턴을 적극 활용하기 때문에 팀원들과 협업 및 소통하는데 있어 효율적이다. 더 나아가, 기본 패턴들을 이용하여 자신만의 기능을 추가하면 유의미한 새로운 패턴을 만들 수 있기도 한다.

 

디자인 패턴은 크게 생성 패턴 / 구조 패턴 / 행동 패턴으로 나뉘며, 각 패턴 별로 세부적인 패턴들이 존재한다.

디자인 패턴 별 상세 구현 코드는 다음 깃허브 링크를 참고하면 되겠다.

https://github.com/94mark/design-patterns/tree/main/DesignPattern/Assets/Scripts

 

GitHub - 94mark/design-patterns: 디자인 패턴 공부

디자인 패턴 공부. Contribute to 94mark/design-patterns development by creating an account on GitHub.

github.com

 

명령 패턴 Command Patterns

게임 프로그래밍에서 자주 사용하는 디자인 패턴으로는 명령 패턴(Command Patterns)이 있다. 명령 패턴은 요청 자체를 캡슐화하는 방식으로 서로 다른 클라이언트를 매개변수로 만들고 요청을 대기시키거나 로깅하며, 되돌릴 수 있는 연산을 지원한다.

 

보통인 키 입력 시 키 커스터마이징을 통해 확장성을 늘리는데 사용한다. 가령 스타크래프트를 예로 들면, 기존의 키 입력대로라면 해처리를 클릭 후 Kecode S, M을 차례로 입력하면 뮤탈리스크가 생산된다. 하지만 Hot Key 설정에 들어가 유저가 직접 키 입력을 바꾸면 Kecode S, T를 입력하여 뮤탈리스크를 생산할 수 있다. 이는 키 입력값 요청 자체를 캡슐화시킨 명령 패턴의 대표적인 사례라고 볼 수 있다.

 

비슷하게 실행 취소/돌아가기 등 직전의 명령으로 돌아갈 때도 사용한다. 명령 입력 시 기본적으로 스택에 후입선출(LIFP) 방식으로 데이터가 들어가기 때문에 이전 상황으로 명령을 취소하여 재실행 할 수 있게 된다.  

 

싱글톤 패턴 Singleton Patterns

게임 프로그래머라면 싱글톤 패턴(Singleton Patterns)에 대해 익숙할 것이다. 싱글톤 역시 디자인 패턴 중에 하나이며 특히, 게임 프로그래밍에서 매우 자주 사용된다. 싱글톤은 해당 클래스의 인스턴스를 생성하고 접근가능하도록 만들어 프로퍼티를 호출 시 생성한 인스턴스를 호출하는 방식을 의미한다. 

 

가령, 피격 시 데미지 함수를 호출하여 체력을 감소시킬 때 플레이어 체력 관련 클래스를 인스턴스화하여 데미지를 호출하는 클래스에 넣어 활용하곤 한다. 인스턴스를 static으로 선언하기 때문에 시스템 전역에서 관리되고 단 하나의 클래스에서만 정보가 유지되는 것을 목적으로 한다. 따라서 싱글톤은 게임 매니저, 게임 플레이 시간, 유닛 킬수, 건물 갯수 등 게임 플레이 과정에서 생성되는 전체적인 누적 데이터를 관리하는데 사용된다. 

 

유한상태머신 패턴 FSM, Finite State Machine Patterns

게임 개발자라면 FSM 패턴을 이미 한번 씩은 다 사용해보았을 것이다. 유니티에서 제공하는 Animator 프로퍼티는 FSM 패턴을 시각화해서 드래그앤 드롭 만으로 커스터마이징 할 수 있게 만든 것이다. 상태 패턴을 다중으로 처리하지 않고, 이벤트 발생 시 하나 씩 처리해 현재 상태에서 다음 상태로 전이하게 하는 디자인 패턴으로 특정 객체의 상태를 관리하기 위한 패턴으로 이해하면 되겠다.

 

리팩토링 Refactoring

보통 신입이든 경력이든 회사에 입사하면 새로운 프로젝트가 아닌, 기존의 프로젝트에 투입된다. 그러면 기존 팀에서 만들어놓은 코드 구조를 이해해야 하는데 내가 짠 코드가 아니기 때문에 사용하기 어려운 부분이 있다. 이럴 때 나만의 코드 짜는 스타일로 전체 코드를 재구조화 하는 것을 리팩토링(Refactoring)이라고 한다.

728x90