유치한 게임

[파이썬 간단한 게임 만들기] 4. 폭탄 피하기

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

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

이번에는 폭탄 피하기 게임을 만들어 보겠습니다.

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

 

1. 목표

2. 사전 준비

3. 소스 코드 (전체)

4. 사전 지식

5. 구현 순서

6. 정리

 

 


1. 목표

이번에 만들 게임은 폭탄 피하기 게임입니다. 폭탄 피하기 게임의 규칙은 다음과 같습니다.

폭탄은 랜덤한 위치에서 Y축을 기준으로 위에서 아래로 떨어지며 하단에 게임 캐릭터가 위치하여 폭탄을 피해 생존해야 합니다.

폭탄은 최대 5개까지 내려올 수 있으며, 내려오는 속도가 모두 다릅니다.

하늘에서 여러개의 폭탄이 마구 떨어지고, 그 폭탄을 피하는 재미난 게임을 만들어 보시죠.

 

[그림 4-1] 폭탄피하기 게임

 

 

이번 장에서는 이 폭탄 피하기 게임을 구현하고, 개체간의 접촉을 통한 이벤트 처리에 대해 배워보도록 하겠습니다.

 

 

2. 사전 준비

1) 파이썬 문법 이해

// 연산을 이해합니다.

2) colliderect() 이해

- Rect()로 생성된 객체에서 사용할 수 있는 함수이며, 해당 사각형과 인자로 들어온 사각형을 비교하여 overlap이 되면 true를 반환해주는 함수 

참고) colliderect() 사용해보기

더보기
- 객체 생성 : 사각형 2개 만들기
    - 1) 파란색 사각형 (사이즈 : 30x30, 시작위치 : (0,0)) 
    - 2) 빨간색 사각형 (사이즈 : 30x30, 시작위치 : (100, 100))
- 이벤트 컨트롤 
    - 파란색 사각형은 위치 고정
    - 빨간색 사각형은 키보드이벤트를 통해 위치 이동
- 상태 표시
    - colliderect()로 두 객체 충돌 여부 확인
    - 두 객체가 overlap시 '충돌!!!' 이라는 메시지를 게임판에 출력
import pygame # 1. pygame 선언
import random

pygame.init() # 2. pygame 초기화

# 3. pygame에 사용되는 전역변수 선언

WHITE = (255, 255, 255)
size = [400, 400]
screen = pygame.display.set_mode(size)

done = False
clock = pygame.time.Clock()
sysfont = pygame.font.SysFont('malgungothic', 36)

# 4. pygame 무한루프
def runGame():
    global done
    dx =0 ; dy=0
    rect2=pygame.rect.Rect(100,100,30,30)
    
    while not done:
        clock.tick(10)
        screen.fill(WHITE)
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done=True
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    dx = -10
                elif event.key == pygame.K_RIGHT:
                    dx = 10
                elif event.key == pygame.K_UP:
                    dy -= 10
                elif event.key == pygame.K_DOWN:
                    dy += 10
            elif event.type == pygame.KEYUP:
                dx =0 ; dy=0
        
        rect1=pygame.draw.rect(screen, (0, 0, 255), (0, 0, 30, 30))
        
        rect2.top += dy
        rect2.left += dx
        rect2=pygame.draw.rect(screen, (255, 0, 0), rect2)
        if rect1.colliderect(rect2) == True:
            print("충돌!!!!")
            text = sysfont.render("충돌!!!", True, (0, 255, 0)) # BLUE = (0, 0, 255) 
            screen.blit(text, (200,200))
            
        
        pygame.display.update()

runGame()
pygame.quit()​

3) random.randint() 이해

- 랜덤 추출 함수입니다. 즉, random.randint(0, 10) 이라고 하면 0~10사이 숫자를 무작위로 출력해줍니다.

 

4) 게임은 어떤 고려사항이 있을까?

4-1) 폭탄 : 총 5개의 폭탄이 만들어집니다. 랜덤으로 생성되고, y축 방향으로 내려오는 속도도 모두 다릅니다.

       ** 처음에는 1개의 폭탄만 제어합니다. 그 후 폭탄 수를 늘려 관리하는 방법을 생각해봅니다.

4-2) 캐릭터 움직임 : 키보드 좌우 방향키를 통해 제어
4-3) 게임 종료 조건 : 캐릭터가 폭탄 그림이 겹쳤을 때 또는 [x] 키가 눌려졌을때

참고) 설계를 해보자!

 

5) 게임판 구상

import pygame # 1. pygame 선언
import random

pygame.init() # 2. pygame 초기화

# 3. pygame에 사용되는 전역변수 선언

BLACK = (0, 0, 0)
size = [600, 800]
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(BLACK)
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done=True
        
        pygame.display.update()

