ai-creator

[파이썬 간단한 게임 만들기] 1. 기본기 쌓기 (종합) 본문

유치한 게임

[파이썬 간단한 게임 만들기] 1. 기본기 쌓기 (종합)

ai-creator 2021. 4. 3. 10:53
반응형

유치한 게임에 오신 것을 환영합니다.

게임을 만들기 위한 기본기입니다.

아래와 같은 순서로 배워보겠습니다.

 

1. 목표

2. 사전 준비

3. 소스 코드 (전체)

4. 사전 지식

5. 구현 순서

6. 정리

7. 확장하기

ㅁ 참고

 


1. 목표

이번 장에서는  파이썬으로 게임 만들기를 해볼게요.. 파이썬으로 게임을 만드는 대표적인 방법은 PyGame 라이브러리를 활용합니다.

 

PyGame을 활용하면 슈팅, 시뮬레이션, 아케이드 등의 다양한 장르의 게임을 비교적 간단히 만들 수 있습니다.

이번 시간에는

1) 게임을 구상하기 위한 기본기를 배우고 

2) 게임 화면에서 상,하 바향키를 눌러 비행기를  움직이는 간단한 게임

을 만들어 보도록 하겠습니다.

비행기 움직이기

 

 

2. 사전 준비

라이브러리와 소스 코드입니다.

 

1) 라이브러리 설치

유치한게임_1.기본기.zip
0.65MB

프로젝트 폴더 구성

- tutorial.py

- images

    - plane.png

 

 

3. 소스 코드 (전체)

이번장에서 공부하게 되는 게임 기본기의 전체 소스코드 입니다.

생각보다 짧죠? 

 

파일명 : tutorial.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import pygame # 1. pygame 선언
 
pygame.init() # 2. pygame 초기화
 
# 3. pygame에 사용되는 전역변수 선언
WHITE = (255,255,255)
size = [400,300]
screen = pygame.display.set_mode(size)
 
done= False
clock= pygame.time.Clock()
 
# pygame에 사용하도록 비행기 이미지를 호출
airplane = pygame.image.load('images/plane.png')
airplane = pygame.transform.scale(airplane, (6045))
 
# 4. pygame 무한루프
def runGame():
    global done, airplane
    x = 20
    y = 24
 
    while not done:
        clock.tick(10)
        screen.fill(WHITE)
 
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done=True
 
            # 방향키 입력에 대한 이벤트 처리
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_UP:
                    y -= 10
                elif event.key == pygame.K_DOWN:
                    y += 10
    
        screen.blit(airplane, (x, y))
        pygame.display.update()
 
runGame()
pygame.quit()
cs

 

4. 사전 지식

먼저 여러분들이 이제까지 했던 게임들이 있죠?

그 게임들을 머리속에 떠오르면서, 내가 그 게임을 만든다면 어떤게 필요할까? 를 생각해보세요.

저는 애니팡을 정말 좋아했었는데요, 

- 귀여운 캐릭터들이 나오고

- 손가락으로 동물들의 위치를 맞추면

- 3개 이상의 동물이 맞춰지면, 점수가 올라가는

게임이였습니다.

[그림 1] 예시 - 애니팡

그럼, 대충 어떤게 필요할까요?

- 이미지들이 배치되고

- 손가락의 움직임을 감지하고

- 동일 동물이 3개 이상되는지 계산해야겠죠?

그리고 게임은 위의 것들이 반복적으로 이루어집니다.

그럼 종료는요? 

- 내가 게임을 그만두고 싶을때

- 일정 점수가 되어 다음 단계로 넘어갈 때

로 나뉠수 있습니다.

이런 것들이 게임을 이루는 요소들이 되겠지요.

 

게임 코딩을 위해서 아래와 같은 사전 지식이 필요합니다.

1) PyGame 기본 구조

2) 게임 루프

3) 게임판 구성

4) 이벤트 처리

순서대로 배워보겠습니다.

1) PyGame 기본 구조

