6.1 게임무대에 배경과 배우 등장시키기
Last updated
Was this helpful?
Last updated
Was this helpful?
이번 절에는 코딩의 첫 시작이니 우리 게임의 무대인 게임화면에 배경입히고, 게임무대의 배우들인 블록더미, 블록더미의 블록을 격파하게 될 공, 사용자의 조작이 필요한 공을 반사시킬 반사판(영어로는 패들(paddle)이라 부르나, 우리는 bar라는 이름을 사용함)을 등장시켜보는 것까지 해보겠다. 우리가 만들게 될 게임의 최종 결과물은 다음과 같다. 결과화면을 먼저 보고나면 코드 이해가 훨씬 쉬울 것이다.
이제 블록더미의 구성을 자세히 살펴보자. 가로로 8개씩, 세로로 3열의 형태를 갖고 있는데, 2번 라인에서 정한 게임화면의 가로크기가 800px(픽셀)이기 때문에, 그 안에 8개의 블록을 연이어 붙혀 한 행으로 놓으려면, 예상하기로 블록 1개의 가로길이는 100px 이어야할 것으로 유추할 수 있다. 그 예상이 맞았고, 1개의 블록객체는 (블록 이미지)크기는 가로세로(100 x 32px) 크기다.
for 문 안에 for 문이 들어가는 구조로, 블록더미 한 행 안에서 8개의 블록을 채우는 안쪽 루프와 그 다음행으로 넘어가는 즉 행을 옮기는 바깥쪽 루프를 번갈아 돌면서 생성된(13~17번 라인) 각각의 독립된 블록객체를 리스트 안에 차곡차곡 채우는(18번 라인) 것이다. 리스트에 값을 추가하는 함수는 List 객체(List 자체가 사실은 그 본질은 객체였다 라는 것도 참고로 알아두자)가 제공하는 멤버함수인 append 함수를 이용할 수 있다.
먼저 range 함수는 파이썬언어의 내장함수로 아주 간략화시켜서(본서는 순한맛 버전으로 일단 이정도만 알고 넘어가고) 설명하면, 다음과 같은 행동을 하는 함수이다.
예시로 list(range(4))를 실행시켜 어떤 결과 리턴되는지 확인해보자.
range함수의 결과가 range객체들이기 때문에 list함수로 감싸서, 이를 list형태로 변환해 보는게 우리가 그 실체를 한눈에 이해하기 편한다. 즉, 인자로 4를 넘기면, 0부터 시작해서 3까지의 연속적인 정수값을 담겨져 있다라고 이해할 수 있다.
이제 for-in 문법구문을 이해해 보자. 여기서 "연속형 객체"라는 것은 리스트 같이 여러 개의 값을 값는 데이터타입을 말한다.
다음의 코드 예시를 보면 이해가 빠를 것이다. for-in 구문 안에 내용을 총 4회 반복 수행할 것이고, 매 반복 회차마다 리스트 안에 값(이를 아이템이라 부름)을 우리가 정한 변수명으로 하나하나씩 순차적으로 자동적으로 가져오게 되면서 반복을 수행한다.
위에 예시로 사용한 for item in [0, 1, 2, 3]은 사실은 for item in range(4) 코드와 동일한 것으로 간주할 수 있다. 여기까지 이해가 되었다면, 이제 11번 라인의 for block_row in range(4): 구문을 이해할 수 있을 것이다. 총 4회 반복을 수행하되 매 반복회차마다 block_row 변수값이 차례대로 0~3까지의 값이 될 것이고, 12번 라인의 for block_col in range(8):은 총 8회 반복을 수행하되 매 반복회차마다 block_col 변수값이 차례대로 0~7까지의 값이 될 것라는 것을 예상할 수 있다. 이것을 활용해서 15라인에 block_row, block_col변수값을 활용해 Actor 객체생성시 위치값을 산정할 수 있게 되는 것이다.
왜 anchor를 옮겨야 하느냐라고 묻는다면, 게임화면의 좌측면에 딱 붙혀서 거기서부터 출발해 블록객체 더미를 화면에 그려나가고 싶어서이다. anchor를 옮기지 않고 화면에 블록객체 더미를 그려보면 이 말의 의미를 곧바로 알게 되는데, anchor의 디폴트값이 이미지의 중앙이므로, anchor를 옮기지 않고 그리면 아래의 그림의 상단처럼 블록의 절반이 잘려나간 채로 그려지기 때문이다.
본 장의 1절부터 기존에 공부하지 않았던 개념이 몇 개 등장해 예상보다 설명이 많아지고, 길어진 면이 있다. 다음 2절에서는 등장인물의 움직임 알고리즘 위주로 재미있게 공부해보자.
21번 라인의 게임의 배경을 그리는 부분은 이미 본서의 첫 게임을 만들면서 5.1절 절 전체를 할애해 설명했기 때문에 독자분들이 충분히 잘 이해하고 있을 것으로 추가적인 설명이 필요 없을 것 같다. 참고로 이번 게임제작에 필요한 이미지는 이곳에서 다운로드 할 수 있다. 또는 커스텀 뮤 에디터를 사용 중이라면 뮤 에디터의 작업 디렉토리인 (사용자계정)\mu_code\examples\pygame_zero\images 안에서 복사해 올 수 있다. 다만, 기억해야 할 것은 5.1절에서 이미 언급했듯이, 우리가 코딩시 사용하는 이미지들은 항상 코딩하는 소스코드가 존재하는 폴더(디렉토리)의 하위 폴더로서 존재해야 하며 폴더명은 images 여야만 정상인식되어 사용할 수 있다 규칙을 다시한번 기억하면 좋겠다.
6-7라인에서 먼저, 두 주연배우인 볼(ball)과 반사판(bar)의 배우(Actor)객체를 만들면서 이미지이름과 이 이미지가 화면상에 위치할 위치정보, 이렇게 두 가지의 생성인자값을 사용해 생성하였다. 이어서 공이 닿아 부서지게 될 블록더미라 불리는 블록객체들의 모음을 만들어야 하는데, 보기에는 한 덩어리처럼 보여도 공이 닿아 부셔져야 하는 블록 하나하나가 다 사실은 독립된 블록객체이다. 그 전에 먼저 위에서 살펴본 본 게임의 최종화면을 잘 관찰해보면 블록더미는 게임화면(screen) 최상단에서 어느 정도의 빈 공간의 간격를 떼고 이후에 블록들이 하나의 더미를 이뤄 모여있는 구조와 동시에 공을 반사시키는 반사판 역시도 화면 최하단에서 윗방향으로 어느 정도 간격을 뗀 위치를 갖는 특징을 발견했을 것이다. 이 어느정도의 간격은 우리가 임의로 정한 것이고, 5번 라인에서 이를 의미하는 변수값으로 GAP_FROM_SCREEN 라고 이름짓고, 50px(픽셀)의 간격을 할당하였다.
이제 이 정보를 기반으로 코딩을 하면 되는데, 먼저 독립된 각각의 블록객체를 차곡차곡 담아서 하나의 블록더미를 만들 공간이 필요한데 이 경우, 리스트(List)라는 데이터 형태가 딱이고, 따라서 10번 라인에서 blocks라는 빈 리스트를 하나 생성했다. 이후, 이 리스트에 각각의 생성된 독립적인 블록 하나하나들을 화면에 보여줄 순서에 맞게 차곡차곡 담으면 되는데, 이 때 화면에 보여지는 순서라는 것은 행을 먼저 쌓고 이후 열을 쌓는 순서로 하던, 반대로 열을 먼저 쌓으면서 행을 늘려가는 방식으로 쌓던 어떤 방식이든 관계는 없다 본인이 임의로 택한 방식으로 하면 되는데, 본 서에는 먼저 한 행을 다 쌓고, 이후 다음행으로 넘어가서 쌓는 방식으로 할 것이며, 이런 상황에 적합한 코딩이 11-12라인에서 볼 수 있는 2중 for 루프문(nested loop statements)이다.
이제 반복문을 이해해보도록 하자. 를 거쳐오지 않은 분들을 위해 for-in range() 구문을 한번 더 설명하면, 반복에 사용하는 이 구문은 우리가 엔트리 블록코딩에서 숱하게 사용해 봤던 "몇 회 반복하기" 코딩블럭이라고 생각하면 될 것이다. 일단 저 구문에서 for-in과 range 함수를 분리해서 살펴보는게 필요하다.
블록객체 생성시 활용하는 파라미터 중에 전에 배우지 않은 1가지가 더 남아 있는데, 16번 라인에 있는 anchor에 관한 것이다. anchor는 우리가 엔트리 블록코딩에서 이미 사용해봤던 각 오브젝트마다 갖고 있는 중심점을 말하는 것으로, 파이게임에서는 이를 anchor라고 지칭하고, 엔트리코딩에 코딩시 때로는 그 중심점의 이동이 필요했었던 것처럼, 텍스트코딩에서도 마찬가지 이유로 필요할 때가 있는데, 지금 이순간이 바로 그 순간이다. 엔트리 때도 그랬지만, 기본적으로 Actor 객체의 디폴트 anchor는 이미지의 한 가운데(center) 중심이다. 우리는 이것을 아래 화면상에 보이는 좌측최상단(topleft 또는 lefttop)으로 옮기고자 하며, 이 경우 16번 라인에서 보는 것과 같이 anchor=('left', 'top') 이란 인자값을 넘기면 되는 것이다.
이제 마지막으로 draw 함수 안에서 블록더미를 그리는 23-24라인의 코드를 살펴보자. 우리가 이미 배운 for-in 반복문을 사용하고 있고, blocks 라고 하는 독립된 블록객체들을 모아놓은 리스트 안에 존재하는 블록객체 하나하나씩 꺼내서 화면에 일일이 그리는 일을 리스트 안에 객체가 다 꺼내질 때까지 반복하고 있다는 것을 알 수 있다.