5.2 화면에 플래피버드(오브젝트) 나타내기와 움직이기
Last updated
Last updated
이제 우리 게임의 주인공 플래피버드 객체(object)를 화면에 그려줄 차례이다. 전혀 어렵지 않다. 아래와 같이 이전 코드에서 딱 2라인(5번, 9번 라인)의 코드만 더 추가하면 된다. 그리고, 실행해보자. 플래피버드가 게임화면에 좌측중앙 언저리즘에(정확히는 객체의 한가운데 중앙이 (x, y좌표)로 (75, 350) 위치에) 잘 나타날 것이다.
객체를 생성할 때도 함수호출처럼 유사하게 생성시 클래스로 넘겨야 할 인자값이 있을 수도 있고 없을 수도 있는데, 이 경우는 2가지 인자값을 요구하고 있다. blit 함수에 사용할 때와 유사한 2가지 정보(Actor객체의 외관이 될 이미지 파일이름과 그 이미지가 화면에 어디에 그려질지에 대한 위치정보(정확하게는 해당 이미지의 중심값(center)이 화면상에 위치해야 할 위치정보)를 객체생성 위한 클래스의 인자값으로 넘기게 된다.
그렇다면, 라이브러리 저작자가 우리를 위해 미리 틀을 만들어 제공하는 Actor 클래스의 목적과 용도는 무엇인지를 어떻게 알 수 있을까? 그렇다 지난 시간에 배운 것처럼 라이브러리 메뉴얼(문서)를 찾아보면 저자 자신이 이미 해당 클래스의 목적과 사용방법을 상세히 설명하고 있다. 그러나 Actor 클래스의 목적은 문서를 찾아보지 않더라도 Actor라고 '배우'라는 뜻으로 의도적으로 의미부여한 이름에서 직관적으로 유추할 수 있듯이, 우리 게임이란 무대에 등장하는 움직임이 가능한 배우(객체)를 만드는데 사용한다 것인데 예를들어 우리 게임무대에는 크게 2개의 배우(플래피버드 배우와 플래피버드가 부딪히지 말고 통과해야 하는 파이프 배우)가 있을 수 있다. 지금은 그중에서 지금은 먼저 플래피버드 배우(Actor)객체를 만든 것이다.
🔢 객체는 잘 생성되어졌고, 이제 이를 화면에 출력만 하면되는데 9번 라인의 코드처럼 Actor객체가 제공하는 함수인 draw함수를 호출해서 화면에 그려낼 수 있는데, 현재 생성된 객체를 가리키고 있는(참조하고 있는) 변수인 flappy_bird를 통해 해당 함수를 접근할 수 있다.
플래피버드 객체를 화면에 잘 출력했다. 이제 우리에게 남은 일은 이 게임의 컨셉인 플래피버드의 기본 움직임을 구현하는것인데 기본 움직임은 다음과 같다. 첫번 째는 플래피버드가 강력한 중력(?)의 힘을 받아 가만있으면 아래방향으로 추락하는 것이고, 두번 째는 이 힘을 극복하기 위해 마우스를 클릭할 때마다 추진력을 발휘해 공중으로 얼마간 비상하게 되는 움직임이다.
🔢 먼저, 플래피버드 객체가 화면 아래로 추락하는 중력의 힘을 구현하자. 이것은 다른 말로 말하면, 객체가 아래로 추락하는 움직임이라는 애니메이션의 구현이다. 애니메이션의 기본적인 구현은 우리가 잘 알다시피 매우 짧은 시간안에 아주 조금씩 이미지(여기서는 객체)의 변화지만 빠르게 사용자의 눈에 보여주게 된다면, 마치 우리 눈에는 마치 움직이고 있는 것처럼 보이는 착시효과이다. 구체적으로 잔상 효과라는 착시인데 실제로는 이미지(객체) 사이에 짧은 중단이 있어도 연속적인 이미지가 계속해서 지속하는 것처럼 보이는 현상을 말한다.
우리보고 애니메이션의 메커니즘을 다 구현하라고 하면 갑자기 멘붕(?)이 올 수 있으나, 알다시피 파이게임제로는 최대한 쉬운 코딩으로 게임구현을 목표하고 있기 때문에 그런건 이미 다 내부적으로 구현되어 있고, 우리에게 요구하는 것은 그 한장한장의 이미지(객체)들의 움직임 변화에 대한 것만 코딩해주면 된다. 기존에 우리는 라이브러리가 요구하는 draw 콜백함수를 통해 객체를 화면에 그렸듯이, 애니메이션을 위해서는 라이브러리가 요구하는 update 콜백함수를 통해 객체의 움직임을 표현하면 된다.
그러나 여기서는 이미지(객체) 자체의 변화는 없이 단순히 중력이 작용하는 상황을 애니메이션화해 코드로 표현하면 다음과 같다.
라이브러리는 update 콜백함수를 최대 초당 60회(60 FPS(Frame Per Second)라고 부름)를 자동 콜백호출하게 된다. 호출될 때마다 해야하는 일은 플래피버드 객체가 매우 조금씩(1픽셀씩) 화면 아래 방향으로 움직이면 되는 것이다. 10번 라인에서 flappy_bird.y += 1 이라고 코딩했는데, 생성된 객체(인스턴스)를 가르키는 flappy_bird 변수는 위에 살펴본 바와 같이 생성된 객체의 접근을 대리하는 참조 포인트로서 이 변수를 통해 객체가 객체 이용자들에게 제공하는 함수를 접근할 수도 있고, 객체가 갖고 있는 속성(여기서는 x, y좌표로 표현되는 화면상의 위치정보) 또한 접근할 수 있다. 우리는 객체의 y좌표값를 접근해 그 값을 1픽셀(pixel)씩 증가시키고 있다. 여기서 화면 아래로 이동시키기 위해서 값을 증가시켜야 하는 이유는 우리가 이전 장에서 살펴본 파이게임제로에서의 화면좌표계에 의한 것이다. 실행결과를 살펴보자. 플래피버드 객체는 실행하자마자 마치 중력힘이 존재하는 것처럼 자유낙하하게 된다. 만약 더 빠른 속도로 자유낙하 시키고 싶다면, 어떤 값을 바꿔야 할까? 그렇다 일회 움직임의 픽셀값을 기존 1픽셀보다 더 크게 하면 될 것이다.
두번째로 마우스버튼을 누를 때마다 현재 위치에 위쪽으로 움직이게 하는 것을 코딩하자. 어떻게 코딩하면 좋을까? 블록코딩에서의 경험상, 또 구체적으로는 우리가 이전서에서 배웠던 이벤트 주도형 또는 이벤트 기반형(Event-Based) 프로그래밍 패러다임을 적용하면 되지 않을까? 라는 생각이 들었다면, 여러분은 이제 텍스트코딩 세계의 감을 잡아가고 있는 것이다^^
🔢 기존 코드에서 14-15번 라인에 on_mouse_down 콜백함수(마우스 클릭시마다 라이브러리에서 자동으로 호출되는) 구현을 하나를 추가했다. 콜백함수이기 때문에 함수명은 우리가 정한 이름이 아니고, 라이브러리에서 이미 정해놓은(라이브러리 문서참조) 이름으로 우리는 정확히 그 이름으로 된 함수명을 사용하고, 라이브러리에 의해서 그 함수가 자동으로 불렸을 때 해야할 행동만 함수 안에 구현하면 된다. 불렸을 때 해야할 일은 다음과 같은데, 15번에 라인에서 구현한 것처럼 플래피버드 객체를 현재 위치에 50픽셀(pixel) 위쪽 방향으로 이동시켜 마치 공중으로 부상하는 것 같은 움직임을 만드는 것이다. 위에서 해본 자유낙하 구현과 크게 다를 건 없어서 이해하기 전혀 어렵지 않을 것이다. 다만, 기존 위치에서 -50을 한다는 것은, 역시나 파이게임제로에서의 화면좌표계 때문이고, 화면위쪽으로의 이동은 현재 y축 위치값보다 줄어야들어야(마이너스 해야) 함을 알 수 있다. 현재까지의 코드를 실행시켜보자. 기대했던데로 자유낙하하는 플래피버드는 마우스 클릭을 통해 부양시킬 수 있다.
여기까지 잘 따라온 당신은 이처럼 파이게제로는 적은량의 코드로도 게임을 손쉽게 만들어 갈 수 있다는 것을 이해하기 시작했을 것이다. 현재까지의 코드도 괜찮긴 하지만, 코드를 실행해 보면 플래피버드의 동작에 다소 아쉬운 점이 있다. 그것은 공중부양하는 동작이 자연스럽지 않고, 뚝뚝 끊어짐과 함께 급한 순간이동처럼 느껴지는 상승동작에 관한 것이다. 이 부분을 어떻게 하면 자연스러운 동작으로 개선할 수 있을까? 다음 장에서 살펴보도록 하자.
🔢 이제 코드 분석시간이다. 먼저 우리는 여전히 객체지향 패러다임 안에서 코딩중임을 기억하자. 새롭게 추가한 5번 라인부터 살펴보자. 여러분들은 이 코드를 보자마자 Actor라는 함수를호출해서 리턴된 결과값을 flappy_bird라는 변수에 저장하고 있는 것으로 보일 수 있다. 하지만, 큰 오해가 있는데 Actor는 일단 함수호출이 아니고, 객체(object)를 생성하고 있는 중인 것이다. 어떻게 그것을 단번에 알 수 있는지는 파이썬 문법약속(꼭 파이썬만이 아닌 다른 프로그래밍 언어도 동일)으로 함수이름은 소문자로 시작해 만들고, (class, 객체를 정의하는 문법으로 함수를 정의할때 사용했던 def 문법과 유사) 이름은 대문자로 시작해서 만든다는 관습적인 규칙을 잘 따랐다라고 가정할 수 있고, 그것을 근거로 Actor가 대문자로 시작하고 있기 때문에 Actor라는 클래스를 통해 객체를 생성했고, 그 생성된 객체(참고로 객체지향 패러다임에서는 클래스로부터 생성된 객체를 특별히 인스턴스(instance)라는 용어를 사용해 지칭)를 flappy_bird라는 변수에 저장하고 있다.