PyGame은 멀티미디어 소프트웨어를 위한 파이썬 라이브러리입니다. SDL(Simple DirectMedia Layer) 라이브러리를 기반으로 만들어져 있으며, 조이스틱의 입력, 그래픽 처리, 사운드 재생 등의 게임 구성에 필요한 기능을 가지고 있습니다. 말이 어렵죠? 그냥 파이썬으로 게임을 만들기 위해 필요한 것들을 사용하기 편하게 만들어 놓은 라이브러리라고 정리하죠.

 

게임을 만들기 위한 PyGame의 기본 구조는 다음과 같습니다.

[그림 2] pygame 기본 구조

첫째로 pygame라이브러리를 사용하므로, 사용하겠다!를 선언합니다.

두번째로 초기화를

세번째로 게임에 필요한 전역변수를 선언합니다.

마지막으로는 게임 루프를 코딩 합니다.

 

2) 게임 루프

게임을 진행하기 위해서는 '게임'과 '사용자'간의 지속적인 상호 작용을 합니다. 어떤 상호작용 일까요?

> '게임'은 지속적으로 상태를 화면에 표시하고

> '사용자'는 키보드, 마우스와 같은 입력장치로 입력

을 합니다.

 

이런 '지속적인' 상호작용을 위해서 프로그램에서는 어떤게 필요한가요? 그렇죠,  무한 루프입니다.

 

이 과정에서 게임의 상태 표시, 사용자의 입력은 게임의 시작부터 끝까지 지속적으로 반복하게 되며 이를 '게임 루프'라고 할 수 있습니다. 게임 루프에는 반복적으로 수행하는 3가지 구성요소가 있습니다.

[그림 3] 게임 루프

1. 사용자 입력처리 : 입력장치를 통해 사용자의 명령을 처리

2. 게임 상태 업데이트 : 게임에서 활용되는 상태(ex, 체력, 적과 캐릭터의 위치, 충돌 여부 등)를 지속적으로 갱신

3. 게임 상태 표시 : 위에서 지속되는 상태를 화면에 표시

 

 

3) 게임판 구성

이번에는 '게임판'이 필요합니다. 게임판은 게임을 하는 공간입니다. 쉽게 말하면, 바둑판, 체스판 같은거죠.

 

pygame을 통해서 게임판을 구성하기 위해서는 두가지가 필요합니다.

- 배경

- 크기 

입니다. 

 

게임판을 채울

- 배경은 '색(RGB)' 혹은 '이미지'를 통해서 구성할 수 있으며,

- 크기는 그 게임판이 가용될 면적을 의미하고 '넓이(width)'와 '높이(heigth)'로 지정합니다.

 

[그림 4] 체스에 사용되는 게임판(출처 - Pixabay)

 

4) 이벤트 처리

게임판에 대한 이해도 끝났으니, 이제 실제로 게임을 구현하는 일만 남았습니다. 게임을 구현하는데 있어 게임판 다음으로 중요한 것이벤트 처리입니다.

컴퓨터 세상에서 말하는 '이벤트'와 일상 생활에서 말하는 '이벤트'는 의미가 좀 다릅니다.

컴퓨터 세상에서 말하는 이벤트는 이런거에요.

컴퓨팅에서 이벤트(event)란 프로그램에 의해 감지되고 처리될 수 있는 동작이나 사건을 말한다. 대체로 이벤트는 프로그램 동작 과정과 함께 동시에 처리되도록 되어 있다. 즉 프로그램은 이벤트를 처리하기 위한 하나 이상의 전용 공간(또는 핸들러)를 가지게 되는데, 보통의 경우 이벤트 루프라고 불리는 곳에서 이를 처리하게 된다. 사용자가 키보드의 키를 누르는 것이 가장 대표적인 이벤트 발생 중의 하나이며, 타이머와 같은 하드웨어 장치가 이벤트를 발생 시키기도 한다. 또한 모든 프로그램은 작업이 완료되었다는 사실 등을 알리기 위해 자체적으로 정의한 이벤트를 발생시킬 수도 있다. 컴퓨터 프로그램 중에서 특히 이벤트에 반응하여 동작을 변경하는 방식을 이벤트 드리븐(event-driven) 방식이라고 하는데, 이는 보통 대화형 프로그램을 만드는데 그 목적이 있다. - 출처 : 위키백과 -

