7.1 스크롤 배경객체 만들기, 배경음, 배우(적, 주인공) 등장시키기
Last updated
Last updated
바로 아래 화면의 우리가 만들게 될 게임의 최종 결과물을 먼저 보고나면 코드 이해가 훨씬 쉬울 것이다. 다만, 이번 과의 맨 서두에서 언급했듯이 난이도 조절을 위해 기능동작 전체 다를 구현하지 않을 예정이고, 아래의 최종결과물 전체 다를 구현해보고자 하는 분들을 위해선 따로 공부할 수 있는 참조링크를 전달할 예정이다.
본격적인 게임제작에 앞서 이번 게임제작에 필요한 이미지, 사운드 등의 리소스들은 이곳에서 다운로드 할 수 있으며 게임에 필요한 이미지 파일들은 코드에서 사용한 이름 그대로 imgaes 폴더에 이미 저장되어 있고, 효과음은 sounds에 배경음은 music 폴더에 저장되어 있다고 간주하고 시작하겠다. 또는 커스텀 뮤 에디터를 사용 중이라면 뮤 에디터의 작업 디렉토리인 (사용자계정)\mu_code\examples\pygame_zero 안에서 복사해 올 수 있다.
이번 게임의 무대가 기존과 다른 점은 가만히 멈춰 있는 배경이 아니라, 움직임이 있는 배경(객체)라는 점이다. 만약, 귀하가 엔트리 블록코딩에 익숙하다면 배경이 객체가 될 수 있고, 객체처럼 다뤄 코딩할 수 있는 것이 전혀 낯설지 않을 것이다.
이전 예제들에서 배경을 단순 이미지처럼 사용할 때의 코딩에 대해선 다음과 같이 사용할 수 있다는 것을 우리가 익히 알고 있다.
그러나, 지금부터 우리가 하려는 것은 배경을 객체로 만들어, 무한반복 수직 스크롤하는 배경을 구현하려고 한다. 일단 스크롤 화면을 만들려면 물리적으로 나눠져 있지만 마치 하나의 파노라마 이미지로 볼 수 있는 최소한 2장 이상의 이미지가 필요하다. 여기서는 background 1, background2 로 이름 붙혀진 2장의 이미지 각각을 배우객체로 만들고, 첫번째 배경객체의 Anchor(중심좌표)는 전체화면의 가로, 세로의 각각 절반(WIDTH / 2, HEIGHT / 2) 이여야만 화면크기 안에 딱 맞게 그릴 수 있다. 그 배경객체와 상단에 이어져 존재하는 연이은 배경객체의 중심좌표는 최초 우리 눈에 보이지 않지만, 화면상단쪽 넘어에 위치시키기 위해 화면의 세로길이만큼 뺀((HEIGHT / 2) - HEIGHT) 위치의 Anchor 값(값으로는 -300)을 적용하게 된다.
해당 설명을 이해를 돕기 위해 그림으로 표현하면 다음과 같다.
배경을 객체화 하고, draw 콜백함수에서 화면에 그리기까지 했고, 이후 이 화면에 스크롤되어 무한반복으로 로테이션(rotation) 시키기 위한 코드, 즉 객체에 움직임을 만드는 코드이기 때문에 update 콜백함수에서 코딩되어야 한다. 화면이 이동속도는 3픽셀씩 아래로 이동시키고, 각 배경객체는 이동하다가 현재 보이는 화면영역 밖을 빠져나가게 되면, 화면상단에 보이지 않는 영역으로 즉시 이동시키는 방법으로 무한 로테이션을 시키도록 하면 된다. 이처럼 알고리즘 자체는 이미 블록코딩에서 많이 사용해 봤던 것과 전혀 다르지 않다. 지금까지 언급된 것을 이를 실제 코드로 표현하면 다음과 같다.
이제 이번 절의 나머지는 게임무대의 주인공들(적 비행기, 내 비행기)을 등장시킬 차례이고, 또 궁극적으로 이들을 제어하는데 필요한 기능 코드들에 대해 미리 고려해 보고, 이 기능들을 의미있는 코드덩어리인 함수로 만드는 함수화(functionalize) 작업을 잘 시키는게 좋은 개발자의 자질인 것이다. 이를 고민할 때, 다음과 같이 필요한 함수들의 이름짓기(naming)을 포함한 목록 미리 작성해 나열해 봄으로써 전체적인 구조적 윤곽을 잡은데 도움을 받을 수 있다.
함수화 하는 과정에서 우리가 젤 먼저 고려해야 할 우선 순위는 함수가 탄생하게 된 제일 큰 목적이 그러하듯이 중복되는 코드를 줄이기 위한 목적의 함수에 대해서 젤 우선순위로 생각할 수 있다. 그런데, 우리가 만들고자 하는 최종 프로그램이 어떠한 것이냐에 따라 생각보다 중복코드가 없는 경우도 있을 수 있다. 이번 게임에 경우가 그러한 편인데, 예를들어 1인용 슈팅게임이다 보니, 키보드 조작을 통한 움직임의 경우, 주인공 비행기만 필요하지 다른 여러 객체에서 공통사용은 없다. 또 총알을 쏘는 방식도 주인공이 쏘는 총알의 종류와 쏘는 방법과 적 비행기가 쏘는 총알의 종류와 방법에 있어 공통된 부분의 거의 없어 공통함수로 만들어 쓰는 유익도 없다. 따라서, 아래의 코드에서 확인해보면 우리 프로그램에서의 함수의 사용목적의 중복코드를 줄이기 위한 것이라기보다 코드 가독성을 높이기 위한 의미단위로 함수화 했다는 것을 알 수 있다.
총 5개 (move_player, shoot_bullets, create_enemies, check_collision) 의 빈 함수로 만들면서, 각 함수 안에 pass 라고 임시로 남겼는데, 이 의미는 당장은 실행 것이 아무 것도 없다는 것으로, 세부 구현을 이후로 미루기 위한 임시적인 표현구문이다. 여기서 왜 함수를 5개로 구분해 만들었느냐, 4 또는 6개는 안되느냐 등의 질문이 생길 수 있는데, 초보자 입장에서는 미리 어떤 함수가 필요하겠고, 몇 부분의 함수로 나눌지가 처음부터 잘 떠오르지 않는게 정상이고, 사실상 정확하게 이렇게 나눠져야 하는 100% 정답도 없는 것이 코딩이란 영역이다. 코딩은 본질상 해법이 여러 개일 수 있는데 그 중에서 가장 효율적인 방법을 찾아내는 과정이기 때문이다. 따라서, 이런 부분이 원활하게 되기 위해선 경험이 많이 쌓여야 함을 전제할 필요가 있다. 처음부터 너무 부담을 갖지 않는게 중요하고, 스스로 고민을 많이 해보고, 또 함수를 한번에 완벽하게 만들 수 있는게 아니고, 이렇게 저렇게 만들어 보고 반복적으로 고치보면서 점진적으로 발전해나가는게 자연스러운 과정이다. (코딩에서는 이러한 과정에 리펙토링 이란 용어를 사용한다.)
마지막으로 21번 라인의 게임 내내 배경음을 재생시키는 방법에 대해 언급하고 이번 장을 마무리 하겠다. 효과음과 배경음의 차이는 효과음은 짧은 단회성이고, 배경음은 길고 무한반복적인 특징이 있다. 효과음을 재생시키는 방법은 익히 알고 있고, 배경음 사실은 효과음처럼 재생할 수 있고, 그 음을 무한반복을 시키고자 한다면, 인자값으로 -1을 넘기면 된다.
그러나, 배경음에 대해 라이브러리 차원에서 전용 API를 제공하고 있기 때문에 이를 사용하는게 젤 목적에 부합한다고 할 수 있겠다. 배경음의 음악 파일종류는 mp3와 ogg 파일을 사용할 수 있고, 재생을 위한 함수는 라이브러리가 제공하는 music.play 를 사용하면 된다.
이처럼 게임 프로그램의 경우는 사실상 우리가 에서 배웠던 함수를 통한 보다는 에 더 적합하고, 그러나 우리는 지금까지 남이 만들어 놓은 클래스들을 통한 준비된 객체활용만 해봤지, 내 필요에 의한 나만의 객체를 만들어 활용하는 방법에 대해서는 아직 배우지 못했다. 사실은 필자가 여러분들이 사용자 정의 함수(User defined function)에 생성과 사용에 어느 정도 익숙해지길 기다린 면이 있고, 다음의 8과 예제부터는 우리도 우리만의 클래스와 객체를 통해 코딩하는 법을 배우도록 하겠다.