9.3 객체지향으로 개발하기 1
배틀시티 게임의 객체지향형 버전에선 이전에 비해 객체지향 디자인(OOD: Objected Oriented Design)적인 면을 더 고려해 보는 훈련을 해보면 좋겠다. 객체지향적으로 만든다는 것은 구조적으로 어떠한 형태를 띄어야 하는 것일까? 파이게임제로 라이브러리를 베이스로 사용하고 있기 때문에 필수 콜백함수들(draw, update 함수 등)을 통한 게임루프의 구조는 그대로 가져갈 수 밖에 없다는 걸 전제해야 한다는 것을 이해하고 있을 것이다. 다만, 그 게임루프에서 개임의 주인공 객체간의 협력으로 게임이 잘 동작하게 만드는 것이 우리의 최종 목표라 하겠다.
저 그럼 배틀시티 게임에 필요한 객체식별부터 시작해 보자. 우리 게임무대에 등장인물들은 배우(Actor)객체 중심으로 찾아보면 쉬운데, "주인공 탱크", "적 탱크", "벽 더미", "대포알", "폭발장면"이 있다. 크게 구분해 보면, "주인공", "적", "장애물", "무기" 라는 역할을 한다고 말할 수 있다. 우리의 고민은 여기서 다시 시작된다. 이 게임을 예제수준에서 먼저 절차지향형으로 개발해 본 딱 그정도만 기능구현하고 더이상 추가구현 없는 전혀 건드리지 않을(?) 게임으로 생각하는지, 아니면 개인적인 의욕이 있어 이 게임을 더 개선해서 더 발전된 형태의 버전업이 되는 게임, 예를들어 적으로서 탱크만이 아닌 다양한 형태의 다른 적이 등장한다던지, 내가 사용하는 무기도 대포알 뿐만 아니라 다른 형태의 공격무기도 갖게 할 것인지, 지금은 장매물이 벽 더미이지만, 그 외의 다른 형태의 장애물도 생각하는지 등등에 따라 당장의 상속의 깊이에서부터 객체지향 설계의 스케일이 달라지기 때문이다.
스케일을 너무 크게 잡고 설계 하는 부분에 대해서는 애시당초 이 책이 고려한 학습 난이도에 비해 높고, 분량이 많아져서 기회가 되면 이 책의 다음 레벨의 책에서 더 진도를 나가기로 하고, 이 책에서는 적절한 수준으로 타협하여 설계하도록 하겠다. 그럼, 먼저 주인공과 적의 역할만 놓고 생각해보자. 주인공과 적의 목표는 이동하면서 서로 상대방을 포쏘기 공격해 맞추는 것이다. 이 때 둘의 사용하는 무기(대포알)가 동일하고 이동하는 방법 역시 전후좌우의 직진이동만 할 수 있어 둘 다 똑같은 제약을 갖는다. 그렇다. 탱크라는 한 공통 객체를 만들어 그 객체로부터 재활용해 주인공 탱크/적 탱크 각각을 생성할 수 있는 것이다.
그럼, 이를 또 한편으로 탱크객체가 해야할 책임(외부의 객체의 사용자에게 제공하게 될 정보 또는 요청에 의한 행동)에 대해서 고민해보자. 그런데 책임들을 정하기에 앞서 먼저는 객체들 간에 협력에 대해 생각하는게 우선인데, 협력에 대해 고민하면 자연스럽게 객체의 책임을 이끌어 내기 때문이다. 즉, 어떤 객체가 탱크객체에게 어떤 행동의 요구를 할 것인가에 대한 것을 고민해보자. 가장 본질적인 요구는 각 객체을 생성(creation)하는 것에서부터 출발할 수 있다. 각 객체를 첨부터 무조건 다 만들어 놓고 시작하는게 아니라, 특정 객체가 특정 객체의 생성을 특정 시점에 요구할 수 있는 것이다. 예를들어 스페이스 바를 눌러 대포를 쏘는 시점에 "총알" 라는 객체가 생성되고 날아가기 시작하면 되는 것처럼 말이다.
게임이 맨 처음 시작했을 때 화면에 맨 처음 등장하는 객체들은 무엇인가? "주인공 탱크", "적 탱크", "벽 더미" 이다. 그리고, 객체는 아닌 단순 이미지인 배경 이미지가 존재해야 할 것이다. 그럼, 이들 객체의 생성은 누가할 것인가? 엔트리 블록코딩에서는 엔트리(시스템) 자체가 내부적으로 자동으로 해주었다면, 이젠 그것도 우리가 직접 코딩으로 해야하는 것이다. 객체들이 화면에 그려지기 위해서는 draw 콜백함수 안에서 각 객체의 draw 메소드를 호출해야 할 것이고, 그 말은 draw 콜백함수 이전에 최소한 생성이 되어 있어야 하는 것을 전제한다. 다음의 battle_city_oop.py 라고 명명한 파일에서 방금 언급된 내용의 기본적인 코딩을 해보도록 하겠다.
탱크의 이동에 대해 우리가 간과한(?)이 하나 있는데, 탱크이동에 제약이 있다는 것이다. 이 제약은 기존 절차지향으로 개발할 때도 다 인지가 되었던 것으로 탱크가 벽을 통과해 이동할 수 없고, 보이는 전체 게임화면을 넘어 이동해서도 안된다. 두 제약은 이동제약이란 측면에선 유사하지만 실제 구현관점에선 화면경계 제약은 단순 범위제약이고, 벽 관련 제약은 두 객체(탱크와 벽)의 충돌확인 후 이동의 제약이라 서로 내용이 다르다.
여기서 전자의 경우는 꼭 탱크객체에게만 유효할까? 다른 객체에는 필요없을까? 를 생각해보면, '총알' 객체에게도 필요한 부분이다. 왜냐하면, 총알객체가 화면경계 밖을 넘어서자마자 객체를 삭제(메모리에서 제거)해야 하기 때문이다. 이렇게 모든 객체에게는 필요하지 않지만, 일부 객체에겐 필요한 기능을 구현하기 위해 객체지향 프로그래밍에서 반드시 알아야하는 또다른 개념이 하나 등장하는데 추상 클래스(abstract class) 또는 인터페이스(interface)라는 개념을 배워야 할 시점이 왔다. 이 부분은 이론적 이해가 필요해 내용이 길어질 수 있으므로 다음 장에서 좀 더 상세히 설하도록 하겠다.
Last updated
Was this helpful?