이번 절에서 우리는 우리 무대의 등장인물을 각각 움직여 보도록 하겠다. 가장 먼저는 이 게임에서 유일하게 사용자가 조작할 수 있는 반사판을 화면 하단의 좌우방향으로만 움직이되 화면의 끝을 넘어가지는 못하도록 코딩하겠다.
TITLE = 'Breakout'
WIDTH = 800
HEIGHT = 600
GAP_FROM_SCREEN = 50
ball = Actor('ball', (WIDTH / 2, HEIGHT / 2))
bar = Actor('bar', (WIDTH / 2, HEIGHT - GAP_FROM_SCREEN))
# 4행*8열짜리 블록더미 만들기
blocks = []
for block_row in range(4):
for block_col in range(8):
block = Actor(
'block',
(block_col * 100, block_row * 32 + GAP_FROM_SCREEN),
anchor=('left', 'top')
)
blocks.append(block)
def draw():
screen.blit('space', (0, 0))
ball.draw()
bar.draw()
for block in blocks:
block.draw()
def update():
# 반사판의 이동을 화면 안에 안에 가두기
if bar.left < 0:
bar.left = 0
if bar.right > WIDTH:
bar.right = WIDTH
def on_mouse_move(pos):
x, y = pos
bar.centerx = x
TITLE = 'Breakout'
WIDTH = 800
HEIGHT = 600
GAP_FROM_SCREEN = 50
ball = Actor('ball', (WIDTH / 2, HEIGHT / 2))
bar = Actor('bar', (WIDTH / 2, HEIGHT - GAP_FROM_SCREEN))
# 4행*8열짜리 블록더미 만들기
blocks = []
for block_row in range(4):
for block_col in range(8):
block = Actor(
'block',
(block_col * 100, block_row * 32 + GAP_FROM_SCREEN),
anchor=('left', 'top')
)
blocks.append(block)
# 볼의 초기 (방향이 있는)속도값
vx = 5
vy = -5
def draw():
screen.blit('background', (0, 0))
ball.draw()
bar.draw()
for block in blocks:
block.draw()
def update():
global vx, vy
# 반사판의 이동을 화면 안에 안에 가두기
if bar.left < 0:
bar.left = 0
if bar.right > WIDTH:
bar.right = WIDTH
# 각각의 x와 y 방향으로 거리 vx와 vy만큼 공을 이동시키기
ball.move_ip(vx, vy)
def on_mouse_move(pos):
x, y = pos
bar.centerx = x
그리고, 이를 update 함수 안에 적용하여 초당 60회 호출이 되는(5.2절에서 이미 언급) update 함수 호출 때마다 객체를 계속 이동시키기 위해 41번 라인에 ball 객체가 갖고 있는 move_ip 함수(메소드)를 활용했다. 이 함수의 인자로 우리가 설정한 두축의 초기 속도값을 전달하면, 호출될 때마다 해당 객체의 현재 위치에서 그 속도의 다음위치를 이동시켜주게 된다. 만약 move_ip 함수}를 사용하기 싫으면 그 대신에 다음과 같이 코딩해도 똑같은 의미이고, 결국 ball 객체의 x, y 위치값을 속도 변화량인 vx, vy 만큼 매번 누적변화를 만든다는 의미이다.
ball.x += vx
ball.y += vy
우리는 지난 절에서 많은 것을 배우느라 머리 속에 넣을 것이 많아 약간 피곤(?)해졌을 수 있어서, 여기서 간단히 이정도로 이번 절을 마무리하겠다. 다음 절에서는 더 재미있는 공을 반사시키고, 블록을 격파하는 알고리즘에 대해 배워볼 것이다.
34-36 라인에서 마우스가 움직이는 이벤트가 있을 때마다 콜백호출 되는 on_mouse_move 콜백함수를 사용하도록 하자. 해당 함수에 대한 자세한 사용법은 파이게임제로 라이브러리 문서를 살펴보면 될 것이다. 간단히 설명하면 on_mouse_move 함수의 첫번째 인자인 pos 는 움직이는 마우스 포인터의 현재 위치(x, y좌표값)를 저장하고 있는 것으로, 35번 라인에서 pos안에 두 값(x, y좌표값)을 각각의 x, y 변수값의 분리해낸 후, 우리는 이것의 x좌표값을 bar.centerx 위치(bar객체 중심위치의 x좌표)와 동조화시키도록 하면서, 마우스를 움직일 때마다 bar 객체가 계속 따라서 움직이게 할 수 있는 것이다. 이후 움직이는 bar 객체가 게임화면을 넘어서까지 이동할 수 없도록 update 콜백함수 내의 29-32번 라인처럼 만약 화면좌측 끝을 넘어간다면(bar.left < 0 라면) 그때는 실제로 음수값을 갖게하면 안되기 때문에 최대치인 0값을 그대로 유지하게 하고, 마찬가지로 화면우측 끝을 넘어간다면(bar.right > WIDTH 라면) 그 이상의 값을 갖지 못하도록 bar.right의 최대치인 WIDTH를 유지하도록 하면된다. 이러한 방식으로 그 움직임의 최대치 경계를 지어주면 된다.
두번째로 공을 움직임을 주기 위해 추가된 코드들을 살펴보도록 하겠다. 공을 이동시키려면 기본적으로 파이게임 좌표계 안에서 어떤 방향(direction)으로 얼마만한 속력(speed)으로 이동하겠는가라는 기준을 정해야 할 것이다. 이 두 가지 속도와 방향이 합쳐진 물리량을 속도(velocity)라고 부른다. 지금은 물리시간은 아니니 이 개념의 명확한(?) 이해가 필요하면 나무위키 등을 찾아보자^^; 다만, 어렵게 생각할 필요는 없고, 기존의 파이게임좌표계를 기준하면 되고, x축에서 좌측방향(음수) 또는 우측방향(양수)으로 한번 이동할 때는 얼마크기만큼 이동하겠느냐의 개념이고, 마찬가지로 y축에서 상측방향(음수) 또는 하측방향(양수)으로 한번 이동할 때 얼마크기만큼 이동하겠느냐 값이고, 각각의 두축의 속도의 초기값 갖고 시작해야 하기 때문에 21-22라인에 그 내용을 글로벌 변수로 코딩했다. 글로벌 변수로 사용했다는 의미는 이 변수값이 함수 여러곳에 사용될 수 있거나 또는 함수 안에 이 변수값을 바꿀 수 있고, 그 바뀌어진 값이 다음번 함수 진입시마다 계속 유지된 상태여야 한다는 목적을 실현시키기 위한 의도적인 코딩이다. 이번의 경우는 후자의 목적실현에서 글로벌 변수로 코딩했다.