스스로 만든 미로에 갇혀
1년 전쯤에, 저는 파이썬과 pygame을 이용하여 게임을 만들려고 했습니다.
원래의 목적은 목장이야기 코로보쿠르 스테이션에 evil farming game의 요소를 혼합한 자유도 높은 농사 시뮬레이터 게임을 만드는 것이었습니다. 그러나 실제 개발은 게임에 필요한 기본 요소(플레이어 이동, 농작물 시스템 등)를 만드는 데에서 중단되었습니다. 당시에는 어떤 코드가 좋은 코드인지, 어떻게 프로젝트를 잘 관리할 수 있는지 등을 전혀 알지 못한 채 무턱대고 코드를 작성했고, 그 결과 모래성 위에 모래성을 쌓으면서 스스로 잘 하고 있다고 착각했습니다.
어느 선까지는 어떻게든 진행됐습니다. 그러나 결국 프로젝트의 복잡도는 혼자 관리할 수 있는 수준을 넘어서 버렸고, 결국 저는 프로젝트를 포기한 채 깃허브 한편에 1년 동안 방치해 놓았습니다.
그리고 오늘, 이 프로젝트를 다시 꺼내 분석해볼 것입니다.
들어가기에 앞서, 옛날 프로젝트를 파헤치도록 동기부여를 해준 동아리의 친구에게 감사를 표합니다. 의지할 문서도 없고 주석도 부실한 프로젝트를 분석하는 것은 그 자체로 큰 도전입니다. 프로그래밍의 입문자들이 이 글을 보고 교훈을 얻을 수 있도록 기술적 세부사항은 최소화하고, 코딩을 잘 모르더라도 읽기 쉽게 쓰려고 노력했습니다.
2.본격적 코드 분석
(참고:이 글에서는 파이썬 또는 pygame의 세부사항에 대해 다루지 않고, 코드의 추상적인 구조만을 설명합니다. 또한 구조의 설명에 필수적이지 않은 부분은 생략되었습니다.전체 코드를 보고 싶다면 여기를 참조하세요.)
2.1.파이게임 구조
이 프로젝트는 pygame에 기반하여 만들어졌으므로, 우선 pygame의 구조에 대해 살펴봐야 이 프로젝트를 이해할 수 있을 것입니다.

pygame은 초기 설정-게임 루프-종료의 3단계로 이뤄집니다. 실제 '게임 플레이'에 해당하는 부분은 게임 루프 안에서 일어납니다.
2.2. main.py
이 프로젝트의 main.py 또한 전반적으로 이러한 구조를 취하고 있습니다. 우선 '초기 설정' 부분을 보겠습니다.

초기 설정 부분에서 입력 이벤트를 저장하는 eventList, pc(player character) 객체 및 매니저 객체를 담은 essential_pack을 만듭니다. 나중에 살펴보겠지만, 이 부분이 프로젝트의 설계 오류를 상징합니다.

게임 루프 안에서는, eventList에 한 틱 동안 발생한 모든 입력을 저장합니다. 이후 게임 상태의 업데이트 및 화면 그리기를 수행합니다.
2.3. pc.py
이 파일은 플레이어에 대한 코드입니다. 짐작할 수 있다시피 플레이어와 조금이라도 관련된 모든 코드를 몰아넣기에 좋은 곳이죠.
2.3.1 update
이 함수 하나에 몇 개의 기능이 들어 있을까요?

- 플레이어가 맵 바깥으로 벗어났는지를 검사합니다.

- 플레이어의 앞에 놓인 객체를 저장하는 용도의 변수들을 선언합니다.

- 플레이어가 앞으로 이동할 수 있는지 여부를 검사합니다.

- 여기서부터는 eventList 내의 입력을 처리합니다. 만일 입력이 방향키 중 하나라면 그 방향으로 움직입니다.(분량상 접기 처리한 나머지 3개의 elif문도 move, mapMamager를 통해 호출하는 메소드만 다르고 거의 동일한 구조를 가지고 있습니다.)

- 입력이 F키라면 인게임 정보를 보여줍니다. 이 기능은 디버그용 print문만 있는 더미로 구현되어 있습니다.(print문의 출력은 콘솔에만 출력되고 게임 화면에는 영향을 미치지 않습니다.)

- R키는 npc와의 상호작용 버튼입니다. mapManager를 통해 맵에 있는 npc 정보를 불러오는 것으로 보입니다.

- C키는 아이템 버리기 버튼입니다. throwing 함수를 호출합니다.

- E키는 '상호작용' 버튼입니다. 플레이어가 어떤 아이템을 들고 있는지, 플레이어의 앞에 무엇이 있는지 등의 상황에 따라 다른 상호작용이 발생하는 가장 복잡한 버튼입니다. 우선 들고 있는 아이템의 이름을 '_'를 기준으로 파싱하여 문재열 배열로 저장합니다.

- 만일 앞에 문이 있다면 문을 통해 이동합니다. target_door[0][0]은 문의 목적지를 가리키는 것으로 추정됩니다.

- 들고 있는 아이템의 0번째 단어가 tool이라면 도구를 이용한 상호작용을 수행합니다. 각 상호작용은 도구의 '_able' 속성(도구가 어떤 작업을 할 수 있는지 여부)과 맵의 소유자인지 여부(자신 소유의 맵에서만 도구 사용 가능)를 검사한 뒤 수행됩니다.

- 들고 있는 아이템의 1번째 단어가 seed라면 이를 심습니다.

- front(플레이어의 앞을 나타내는 객체), inventory를 업데이트 후 rect.x/y를 갱신합니다. 이 변수는 플레이어의 위치를 나타내는 것으로 추정됩니다.
보다시피 하나의 함수에 무려 12개의 기능이 구현되어 있습니다. 이렇게 한 함수가 너무 많은 일을 하게 된다면 함수의 목적과 기능을 파악하기 어려워지고, 함수의 한 부분을 수정했을 때 다른 부분이 영향을 받을 위험 또한 생깁니다.