본문 바로가기

Python/Pygame

4강 Pygame으로 만든 'Hello World' 소스코드

Pygame 으로 만든 우리의 첫 번째 프로그램은 'Hello World!'를 보여주는 윈도우를 만든다.


IDLE을 실행해서 File >New File을 선택하면 편집기 화면이 뜬다.


아래의 코드를 편집기에서 입력한 다음 blankpygame.py 라는 이름으로 저장하자.


(참고로 코드 앞쪽에 보이는 라인번호는 타이핑하면 안 된다. 여기서는 설명을 하기위해 달아놓은 번호이지 코드의 일부분이 아니다.)


blankpygame.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import pygame, sys
from pygame.locals import *

pygame.init()
DISPLAYSURF = pygame.display.set_mode((400,300))
pygame.display.set_caption('Hello World!')
while True: # main game loop
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
    pygame.display.update()


다음으로 F5를 누르거나 아니면 편집기에서 Run > Run Module을 수행하면 파일을 실행할 수 있다.



프로그램을 실행하면 검정 바탕의 윈도우가 보인다.


자! 이제 첫 비디오 게임을 만들었다.


(비록 세게에서 가장 지루해 보이는 게임이긴 하지만.)


'Hello World!'가 윈도우 상단


타이틀 바 (캡션이라고도 한다)에 보이는 검정색 윈도우이긴 하지만,


윈도우를 만드는 것이 그래픽 게임을 만드는 첫 번째 단계다.


오른쪽 상단의 'X' 버튼을 누르면 프로그램이 종료되고 윈도우는 없어진다.




만약 print() 함수를 써서 윈도우에 글씨를 찍으려고 한다면  그건 여기서 작동하지 않을 것이다.


print()는 CLI에서 작동하는 함수이기 때문이다. 따라서 input()을 통해 키보드 입력 받을 수도 없다.


pygame의 입출력은 이후에 다루겠다.



지금은 우선 우리의 첫 번째 'Hello World' 프로그램을 살펴보도록 하자.


1
import pygame, sys


첫 번째 줄에서는 pygame과 sys 모듈을 가져와서 프로그램이 모듈 안의 함수를 사용할 수 있도록 한다.


그래픽 함수, 사운드 함수, 그 외 pygame이 처리하는 모든 기능은 pygame 모듈 안에 들어 있다.



pygame 모듈을 가져올 때 pygame의 pygame.images나 pygame.mixer.music 같은 모든 모듈을 자동으로 가져온다.


모듈안의 이름을 지정해서 또 가져오도록 할 필요 없다.


2
from pygame.locals import *


두 번째 줄에서도 역시 모듈을 가져오는 명령이다.


그런데 여기에서는 import modulename 형식이 아니라


from modulename import  * 형식을 사용했다.


일반적으로 모듈 내 함수를 호출할 때는 모듈을 임포트해서 가져온 다음


modulename.functionname() 형식으로 사용한다.


하지만 from modulename import * 으로 사용하면 modulename을 생략해도 된다.


Python의 내장 함수를 사용하는 것처럼 간단하게 functionname()으로 사용할 수 있다.



pygame.locals에 대해서 import 형식을 이렇게 다르게 사용하는 이유는


pygame.locals 안에 미리 정해 놓은 상수들을 워낙 많이 사용하기 때문이다.


이 경우 상수 이름 앞에 일일이 pygame.locals.를 붙이지 않고 사용하려면 이런 식으로


import를 하는 것이 좀 더 편리하기 때문이다.


다른 모듈 같은 경우는 그냥 import modulename 형식으로 쓰는 것이 일반적이다.