쉽게 말하면, 컴퓨터 입장에서  '처리해야 하는' 동작을 의미하는 거죠. 애니팡에서 손가락이 움직이는 방향에 맞춰, 동물을 움직이는 것을 생각하면 됩니다.

 

앞서 설명한 게임 루프에 사용자 입력 처리, 상태 업데이트, 상태 표시의 과정이 있었죠?

상태 업데이트에서는 사용자의 입력에 따라 상태가 변할 수 도 있으며, 사용자의 입력이 없다고 하더라도 시간 초과 등의 게임 룰에 의해 업데이트 될 수 있습니다.

 

따라서 사용자의 입력 처리부터 상태 업데이트, 상태 표시까지 이어주는 '흐름'을 만드는 것이벤트 처리이며, 모든 이벤트 처리는 특정 조건(=동작)에 의해 발생되도록 정의됩니다.

 

이 정도의 기본기면 충분합니다. 이제 게임을 만들어보겠습니다.

 

5. 구현 순서

이제 파이썬과 pygame을 사용해서 게임을 만들어볼게요.

앞서 설명드린 기본 구조를 바탕으로 작성을 할 것이며, 게임판을 설정하고 게임 흐름을 만드는 이벤트 처리까지도 생성하는 순으로 진행하겠습니다.

이를 통해 간단하게 비행기를 배치하여 이벤트 처리까지 생성하도록 하겠습니다.

 

Step1 기본 구조 작성 및 게임판 설정
Step2 이벤트 생성 1 - 이벤트 처리
Step3 이벤트 생성 2 - 비행기 움직이기

 

Step1) 기본 구조 작성

[그림 2]의 게임 기본 구조에 해당하는 소스를 먼저 작성해보도록 하겠습니다. 

pygame 기본 구조

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import pygame # 1. pygame 선언
 
pygame.init() # 2. pygame 초기화
 
# 3. pygame에 사용되는 전역변수 선언
WHITE = (255,255,255)
size = [400,300]
screen = pygame.display.set_mode(size)
 
done= False
clock= pygame.time.Clock()
 
# 4. pygame 무한루프
def runGame():
    global done
    while not done:
        clock.tick(10)
        screen.fill(WHITE)
        pygame.display.update()
 
runGame()
pygame.quit()
cs

 

1~3번 라인은 앞서 작성된 1,2번 순서대로 pygame 선언과 pygame 초기화에 해당하는 코드가 작성되어 있습니다.

6~9번 라인은 게임판 설정입니다. 게임판 구성요소는 2가지라고 말씀드렸죠. 바로 '배경'과 '크기'입니다.

이번 게임에서는 '배경'은 흰색으로, '크기'는 넓이(width) 400, 높이(height) 300로 설정해보겠습니다. 흰색을 표현할때는 RGB 값을 이용합니다. 즉, 색을 표현하는 방법은 여러가지가 있는데요, 그 중  RGB 색상표로 색을 표현하는 것입니다.

R = Red

G = Green

B = Blue

이렇게 3가지를 적절한 비율로 섞어 색을 표현합니다.

www.n2n.pe.kr/lev-1/color.htm

 

256 color 색상표

333333 R - 051 G - 051 B - 051

www.n2n.pe.kr

흰색은 R = 255, G=255,  B=255 네요.

6라인 WHITE = (255,255,255) 이렇게 튜플형태로 만들어주고,

18라인 에서 screen.fill(WHITE) 색을 채워줍니다. 만약, 파란색으로 하고 싶다면? (0, 0, 255)로 설정하면 되겠죠.

 

그럼  screen이라는 객체는 어떻게 만들어진걸까요? 7라인에  넓이(width) 400, 높이(height) 300으로 설정하고, 8라인을 통해 screen객체가 생성되었습니다. 이렇게 게임판을 구성하였습니다.

 