runGame()
pygame.quit()

 

게임을 진행할 화면을 다음과 같이 설정하도록 하겠습니다.

8번 라인(화면 색) :  black(RGB - 0,0,0)

9번 라인(화면 크기) : 넓이(width) - 600, 높이(height) - 800/ 600x800

 

 

3. 소스 코드 (전체)

프로젝트 폴더 구성

- bomb_game.py

- bomb.png

- person.png

4. 사전 지식

1) 폭탄 피하기 게임에 필요한 요소 정의

폭탄 피하기 게임은 게임판 안에서 떨어지는 폭탄을 피하는 게임 입니다. 따라서 지속적으로 폭탄이 랜덤한 위치에 떨어져야 하며, 떨어지는 폭탄을 피할 캐릭터까지 두가지 요소가 필요합니다.

 

폭탄은 이전 장에서 배운 사각형을 그리는 Rect() 함수에 폭탄 이미지를 넣어 마치 사각형의 도형이 아닌 폭탄이 떨어지는 것처럼 표현합니다.  또한 이 폭탄들은 여러개이므로 리스트(bombs)에 담아 관리합니다.

 

1
2
3
4
5
6
7
8
9
10
11
def runGame():
    bomb_image = pygame.image.load('bomb.png')
    bomb_image = pygame.transform.scale(bomb_image, (5050))
    bombs = []
 
    for i in range(5):
        rect = pygame.Rect(bomb_image.get_rect())
        rect.left = random.randint(0, size[0])
        rect.top = -100
        dy = random.randint(39) ## 떨어지는 속도
        bombs.append({'rect': rect, 'dy': dy})
cs

먼저 폭탄부터 살펴보도록 하겠습니다.

2번 라인은 pygame.image.load() 함수를 이용하여 폭탄 이미지 파일을 불러오는 코드입니다.

3번 라인은 앞서 불러온 이미지를 게임판 내부에 알맞은 규격으로 재설정 해줍니다. scale() 함수를 통해서 bomb_image의 크기를 50X50으로 조절해보겠습니다.

4번 라인은 이후 Rect()로 생성할 폭탄들을 담을 리스트를 선언해주는 코드입니다.

6번 라인부터는 총 5개의 폭탄을 생성하기 위해 for문을 통해 반복문을 실행해줍니다.

7번 라인은 Rect() 함수를 통해서 폭탄 이미지의 사각형 크기를 가져와 네모난 사격형 안에 폭탄 이미지를 넣어주는 코드입니다.

8,9번 라인은 앞서 가져온 사각형의 좌표를 설정해주는데 먼저, left라는 변수를 random 값을 넣어 스크린의 width(size[0]) 안에 속하는 랜덤 x 좌표를 설정해주고, top이라는 변수에는 폭탄의 시작점을 설정해줍니다.

10번 라인에서는 폭탄의 속도를 정해주는 dy 변수를 선언해주는데 각 폭탄이 떨어지는 속도를 다르게 하기위해 random.randint() 함수를 통해 랜덤값을 넣어줍니다.

11번 라인은 앞서 생성한 객체와 변수를 bombs 리스트 안에 삽입하는 코드입니다.

 

 

[그림 4-2] 폭탄 이미지

 

다음으로는 캐릭터입니다.

캐릭터는 키보드 방향키를 이용하여 좌우로 이동하여 폭탄을 피하게 됩니다. 따라서 캐릭터(person)가 존재하는 x와 y좌표, 다음으로 좌우 이동속도와 상하 이동속도를 담을 dx, dy 변수를 설정해줍니다. 캐릭터는 좌우로만 이동하므로,  오른쪽/왼쪽 방향키가 눌린다면 값이 증가/감소 되고,  위/아래 방향키가 눌릴때는 값의 변화가 없으면 되겠죠.

 

