파이썬에서 모든 이벤트 처리는 bind를 통해서 이루어진다. bind는 "묶다" 라는 의미로서 이벤트가 발생할 때 어떠 함수가 호출 되도록 할 것인지를 연결하는 역할을 합니다. 다른 언어에도 bind 이외에 다른 용어 또는 키워드를 사용하지만 동일한 의미를 가지고 있습니다.
파이썬에서 이벤트와 함수와의 연결은 아래와 같은 형식으로 작성을 합니다.
widget.bind("이벤트 종류",함수명)
위젯은 윈도우, 버튼, 라벨 등 을 작성하고 bind() 함수를 이용하여 위젯에 발생한 이벤트를 두번째로 작성된 함수명으로 전달을 합니다. 아래 코드는 window 위젯에 키 이벤트처리를 위한 기본 예제 코드입니다.
from tkinter import *
def keyPressHandler(event):
print("Press: ",event.keycode)
def keyReleaseHandler(event):
print("Release: ",event.keycode)
window = Tk()
window.geometry("640x480")
window.bind("<KeyPress>",keyPressHandler)
window.bind("<KeyRelease>",keyReleaseHandler)
window.mainloop()
키를 눌렀을 때 KeyPressHandler 함수가 호출되고 호출된 함수안에 작성된 print() 함수를 실행합니다(Line 4, 5). 이때 계속 누르고 있으면 연속으로 계속 호출되는 것이 아닌 키를 누르는 시점에 한 번 호출됩니다. 반대로 키를 떼는 순간 keyReleaseHandler() 함수를 호출합니다.
이벤트에 의해 호출되는 함수를 정의할 때는 항상 매개변수 1개를 선언해야 합니다. 매개변수의 역할은 이벤트가 발생할 때 이벤트에 대한 정보를 함께 함수로 전달하는데 이때 전달된 정보가 매개변수에 저장됩니다. 위 예제의 키 이벤트의 경우 어떤 키가 눌러졌는지 키 정보가 event 변수에 저장됩니다. 그리고 event.keycode는 눌러진 키의 아스키코드 값을 알 수 있습니다.
키보드 이외에 마우스와 같은 많은 이벤트들이 있으며 필요에 따라 직접 찾아서 사용해보기 바랍니다.
이제 키보드 이벤트 기능을 게임 기본구조 코드에 적용하도록 하겠습니다.
일반적으로 게임에서는 키 입력에 따른 콘텐츠를 조작을 위해 키보드 이벤트를 사용한다. 이때 2가지 중요한 이슈가 있는데,
첫번째는 2개 이상의 키입력을 어떻게 처리 할 것인가?
두번째는 이벤트 처리 시점 입니다.
2개 이상의 키를 눌렀을 때 눌러진 상태를 알려주는 친절한 프로그래밍 언어는 없습니다.(라이브러리에서 지원해주는 경우는 있음) 가령, 대각선 위(북동 방향)로 계속 이동하도록 프로그래밍을 한다고 가정을 하였을 때, →, ↑ 방향 키를 동시에 누르고 있으면 두 키가 눌러진 시점에서 이벤트만 한번이 발생하고 끝입니다. 아래와 같이 프로그래밍을 한다면 누르는 시점 한번만 이동하고 더이상 움직임이 없다는 것입니다.
def keyPressHandler(event):
if (event.keycode==38):#아스키코드 38 는 ↑ 키
# 콘텐츠 위로 이동 코드
elif (event.keycode==39):#아스키코드 39 는 → 키
# 콘텐츠 앞으로 이동 코드
그래서
1. 키 이벤트 발생한 시점에서 콘텐츠(이미지)의 이동 코드를 작성하면 안되고, 콘텐츠의 이동 코드는 다른 코드영역(무한루프 영역)에서 작성해야 합니다.
2. KeyPress 이벤트 처리 함수에는 어떤 키가 눌러졌는지에 대한 키 정보를 저장하는 코드를 작성합니다. 그리고 KeyRelease 에는 저장된 키 정보에서 떼어진 키를 삭제하는 코드를 작성합니다.
앞에 내용들을 포함하여 작성한 코드는 아래와 같습니다.
from tkinter import *
keys = set()
def keyReleaseHandler(event):
if event.keycode in keys:
keys.remove(event.keycode)
def keyPressHandler(event):
keys.add(event.keycode)
window = Tk()
window.geometry("640x480")
window.bind("<KeyPress>",keyPressHandler)
window.bind("<KeyRelease>",keyReleaseHandler)
while True:
#
if (len(keys)>0):
print("Key: ", keys)
#
window.after(33)
window.update()
눌러진 키 정보를 저장할 때는 파이썬 자료구조 중 집합인 set() 을 이용하였습니다. set() 의 경우 유일한 값만 가지기 때문에 동일한 키값을 입력해도 자동으로 하나로 처리가 되는 장점이 있습니다.
위 코드를 게임 기본 코드 구조에 적용하면 아래와 같습니다. 이벤트 처리 함수의 경우, 클래스 멤버함수이기 때문에 매개변수가 하나 더 추가 되며 두번째 매개변수에 이벤트 정보가 저장됩니다.
from tkinter import *
class KeyboardEvent:
def __init__(self):
window = Tk()
window.title("키보드 이벤트")
window.geometry("640x480")
self.keys = set()
self.canvas=Canvas(window, bg ="white")
self.canvas.pack(expand=True, fill=BOTH)
window.bind("<KeyPress>",self.keyPressHandler)
window.bind("<KeyRelease>",self.keyReleaseHandler)
self.canvas.create_text(320,400,font="Times 15 italic bold",text="Key Event Example")
while True:
#
if(len(self.keys)>0):
print("Key: ", self.keys)
#
window.after(33)
window.update()
def keyReleaseHandler(self, event):
if event.keycode in self.keys:
self.keys.remove(event.keycode)
def keyPressHandler(self,event):
self.keys.add(event.keycode)
KeyboardEvent()