10,11번 라인은 게임의 종료를 확인할 done 변수와 FPS(Frame Per Second, 초당 화면 출력) 을 설정하는 변수입니다. FPS라는 개념이 생소하시죠? 화면(frame)을 얼마나 자주 그려줄 것이냐의 의미로 생각하면 됩니다. 

FSP 설명 (출처 : https://securitycamcenter.com/frame-rate-cctv/)

1초에 화면을 12번 그려준다고 하면 12fps 라고 하고, 3번을 그려준다고 하면 3fps라고 하는거죠. 컴퓨터 입장에서는 드문드문 그려줘야 좋겠죠. 그러나, 사용자 입장에서는 자주 그려줘야 부드럽고, 생동감 있게 느껴집니다.

FSP 설명 (출처 : https://theappliancesreviews.com/why-frame-rate-is-25-30-or-29-97-fps/)

 11라인에서는 객체를 선언한 것뿐이고, 17라인에서 설정을 해줍니다. clock.tick(10)로 설정함으로써 1초에 10번 화면을 출력해준다는 의미입니다. 즉, 10fps로 설정되었습니다. 적절하게 쉬는 시간을 주어 컴퓨터 입장에서는 과부하되는 것을 막아줍니다. 

14~17번 라인은 게임이 실행되는 함수 입니다. 15번 라인부터 while문을 통해 무한 루프가 지속되며 게임 루프를 실행하게 됩니다. 

 

15번 라인은 게임 종료를 검증하기 위한 done  변수를 전지역(global scope)에서 사용 할 수 있도록 global이라는 키워드를 사용합니다.

 

16번 라인은 실제 사용될 FPS를 설정해주는 라인입니다. 값을 10으로 지정한 것은 초당 10번의 화면을 출력 해준다는 의미입니다. 해당 값이 높아질 수록 CPU에 사용량이 높아지며 프레임에 따라 모니터가 제대로 출력하지 못하는 경우가 많아 기본적으로 10, 30, 60을 많이 사용합니다. 
17번 라인에서는 8번라인에서 지정한 screen 변수에 WHITE 값을 넣어 화면을 흰색으로 칠합니다.
19번 라인은 게임을 실행하도록 runGame()함수를 호출하는 라인입니다.
 
지금까지 구현한 코드는 절대 종료되지 않는 프로그램입니다. 이제 프로그램을 '끝'낼 수 있도록 구현해보겠습니다.

 

 

Step2) 이벤트 생성 1 -  종료 처리

게임 기본 구조를 작성하였으니 이제는 이벤트 처리를 구현해볼께요.

step1)에 구현된 내용은 절대 종료되지 않는 프로그램라고 말씀드렸죠? 그럼, 해당 코드에서 어떻게 되어야 프로그램이 종료되나요? while문을 보면 어떤 조건일 때, 빠져나오죠? 맞습니다. done 변수가 True가 되면 프로그램이 종료됩니다.

그럼 OO동작이 일어나면, done=True로 해서 빠져나오도록 구현해 보겠습니다.

OO동작은 프로그램 상단에 있는 X를 누를 때로 해보겠습니다.

즉, '종료 이벤트가 발생하면 프로그램을 종료한다' 는 구현부 입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import pygame # 1. pygame 선언
 
pygame.init() # 2. pygame 초기화
 
# 3. pygame에 사용되는 전역변수 선언
WHITE = (255,255,255)
size = [400,300]
screen = pygame.display.set_mode(size)
 
done= False
clock= pygame.time.Clock()
 
# 4. pygame 무한루프
def runGame():
    global done
    while not done:
        clock.tick(10)
        screen.fill(WHITE)
 
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done=True
        pygame.display.update()
runGame()
pygame.quit()
cs

 

pygame에서는 pygame.event.get()이라는 함수를 활용하여 해당 게임 안에서 발생한 이벤트를 가져오는 기능이 있습니다. 함수를 실행시 발생한 이벤트는 list형태로 return 됩니다. list형태는 여러개를 의미하므로, for문으로 각각의 이벤트를 검사합니다.