1
2
3
4
5
6
7
person_image = pygame.image.load('person.png')
person_image = pygame.transform.scale(person_image, (100100))
person = pygame.Rect(person_image.get_rect())
person.left = size[0// 2 - person.width // 2
person.top = size[1- person.height
person_dx = 0
person_dy = 0
cs

1~3번 라인은 앞서 설정한 폭탄과 동일하게 Rect() 안에 person_image를 담아 생성해주는 코드입니다.

4번 라인은 person의 x 좌표 위치를 담는 변수입니다. 초기에는 정중앙에 설정을 해야 함으로, 게임판의 width(size[0])을 기반으로 중앙에 설정해줍니다.

5번 라인은 게임판의 heigth(size[1])을 기반으로 최하단에 위치 시키는 코드입니다.
6,7번 라인은 폭탄과 다르게 캐릭터는 사용자의 입력 기반으로 이벤트 처리가 일어나기에 이동속도는 0으로 초기화 해주는 코드입니다.

 

[그림 4-3] 게임 캐릭터

 

 

2) PyGame 접촉 처리

폭탄 피하기 게임에서 게임이 종료되는 경우는

- 캐릭터와 폭탄이 접촉했을 때

- 사용자가 종료[X] 키를 눌렀을때

입니다.

 

"캐릭터와 폭탄이 접촉했을 때"를 알아볼게요.

이론적으로 접촉을 감지하는 방법은 다음과 같습니다. 폭탄의 사각형 도형의 실시간 좌표와 게임 캐릭터의 사각형 도형의 실시간 좌표를 비교하여 해당 영역이 겹치게 되면 이벤트 처리를 발생시키는 방법입니다.

 

하지만, game 구현을 하기 위한 전용 라이브러리인 만큼, pygame에서는 이런 접촉을 편리하게 감지할 수 있는 함수를 제공합니다.

바로, colliderect() 함수입니다. colliderect() 함수는 Rect()로 생성된 객체에서 사용할 수 있는 함수이며, 해당 사각형과 인자로 들어온 사각형을 비교하여 overlap이 되면 true를 반환해주는 함수 입니다. 따라서 폭탄 피하기 게임에서 이 colliderect() 함수를 활용하여 폭탄과 캐릭터의 접촉 처리를 해보도록 하겠습니다.

 

1
2
3
4
for bomb in bombs:
    if bomb['rect'].colliderect(person):
        done = True
    screen.blit(bomb_image, bomb['rect'])
cs

 

1번 라인에서 앞서 선언한 bombs리스트 안의 요소들을 돌면서 반복문을 실행하도록 합니다.

2,3번 라인에서 bomb객체 안의 사각형을 이용하여 colliderect() 함수에 캐릭터 사각형 도형(person)을 인자로 넣어 접촉을 판단합니다. 접촉이 되면(True 가 리턴) done을 True로 변경하여 게임을 종료하도록 합니다.

 

 

5. 구현 순서

구현 순서는 다음과 같습니다.

Step1 키보드 이벤트 처리를 통한 캐릭터(person) 제어
Step2 개체 출력하기
Step3 접촉 판단과 게임 종료

 

Step1) 키보드 이벤트 처리를 통한 캐릭터(person) 제어

 

먼저 키보드 좌우 버튼을 통해서 캐릭터를 제어 해보도록 하겠습니다. 이전 장에서 학습한 방향키 이벤트 처리와 다르게 이번 게임에서는 키보드를 계속 누르고 있는 경우에 캐릭터 또한 계속 이동할 수 있도록 설정해보도록 하겠습니다.

for event in pygame.event.get():
    if event.type == pygame.QUIT:
    	done = True
        break
    elif event.type == pygame.KEYDOWN:
        if event.key == pygame.K_LEFT:
            person_dx = -5
        elif event.key == pygame.K_RIGHT:
            person_dx = 5
    elif event.type == pygame.KEYUP:
        if event.key == pygame.K_LEFT:
            person_dx = 0
        elif event.key == pygame.K_RIGHT:
            person_dx = 0

 

먼저 KEYDOWN 이벤트를 통해 버튼이 눌러진 이벤트를 캐치하고, K_LEFT와 K_RIGHT 이벤트를 통해서 좌우 방형키의 다운키 이벤트를 검증해줍니다.

7번 라인은 키보드의 왼쪽 방향키 이벤트가 발생했을 때, person_dx의 값을 -5로 설정하여 person의 left를 5의 값으로 빼주도록 합니다.

9번 라인은 반대로 오른쪽 방향키 이벤트가 발생했을 때, person_dx의 값을 5로 설정하여 person의 left를 5의 값으로 더하도록 하니다.

위의 라인대로 키보드가 눌려지고 있을 때는 지속적으로 이동하도록 하며 이번에는 키보드가 눌렀다 띄어졌을 때는 이동하지 않도록 설정하겠습니다.

10,11번 라인에서는 키보드의 왼쪽 방향키와 오른쪽 방향키가 띄어지는 이벤트가 각각 발생했을 때는, person_dx값을 0으로 설정하여 person의 left값이 변하지 않도록 합니다.

 

 

Step2) 개체 출력하기

 

이번에는 앞서 작성한 코드를 기반으로 제어된 캐릭터를 출력하며 자동 생성되는 폭탄을 게임판 화면에 출력되도록 하겠습니다.

먼저 앞의 bombs 리스트를 통해 폭탄을 출력하기 위한 준비를 하겠습니다.

 

