[파이썬 게임 프로그래밍 공부] 3. tkinter 키 입력

Alegruz
2017-09-02 01:21
조회수 4873

왼쪽 방향키를 누르면 왼쪽으로 가게 설정하고 싶은데, 어떻게 그렇게 설정할 수 있을까요?

우선, 키 입력을 논하기 전에, 움직이는 방법부터 알고 지나갑시다. 여기서 필요한 것은 바로 move 메소드입니다. 이 메소드에 대해 공부하기 전에, 새로운 클래스 GameObject를 만듭시다. 공만 움직이는 기능 부여하지는 않을테니까, 미리 게임오브젝트라는 클래스 만들어놓고, 움직임이 필요한 애들 상속시킵시다.


class GameObject:
    def __init__(self, canvas, item):    # the object needs to be drawn on the canvas and needs its identity (item).
        self.canvas = canvas
        self.item = item

    def move(self, x, y):
        self.canvas.move(self.item, x, y)    # the move method moves an item to the given argument, (x, y)


자 이제 우리들의 작고 귀여운(?) 하얀 공 클래스를 만들어봅시다. 꼭 GameObject를 상속받아야해요.


class Ball(GameObject):
    def __init__(self, canvas, x, y):
        self.radius = 10
        item = canvas.create_oval(x-self.radius, y-self.radius,
                                  x+self.radius, y+self.radius,
                                  fill='white')
        super(Ball, self).__init__(canvas, item)


우리 공에게 좀 더 정석을 쏟아서 반지름 인스턴스를 만들어 주었어요. 자 이제 캔버스에 공을 그린 다음 움직여 봅시다.


self.ball = Ball(self.canvas, self.width/2, self.height/2)
self.ball.move(100, 100)


프로그램을 실행시켜서 공이 움직였는지, 안움직였는지 확인해보세요. 입력한 값만큼 움직인 것을 확인할 수 있습니다.

자, 이제 공을 움직이는 방법을 알았으니, 키 입력을 어떻게 하는지 알아볼까요?

키 입력을 하는 방법은 아주 고맙게도, tkinter 모듈의 메소드 중 하나에 있습니다. 바로 bind 메소드입니다. bind 메소드의 구조는 다음과 같습니다,


bind('<Key>', function(event))


딱 보면 알겠지만, 어떤 한 함수를 키에 종속(bind)시키는군요. 그렇다면 실 예제로 한 번 이해해보겠습니다.


import tkinter as tk

root = tk.Tk()

def hello(event):
    print("Hello")

def callback(event):
    frame.focus_set()
    print("World")

frame = tk.Frame(root, width=100, height=100)
frame.bind("<Key>", hello)
frame.bind("<Button-1>", callback)
frame.pack()

root.mainloop()


이 예제 코드를 실행시킨 뒤 아무 키나 눌러보면, 파이썬 쉘 창에 "Hello"라는 글자가 프린트 될 것입니다. 만약 프레임을 마우스 왼쪽 버튼으로 클릭을 해본다면, "World"라는 단어가 프린트될 것입니다.


이제 이 메소드를 이용해 공을 움직여 봅시다. 다만 한 가지 문제가 있네요. 위 예제에서 보면 알겠지만, bind 메소드를 이용해 함수를 키 입력에 종속시키려면, 함수는 event를 변수로 받아야합니다. 하지만 저희들이 설정한 move 메소드는 그런거 없죠? 이러한 문제를 해결하기 위해, 첫번째 변수를 무시하는 기능이 있는 lambda를 사용하는 것입니다. 사용방법은 다음과 같습니다.


self.canvas.bind('<Left>',
                 lambda _: self.ball.move(-10, 0))
self.canvas.bind('<Right>',
                 lambda _: self.ball.move(10, 0))


이제 공 좀 굴릴 수 있겠네요. 한 번 프로그램 실행해보세요. 뭐라구요? 공이 안움직인다구요?

아마 시점이 공에 고정이 되어있어서 그럴겁니다. 시점을 캔버스에 고정을 해봅시다. 고정하는 방법은 간단해요. focus_set 메소드를 사용하면 됩니다.



self.canvas.focus_set()


자, 이제 갓겜인 공 굴리기 게임을 즐겨봅시다

물론 정확하게 말하면 이걸 게임이라곤 할 순 없겠죠? 이제 게임 규칙이나 메커니즘을 적용할 시간이 된 것 같네요.


import tkinter as tk

class Game(tk.Frame):
    def __init__(self, master):
        super(Game, self).__init__(master)
        self.width = 610
        self.height= 400
        self.canvas = tk.Canvas(self, bg = '#aaaaaa', width = self.width, height = self.height)
        self.canvas.pack()
        self.pack()
        self.ball = Ball(self.canvas, self.width/2, self.height/2)

        self.canvas.focus_set()
        self.canvas.bind('<Left>',
                         lambda _: self.ball.move(-10, 0))
        self.canvas.bind('<Right>',
                         lambda _: self.ball.move(10, 0))

class GameObject:
    def __init__(self, canvas, item):
        self.canvas = canvas
        self.item = item

    def move(self, x, y):
        self.canvas.move(self.item, x, y)

class Ball(GameObject):
    def __init__(self, canvas, x, y):
        self.radius = 10
        item = canvas.create_oval(x-self.radius, y-self.radius,
                                  x+self.radius, y+self.radius,
                                  fill='white')
        super(Ball, self).__init__(canvas, item)


if __name__ == '__main__':
    root = tk.Tk()
    root.title('Game Title')
    game = Game(root)
    game.mainloop()


2 0