(이에 대한 좀더 자세한 정보는 http://www.tutorialspoint.com/python/python_modules.htm 에서 찾아볼 수 있다.)


4
pygame.init()


네 번째 줄에 나오는 pygame.init()는 pygame 모듈을 가져온 다음


Pygame 함수를 호출하기 전에 반드시 수행해야 하는 함수다.


이 함수가 어떤 일을 하는지 자세하게 알 필요는 없지만, 반드시 이 함수를 수행하고 나서야만


Pygame 함수를 수행할 수 있다.


만약 'pygame.error: font not initalized'와 같은 에러 메시지를 보게 된다면


프로그램을 시작할 때 pygame.init()를 호출했는지 확인해 보도록 하자.


5
DISPLAYSURF = pygame.display.set_mode((400,300))


다섯 번째 줄의 pygame.display.set_mode() 함수는 윈도우에 대한 pygame.surface 객체를 반환한다.


이때 (400, 300) 이라는 한쌍의 튜플이나 리스트 값을 함수에게 넘겨주는데 이것은 각각 윈도우의


너비와 높이를 set_mode() 함수에게 알려주는 역할을 한다.


따라서 결과적으로 너비 400픽셀, 높이 300픽셀짜리 윈도우를 만든다.


이때 set_mode() 함수에게 정수 1쌍을 넘겨준다는 데 주의하자.


그냥 정수 2개를 넘겨주는 게 아니다.


함수 호출은 pygame.display.set_mode((400, 300))이 올바른 방법이고


pygame.display.set_mode(400, 300) 라고 하면 안 된다.


이 경우 "TypeError: argument 1 must be 2-item sequence, not int"와 같은 에러가 발생한다.


pygame.display.set_mode에서 반환한 pygame.Surface 객체 (줄여서 Surface 객체라고 하자)는


DISPLAYSURF 변수에 저장한다.


6

pygame.display.set_caption('Hello World!')


여섯 번째 줄에서는 pygame.display.set_caption() 함수를 통해 윈도우의 캡션을 지정한다.


'Hello World!'를 함수에 넘겨서 이 글씨가 캡션에 보인다.





- 게임 루프와 게임 스테이트 -


7 8

while True: # main game loop
    for event in pygame.event.get():


일곱 번째 줄의 while 문은 True 조건문을 가지고 있다.


이것은 조건문이 False가 될 때까지는 절대 종료하지 않고 계속 순환문을 수행한다는 뜻이다.


이 무한 반복을 끝낼 방법은 break를 수행하거나 (이렇게 하면 루프문이 끝나고 바로 첫째 명령으로 이동한다.)


sys.exit() 뿐이다 (프로그램 자체를 종료한다.)


만약 이런 순환문이 함수 안에 있으면 return문이 나와도 순환을 종료할 수 있다.

(물론 순환문을 포함한 함수도 좋다.)


우리가 앞으로 보게될 게임프로그래밍 예제들은 거의 모두 while True 문을 가지고 있고


'main game loop' 라고 주석문을 붙여놓았다.


게임루프 (다른 말로는 메인루프)는 다음 3가지 일을 수행한다.






1. 이벤트 핸들링

2. 게임 상태 업데이트

3. 게임 스테이트를 화면상에 그린다



게임 스테이트는 게임 프로그램 안에서 사용하는 모든 변수의 값을 통칭한다.


대부분의 게임에서 게임 스테이트는 게임 플레이어의 상태 정보나 위치, 적의 상태, 위치 등을 포함하며


보통 이런 정보들은 점수로 환산되거나 혹은 누구의 차례인지 결정할 때 사용된다.


예를 들어 게임에서 플레이어가 피해를 입거나 총을 맞는 일이 발생하거나

(즉 health(HP) 값이 내려가는 상황이 되면)

아니면 적의 위치가 변경되거나 게임 안에서 특정 이벤트가 발생하면 이를 모두


게임 스테이트가 바뀌었다고 말한다.



여러분은 게임을 하다가 중간에 여태까지 한 내용을 저장할 수 있는 게임을 해본 적이 있을 것이다.


이때 저장하는 정보들이 게임 스테이트라고 할 수 있다.


게임 스테이트를 저장하면 저장한 상태에서 게임의 상태는 바뀌지 않는다.


게임 스테이트는 특정 이벤트가 발생하거나 (예를 들어 마우스를 클릭하거나 키보드를 누르면)


시간이 지나면 바뀐다. 따라서 게임 루프는 끊임없이 새로운 이벤트가 발생했는지 검사해야 한다.


루프 안에서 프로그램 코드는 새로 발생한 이벤트가 없는지 검사한다.

(Pygame에서는 pygame.event.get() 함수로 검사한다.)


또 메인 루프 안에서는 발생한 이벤트에 따라 게임 스테이트를 업데이트한다.


이를 이벤트 핸들링이라고 한다.




- Pygame.event.Event 객체 -


사용자가 프로그램 윈도우에서 마우스를 움직이거나 키보드를 누르는 몇 가지 행동

(좀더 자세한 내용은 뒷부분에서 다룬다)


을 할 때 Pygame 라이브러리는 이 이벤트를 기록하기 위해 pygame.event.Event 객체를 만든다.

(Event라는 객체 타입이며 pygame 모듈 안에 있는 event 모듈 안에 정의되어 있다.)


pygame.event.get()를 호출하면 어떤 이벤트가 발생했는지 알 수 있고,


pygame.event.get()은 pygame.event.Event 객체의 목록을 반환한다. (pygame.event.Event를 줄여서 Event 객체라고 하자)


Event 객체의 목록은 이전에 pygame.event.get()가 호출된 다음 발생한 이벤트들이다

(만약 pygame.event.get()을 한 번도 호출하지 않았으면, Event 목록은 프로그램이 시작한 다음 발생한 모든 이벤트들이 될 것이다.)


7 8

while True: # main game loop
    for event in pygame.event.get():


여덟 번째 줄은 for 문이며 pygame.event.get() 에서 넘긴 이벤트의 목록 하나하나에 대해 수행한다.


이벤트 목록의 값은 매번 event라는 변수로 할당된다.


pygame.event.get()에서 반환한 이벤트의 목록은 발생한 순서대로 저장되어 있다.


만약 사용자가 마우스를 클릭하고 키보드를 눌렀다면 Event 객체에는 마우스 클릭 관련


객체가 첫 번째로 오고, 그다음에는 키보드 관련 객체가 저장된다.


만약 아무 이벤트도 발생하지 않았으면 pygame.event.get()은 빈 목록을 반환한다.



- Quit 이벤트와 pygame.quit() 함수


1
2
3
        if event.type == QUIT:
            pygame.quit()
            sys.exit()


Event 객체는 type이라는 멤버 변수 (member variable, attribute, property라고도 한다.)가 있는데,


이것을 통해 Event 객체의 종류를 알 수 있다.


Pygame은 발생할 수 있는 이벤트의 타입들에 대해 미리 pygame.locals 모듈에 정의해 놓았다.


아홉 번째 줄에서는 Event의 객체 type이 QUIT인지 검사한다.


앞에서 말했듯이 모듈을 가져올 때 from pygame.locals import * 형식을 사용했기 때문에


pygame.locals.QUIT 이라고 하지 않고 그냥 QUIT이라고 해도 된다.



Event 객체가 quit  이벤트라면 pygame.quit()와 sys.exit() 함수를 호출한다.


pygame.quit()은 pygame.init()의 반대되는 함수다.


pygame.quit()은 은 Pygame 라이브러리를 종료하는 일을 한다.


sys.exit()으로 프로그램을 종료하기 전에 항상 먼저 pygame.quit()을 호출해야 한다.


일반적으로는 프로그램이 종료되면 Python이 알아서 pygame도 종료하지만


IDLE에 버그가 있는 경우가 있어서 pygame.quit()이 호출되지 않고 Pygame이 종료되면


IDLE에 행(hang)이 걸려 반응이 없을 수 있다.




- 픽셀 좌표


"Hello World" 프로그램으로 만든 윈도우는 스크린에서


작은 네모로 된 점으로 이루어져 있는데 이를 픽셀이라고 한다.


각 픽셀은 검정색이지만 색깔을 바꿀 수 있다.


400픽셀짜리 가로와 300픽셀짜리 세로로 된


Surface 객체 대신 가로, 세로 각각 8픽셀인 Surface 객체를 상상해 보자.


8 x 8 Surface를 확대해 보면 격자 모양의 사각형 처럼 보일 것이다.



특정 픽셀을 지정하려면 카르테시안 좌표 시스템에 따라 지정할 수 있다.


즉, X축과 Y축은 0부터 7까지 정수를 가지고 있고,


X축과 Y축의 숫자에 따라 픽셀을 찾아갈 수 있다.


예를 들어 위의 8 x 8 이미지를 보면


X, Y 좌표가 (4,0), (2,2), (0,5), (5,6)인 점이 검정색으로 보인다.


그리고 (2, 4)인 점은 회색으로 보이고, 그 외의 다른 점은 모두 흰색으로 보인다.


X, Y 좌표는 점이라고도 한다.


수학 수업을 들었고 카르테시안 좌표에 대해 알고 있으면 수학책에서 본 것과는


달리 위 그림에서 Y축이 0으로 시작해서 점점 숫자가 줄어드는 게 아니라


늘어나는 게 이상해 보일 것이다.


이것은 Pygame에서 카르테시안 좌표 시스템이 동작하는 방법이니


그냥 원래 이렇다고 기억해 두자


(사실 대부분의 프로그래밍 언어의 좌표 시스템은 이렇게 보인다.)


Pygame 프레임워크는 카르테시안 좌표 시스템을 (4, 0) 이나 (2, 2)처럼 2개의 숫자 쌍으로 표현한다.


첫 번째 정수는 X좌표이고, 두 번째 정수는 Y좌표이다.


카르테시안 좌표 시스템은 http://zpdl92.tistory.com/83 이곳에서 좀더 자세히 다루고 있다.



'Python > Pygame' 카테고리의 다른 글

3강 GUI 와 CLI 에 대한 이해  (0) 2014.11.03
2강 Python과 Pygame 설치하기  (0) 2014.11.03
1강 Python 과 Pygame에 대한 간략한 소개  (0) 2014.11.03