20~22번 라인은 [X]를 눌러 게임을 종료하면, pygame.QUIT라는 이벤트가 발생합니다.  해당 이벤트가 있다면, done 변수를 True로 변경하여 게임 루프를 종료합니다.

 

이와같이 게임해서 발생하는 pygame.event.get() 함수와 발생한 이벤트들을 검사할 수 있도록 실행하는 for문 마지막으로 각각의 이벤트를 검사하는 if문을 통하여 게임의 이벤트 처리를 수행합니다.

 

여기까지 구현이 되었다면, 한번 실행해보세요. [X]를 눌러 종료도 해보세요.

 

Step3) 이벤트 생성2 - 비행기 움직이기

이벤트 처리에 대한 기본기를 배웠으니

- 비행기를 배치하고

- 비행기를 움직일 수 있도록 하는 이벤트를 생성

해보도록 하겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import pygame # 1. pygame 선언
 
pygame.init() # 2. pygame 초기화
 
# 3. pygame에 사용되는 전역변수 선언
WHITE = (255,255,255)
size = [400,300]
screen = pygame.display.set_mode(size)
 
done= False
clock= pygame.time.Clock()
 
# pygame에 사용하도록 비행기 이미지를 호출
airplane = pygame.image.load('images/plane.png')
airplane = pygame.transform.scale(airplane, (6045))
 
# 4. pygame 무한루프
def runGame():
    global done, airplane
    x = 20
    y = 24
 
    while not done:
        clock.tick(10)
        screen.fill(WHITE)
 
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done=True
 
            # 방향키 입력에 대한 이벤트 처리
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_UP:
                    y -= 10
                elif event.key == pygame.K_DOWN:
                    y += 10
    
        screen.blit(airplane, (x, y))
        pygame.display.update()
 
runGame()
pygame.quit()
cs

 

 

먼저 비행기를 배치해보겠습니다.

이미지를 읽고, 적절한 위치에 배치시키면 됩니다. 

 

14,15번 라인에서 pygame.image.load()라는 함수를 통해 이미지 파일을 읽습니다.  파일을 읽을 때는 '경로(path)'를 주의하세요. 어디에 이미지 파일이 있는지 확인하셔야 합니다. 만약, 절대경로/상대경로에 대한 지식이 없다면, 링크(상대경로, 절대경로)에 있는 글을 읽어보세요.

이미지를 읽었다면, 크기를 조절해주면 됩니다.   pygame.transform.scale() 함수로이미지 크기를 조절할 수 있습니다.  게임판의 사이즈에 맞춰 넓이 60, 높이 45의 크기로 변환합니다.

 

[그림 5] 비행기(출처 - PNGFLOW)

 

다음으로 비행기를 배치(=시작위치)하기 위한 좌표 설정을 해보겠습니다.

20, 21번 라인에서 x, y라는 변수를 선언하여 비행기가 배치될 위치를 지정할 수 있도록 합니다.

x=0, y=0 으로 그렸을 때와 비교해보세요.  (0,0)의 좌표는 어떤가요? 왼쪽 제일 상단이죠? 좌표의 구성은 다음과 같습니다.

 

(0,0)을 기준으로 오른쪽으로 가려면 + (더하기)연산을 하고, 왼쪽으로 가려면 - (빼기) 연산을 하면 됩니다.

 

비행기 배치에 대한 설정을 끝냈으니 이번엔 키보드 방향키(상,하)로 비행기를 위, 아래로 움직일 수 있도록 이벤트 처리를 해보겠습니다.

 

먼저 pygame에서 키보드 방향키 입력에 대한 이벤트 감지에 대해서 말씀드리겠습니다.