1
2
3
4
5
6
7
8
9
for bomb in bombs:
    bomb['rect'].top += bomb['dy']
    if bomb['rect'].top > size[1]:
        bombs.remove(bomb)
        rect = pygame.Rect(bomb_image.get_rect())
        rect.left = random.randint(0, size[0])
        rect.top = -100
        dy = random.randint(39)
        bombs.append({'rect': rect, 'dy': dy})
cs

 

1번 라인에서 먼저 for in 문을 통해 bombs 리스트의 bomb 요소들을 반목분을 돌며 처리해주도록 합니다.

2번 라인은 bomb 객체 안의 'rect'라는 사격형 도형의 위치에 랜덤으로 생성한 dy값을 추가하여 -100 부터 시작된 위치에서 점점 내려오도록 설정합니다.

3번 라인부터는 폭탄의 위치가 heigth 바닥을 넘어갔을때, 새롭게 생성하도록 하는 코드입니다.

4번 라인에서 해당 폭탄 객체를 제거해줍니다.

5~9번 라인은 앞서 폭탄을 초기화 하던 방식과 동일하게 새로운 폭탄을 생성해주고 리스트에 추가해주도록 해주는 코드입니다.

 

다음으로 앞서 키보드 처리 이벤트를 작성한 것을 기반으로 캐릭터를 출력해보도록 하겠습니다.

 

1
2
3
4
5
6
7
8
person.left = person.left + person_dx
 
if person.left < 0:
    person.left = 0
elif person.left > size[0- person.width:
    person.left = size[0- person.width
 
screen.blit(person_image, person)
cs

먼저 person의 left 값에 키보드 처리로 설정한 person_dx 값을 더해 위치를 조정해줍니다.

3~6번 라인은 캐릭터가 만약 좌측 끝점(0값) 혹은 우측 끝 지점(size[0] 값: 600) 에 도달하게 되면 더 이상 이동하지 않도록 설정하는 코드입니다. 만약 캐릭터의 끝값을 조정해주지 않는다면 무한정 옆으로 이동하게 되어 초기에 설정한 게임판 안에 더이상 캐릭터가 보이지 않게 되기 때문에 필수적으로 처리해야 하는 부분입니다. 

8번 라인은 이전에도 사용한 blit()함수를 통해 person 이미지를 기반으로 person 사각형을 그려주도록 합니다.

 

[그림 4-4] 캐릭터 끝 지점 이동 처리

 

 

 

Step3) 접촉 판단과 게임 종료

마지막으로 앞서 배웠던 폭탄과 캐릭터의 접촉 판단과 해당 이벤트가 발생했을 때의 게임종료를 작성해도록 하겠습니다.

 

폭탄 접촉 판단을 폭탄 출력에 앞서 작성하는 이유는 해당 폭탄이 캐릭터와 접촉하게 된 후에 이동을 한번 더 한 후에 게임이 종료되는 것이 아니라, 접촉하게 되는 순간에 게임 종료 처리를 하기 위함입니다.

 

1
2
3
4
5
6
for bomb in bombs:
    if bomb['rect'].colliderect(person):
        done = True
    screen.blit(bomb_image, bomb['rect'])
 
pygame.display.update()
cs

1~3번 라인은 앞서 배운 접촉처리 코드와 동일합니다.

4번 라인은 리스트를 반목문을 통해 돌며 폭탄을 화면에 출력하도록 합니다.

6번 라인은 마지막으로 게임판의 디스플레이를 업데이트 하여 앞서 설정한 요소들이 화면에 업데이트 되도록 합니다,

 

6. 정리

이번 장에서는 앞서 배운 pygame의 기본 구조와 게임 루프, 이벤트 처리를 기반으로 키보드 처리와 버튼을 지속하여 이동하기 및 접촉 처리까지 학습하여 폭탄 피하기 게임을 구현 해봤습니다.

 

먼저, 게임에 필요한 요소 정의를 하고 접촉 처리를 통해 게임 흐름을 진행할 수 있도록 사전학습을 한 뒤 진행을 했으며,

Step 1) 키보드 이벤트 처리를 통한 캐릭터(person) 제어 -> 키보드 up, down을 통한 이동 제어

Step 2) 개체 출력하기 -> 이동속도 dx, dy를 설정하여 캐릭터 및 폭탄 이동값을 통한 출력

Step 3) 접촉 판단과 게임 종료 -> colliderect() 함수를 통한 개체가 충돌했을 때의 이벤트 처리

를 배웠습니다.

 

이번 장에는 pygame과 키보드 up, down과 및 colliderect() 함수를 사용하며 여러 상황에 맞는 이벤트 처리를 주로 다뤘습니다. 이를 통해 조금 더 색다른 게임을 만들어 보세요.

 

ㅁ 참고

토닥토닥 파이썬

 

 


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

 

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

 

반응형