728x90
반응형
SMALL

정렬시 key  를 사용하여 원하는 기준으로 정렬할 수 있음

 

1) 절대값으로 정렬

a = [-2, -5, 3, 1, -10]

a.sort(key=abs)
print(a)
a = [-2, -5, 3, 1, -10]

b = sorted(a, key=abs)
print(b)

 - 실행결과

[1, -2, 3, -5, -10]

 

2) lambda 를 사용하여 정렬

a = [-2, -5, 3, 1, -10]

a.sort(key=lambda x: -(x*2))
print(a)
a = [-2, -5, 3, 1, -10]

b = sorted(a,key=lambda x: -(x*2))
print(b)

 

각 값들이 -(x*2) 가 적용되어 [4, 10, -6, -2, 20] 로 되고 다시 오름차순으로 정렬되어 아래와 같이 실행결과가 나타남

 

- 실행결과

[3, 1, -2, -5, -10]

 

3) 사용자 정의 객체 리스트를 속성에 따라 정렬하기

 

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

people = [Person("Alice", 25), Person("Bob", 30), Person("Charlie", 20)]
sorted_people = sorted(people, key=lambda x: x.age)
print([person.name for person in sorted_people])

 

key 매개변수에 lambda 함수를 사용하여 각 요소를 어떻게 비교할지를 정의

 

- 실행결과

['Charlie', 'Alice', 'Bob']

728x90
반응형
LIST
728x90
반응형
SMALL

파이썬에서 모든 이벤트 처리는 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()
728x90
반응형
LIST
728x90
반응형
SMALL
from tkinter import *

class BasicForm:
    def __init__(self):
        window = Tk()
        window.title("기본폼")
        window.geometry("640x480")
        
        self.canvas=Canvas(window, bg ="white")
        self.canvas.pack(expand=True, fill=BOTH)

        self.canvas.create_text(320,440,font="Times 15 italic bold",text="Basic Form")
        
        while True:
            #
            window.after(33)
            window.update()


BasicForm()

위 코드와 이후 공유되는 코드들은 파이썬에서 GUI 개발 모듈인 tkinter 를 이용한 게임 제작에 필요한 몇가지 기능들을 구현한 내용입니다.

코드에 대한 설명은 기초적인 파이썬 문법과 클래스에 대한 이해와 사용이 가능하다는 가정하에 작성을 하도록 하겠습니다.

-------------------------------------------------------------------------------------------------------

파이썬에서 tkinter 모듈을 이용하여 GUI 기반의 윈도우 프로그래밍을 할 수 있다. tkinter 에서 가장 기본 단위를 위젯이라고 하며 위젯의 종류에는 버튼(button), 라벨(label), 콤보박스(combobox), 캔버스(canvas) 등 이 있다. 게임을 위해서는 이미지를 이용한 애니메이션이 기본이되며 이와 같은 기능 구현은 캔버스에서 가능하다. 그러므로 작성된 코드에는 사운드를 제외한 대부분의 기능들을 캔버스만을 이용한다.

 

그림 1. 게임 코드 영역

게임을 만들때 일반적으로 코드는 3가지 영역(준비, 무한루프, 이벤트처리)으로 구분되어 작성된다.

  1. 준비영역에서는 윈도우를 생성, 사운드 및 이미지 파일등의 리소스 파일 로딩, 그리고 게임에 필요한 변수들을 초기화하는 코드가 작성된다(line5 ~12). 
  2. 무한루프 영역에서는 게임이 실행되는 동안 변화되는 데이터, 이미지의 위치, 사운드 on / off 등에 대한 코드를 작성한다.(line 15~17)
  3. 마지막으로 이벤츠처리 영역에는 키 또는 마우스 입력이 있을 때 처리해야 될 코드(이미지 위치값 이동, 사운드 on/off등)를 작성한다.(위 예제코드에는 이벤트처리 영역이 미 작성됨)

준비영역은 최초 게임 코드가 시작될 시 한번만 실행되며, 무한루프 영역은 계속 반복해서 실행된다.(일반적으로 while 을 이용한 무한루프형식으로 작성됨) 이벤트처리 영역은 키 또는 마우스 입력이 있을 시 실행되고 실행이 끝나면 다시 무한루프 영역의 코드가 실행되며, 이러한 방식을 Event-based Programming 방식이라고 한다. 무한루프 영역에서 키 또는 마우스 입력이 있을 시 바로 이벤트처리 영역으로 이동하는 것이 아닌 루프영역에서 마지막 코드인 window.update() 함수 호출시 이벤트처리 영역으로 이동하여 코드가 실행된다.

 