이벤트 명 발생 이벤트
event.type  pygame.KEYDOWN 키보드 버튼을 눌렀을 때 발생
event.type  pygame.KEYUP 키보드 버튼을 눌렀다 땠을 때 발생
event.key pygame.K_UP (KEYDOWN과 중복) 위쪽 방향키를 눌렀을 때 발생
event.key pygame.K_DOWN (KEYDOWN과 중복) 아래쪽 방향키를 눌렀을 때 발생
event.key pygame.K_LEFT (KEYDOWN과 중복) 왼쪽 방향키를 눌렀을 때 발생
event.key pygame.K_RIGHT (KEYDOWN과 중복) 오른쪽 방향키를 눌렀을 때 발생

위와 같이 각 키보드 이벤트 처리에 대한 정의가 pygame에서 지정 되어있습니다.

키 버튼이 눌렸다 / 어떤 키 버튼이 눌렸냐? 로 분리할 있습니다. 즉, 키보드 상,하 방향키를 눌렀을 때  KEYDOWN(키 버튼이 눌림)과 K_UP(어떤키? 업 방향키), K_DOWN(어떤키? 다운 방향키) 로 이벤트 처리를 해보겠스빈다.

 

32~36번 라인에서 부터 KEYDOWN을 검사하여 키보드를 눌렀을 때 발생하는 이벤트를 감지하여 위쪽 방향키를 눌렀을 때(K_UP 이벤트 발생) y 좌표값을 감소시켜 비행기의 위치를 상단으로 이동시키며, 아래쪽 방향키를 눌렀을 때(K_DOWN 이벤트 발생) y 좌표값을 증가시켜 비행기의 위치를 하단으로 이동시키도록 하였습니다.

 

이제는 x, y값 좌표를 설정한 비행기를 화면에 표시하는 일이 남았습니다.

38,39번 라인에서 screen.blit()라는 함수를 통해서 위에서 선언한 airplane을 x, y좌표에 배치하도록 지정하였고, pygame.display.update() 함수를 통해서 배치된 비행기가 게임판에 표시되도록 스크린을 업데이트 하였습니다.

 

작성을 완료한 뒤 실행을 해보면 다음과 같이 화면에서 상하 방향키를 눌러 비행기를 움직일 수 있게 되었습니다.

[그림 6] 비행기를 배치 완료한 모습

 

 

6. 정리

이번 장에서는 게임에 필요한 필수요소(pygame 구조, 게임 루프, 이벤트 처리)를 배웠습니다. 기본 구조에서 게임 루프를 구성하고 이벤트 처리를 통해서 게임의 요소를 작동시키는 구조로 게임을 구현하도록 하였습니다.

 

Step1) 기본 구조를 작성한다. -> pygame 선언, pygame 초기화, 전역변수 선언, pygame 메인루프(게임 루프)로 구성

Step2) 이벤트 처리를 생성한다. -> pygame.event.get()을 통해 발생된 이벤트를 가져와 검사

Step3) 비행기를 움직이는 이벤트를 생성한다. -> pygame에서 정의된 키보드 입력에 대한 이벤트를 통해 게임 상태 업데이트

 

다른 게임도 모두 동일한 구조와 다양한 이벤트 처리를 구성하여 구현 할 수 있으며, 색다른 요소를 가미하여 나만의 게임도 만들 수 있습니다. 

 

7. 확장하기

1) 이미지와 좌표 처리

키보드 키를 계속 누르면, 이미지가 안보이게 됩니다.게임판 밖으로 이미지가 나가지 않도록 구현해보세요.

상하로 움직이는 비행기를 좌우로도 움직일 수 있게 구현해 보세요.

 

ㅁ 참고

뇌를 자극하는 파이썬 3 블로그(yoonkh.github.io/python/2017/12/10/brain7.html)

이수안 컴퓨터 연구소 유튜브(www.youtube.com/watch?v=-e_5sOsKqrU)

유치한 파이썬 - 함수편

 

[그림 4]비행기 슈팅 게임 출처


도움이 되셨다면, 좋아요 / 구독 버튼 눌러주세요~

 

저작물의 저작권은 작성자에게 있습니다.
공유는 자유롭게 하시되 댓글 남겨주세요~
상업적 용도로는 무단 사용을 금지합니다.
끝까지 읽어주셔서 감사합니다^^

반응형
Comments