준비 영역과 무한루프 영역에 대한 코드 설명은 아래와 같다.

  • 윈도우 프로그래밍에서 가장 먼저 해야될 일은 윈도우 만들기다. Tk 클래스를 이용하여 윈도우 창을 생성할 수 있다.(line 5) 그리고 title, geometry 함수를 이용하여 윈도우 이름과 크기를 설정한다. (line 6~7)
  • 다음으로 캔버스 객체를 생성하는데, 생성시 캔버스가 붙여질 윈도우를 인수로 작성한다.(line 9) 윈도우 틀이 만들어지고 그 앞에 캔버스를 붙인 후 캔버스 위에 원하는 위치에 이미지를 그릴 수 있는 것이다.

그림 2. 윈도우, 캔버스, 이미지 레이어 구조

  • 윈도우도 하나의 위젯으로 생각할 수 있는데 위젯 간에 서로 붙이기 위해서는 붙일 대상 위젯 지정(line 9)과 실제 붙이는 동작이 있어야 되며 그 중에 하나가 pack() 이라는 함수이다.(line 10) 옵션은 윈도우에 꽉차게 그리기 위해 expand를 true 그리고 fill=BOTH로 설정하였다.
  • 캔버스는 도화지 처럼 무엇이든 그릴 수 있는 함수를 제공하고 있다. 그 함수들의 이름은 "create_"로 시작되며 create_rectangle, create_oval, create_line, create_text, create_image 등 그리는데 필요한 다양한 함수들을 이용할 수 있다. 위 코드에서는 create_text() 함수를 이용하여 "Basic Form" 글자를 320, 400 위치에 작성한다.

그림 3. canvas 클래스에서 사용되는 다양한 create 함수들

  • 캔버스에 무언가를 그리기 위해서는 기준좌표와 기준점이 어디 인지 알아야 된다. 아래 그림은 width: 640, hegiht: 480 크기로 그려진 윈도우의 좌표를 보여준다. 윈도우의 기준좌표는 왼쪽 위가 되며 0, 0 의 좌표값을 가진다. 그리고 그려지는 글자는 글자크기의 가운데 위치가 기준점이 된다. 그래서 글자는 코드에서 작성된 320, 400 의 위치에 글자의 기준점이 맞춰서 그려지게 된다.

그림 4. 기준좌표와 기준점

  • 무한루프 영역에서는 윈도우 클래스의 after()와 update() 함수가 호출된다(line 16, 17). after() 에는 33 이 작성되어 있으며 33은 대기 시간(단위: ms) 나타낸다. 위 코드에서는 게임영상을 초당 30 프레임로 동작하게 하기위해 33 을 작성하였다. 마지막으로 update() 함수 호출시 변화된 내용의 반영과 앞서 설명된 키 또는 마우스 이벤트들이 처리된다.
  • 무한루프 영역에서 이미지의 위치 변경 코드가 작성되어 있으면 그 코드가 호출된 시점에서 바로 이미지의 위치변경이 되는 것은 아니다. 이미지의 위치변경 코드가 많을 경우 코드마다 바로 위치변경하여 화면에 보여주게 되면 컴퓨터가 많은 부하가 발생할 수 있다. 그렇게 때문에 변화된 내용들을 모아서 특정 시간 마다 한번에 처리하면 부하를 줄일 수 있다. 모든 게임에서 그래픽 애니메이션은 이러한 방식으로 처리됨을 명심하기 바란다.

앞서 설명된 내용들은 다른 프로그래밍 언어(c++, java, visual basic등)로 게임을 제작할 때도 동일한 영역과 동작방식을 가지고 있어서 위 내용들을 이해하면 다른 프로그래밍 언어를 이용한 게임제작도 쉽게 할 수 있다. 모든 게임 개발 및 동작을 위한 코드 구조가 위와 동일하다고 생각하면된다(Unity, UnReal Engine 역시 기본구조는 동일함).

이상으로 게임 기본구조에 대한 설명 끝~~!

 

코드 실행결과

728x90
반응형
LIST

+ Recent posts