개발자입니다
[처음코딩] 파이게임 튜토리얼: 화살 쏴서 오소리로부터 아기토끼 지키기 본문
강의 개요 및 출처
파이썬과 파이게임을 이용해 간단한 슈팅게임을 만든다.
https://opentutorials.org/course/3045
개발환경
윈도우 10
파이썬 3.6
파이게임 1.9.3
VSCode
VSCode 세팅
<확장> 탭에서 'python' 검색해서 설치해준다.
파이게임 설치, 화면 구성
cmd에서 입력한다.
pip install pygame
실행 방법
그러면 .py 파일에서 우측에 실행 버튼이 생긴다.
또는 전체 코드 말고 줄 별로 실행하려면 아래 터미널에 'python' 입력해서 파이썬 실행기로 접속한다.
한 줄 실행은 커서 위치에서 Shift + Enter 한다.
여러줄 선택해서 Shift + Enter 하면 선택한 줄이 실행된다.
1단계 - 화면 만들기
1. 파이게임 모듈을 불러온다.
2. 초기화 시킨다.
너비, 높이 창 크기를 설정하고 변수에 저장한다.
7. 화면을 다시 그린다.
8. 화면을 띄우면 바로 꺼지지 않고 유지시킨다.
# 1. 파이게임 모듈을 불러온다.
import pygame
# 2. 초기화 시킨다.
pygame.init()
width, height = 640, 480
screen = pygame.display.set_mode((width, height))
# 3. 이미지를 가져온다.
# 4. 계속 화면이 보이도록 한다.
while True:
# 5. 화면을 깨끗하게 한다.
screen.fill((0,0,0)) # (R,G,B)
# 6. 모든 요소들을 다시 그린다.
# 7. 화면을 다시 그린다.
pygame.display.flip()
# 8. 게임을 종료
for event in pygame.event.get():
# X 를 눌렀으면,
if event.type == pygame.QUIT:
# 게임종료한다
pygame.quit()
exit(0)
2단계 - 그림파일 부르기
github.com/eventia/rabbitone 주소에서 resources.zip 파일을 다운로드 한다.
작업디렉토리 > resources 에 압축푼다.
3. 이미지를 가져온다.
6. 모든 요소들을 다시 그린다.
# 1. 파이게임 모듈을 불러온다.
import pygame
# 2. 초기화 시킨다.
pygame.init()
width, height = 640, 480
screen = pygame.display.set_mode((width, height))
# 3. 이미지를 가져온다.
player = pygame.image.load("resources/images/dude.png")
# 4. 계속 화면이 보이도록 한다.
while True:
# 5. 화면을 깨끗하게 한다.
screen.fill((0,0,0)) # (R,G,B)
# 6. 모든 요소들을 다시 그린다.
screen.blit(player, (100,100))
# 7. 화면을 다시 그린다.
pygame.display.flip()
# 8. 게임을 종료
for event in pygame.event.get():
# X 를 눌렀으면,
if event.type == pygame.QUIT:
# 게임종료한다
pygame.quit()
exit(0)
help()
함수에 대한 설명을 확인할 수 있다.
>>> help(pygame.init())
Help on tuple object:
class tuple(object)
| tuple(iterable=(), /)
|
| Built-in immutable sequence.
|
| If no argument is given, the constructor returns an empty tuple.
| If iterable is specified the tuple is initialized from iterable's items.
|
| If the argument is a tuple, the return value is the same object.
|
| Built-in subclasses:
| asyncgen_hooks
| UnraisableHookArgs
|
| Methods defined here:
|
| __add__(self, value, /)
| Return self+value.
|
| __contains__(self, key, /)
| Return key in self.
|
| __eq__(self, value, /)
| Return self==value.
|
| __ge__(self, value, /)
| Return self>=value.
|
| __getattribute__(self, name, /)
| Return getattr(self, name).
dir()
객체의 속성과 메서드를 나열하는데 사용된다.
dir() 함수를 객체 없이 호출하면, 현재 스코프 내의 모든 이름(변수, 함수, 클래스 등)을 나열한다.
>>> dir(screen)
['__class__', '__copy__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '_pixels_address', 'blit', 'blits', 'convert', 'convert_alpha', 'copy', 'fill', 'get_abs_offset', 'get_abs_parent', 'get_alpha', 'get_at', 'get_at_mapped', 'get_bitsize', 'get_blendmode', 'get_bounding_rect', 'get_buffer', 'get_bytesize', 'get_clip', 'get_colorkey', 'get_flags', 'get_height', 'get_locked', 'get_locks', 'get_losses', 'get_masks', 'get_offset', 'get_palette', 'get_palette_at', 'get_parent', 'get_pitch', 'get_rect', 'get_shifts', 'get_size', 'get_view', 'get_width', 'lock', 'map_rgb', 'mustlock', 'premul_alpha', 'scroll', 'set_alpha', 'set_at', 'set_clip', 'set_colorkey', 'set_masks', 'set_palette', 'set_palette_at', 'set_shifts', 'subsurface', 'unlock', 'unmap_rgb']
3단계 - 배경화면 그리기
(0, 0) 에서 (640, 480) 까지 배경을 깔아야한다.
가로(x축) 방향으로는 (0, 0), (100, 0), ..., (600, 0) 으로 그림 7개가 들어간다.
가로 화면이 640인데 넘어가는 부분은 어차피 화면에 나오지 않으니 상관없다.
동일한 방법으로 세로(y축)도 배경 넣어준다.
3. grass와 castle 이미지를 가져온다.
6. for 문으로 배경이미지를 만든다. 그리고 castle 이미지를 하나하나 넣어준다.
# 1. 파이게임 모듈을 불러온다.
import pygame
# 2. 초기화 시킨다.
pygame.init()
width, height = 640, 480
screen = pygame.display.set_mode((width, height))
# 3. 이미지를 가져온다.
player = pygame.image.load("resources/images/dude.png")
grass = pygame.image.load("resources/images/grass.png")
castle = pygame.image.load("resources/images/castle.png")
# 4. 계속 화면이 보이도록 한다.
while True:
# 5. 화면을 깨끗하게 한다.
screen.fill((0,0,0)) # (R,G,B)
# 6. 모든 요소들을 다시 그린다.
for x in range(width//grass.get_width()+1):
for y in range(height//grass.get_height()+1):
screen.blit(grass, (x*100,y*100))
screen.blit(castle, (0, 30))
screen.blit(castle, (0, 135))
screen.blit(castle, (0, 240))
screen.blit(castle, (0, 345))
screen.blit(player, (100,100))
# 7. 화면을 다시 그린다.
pygame.display.flip()
# 8. 게임을 종료
for event in pygame.event.get():
# X 를 눌렀으면,
if event.type == pygame.QUIT:
# 게임종료한다
pygame.quit()
exit(0)
4단계 - 키보드로 그림 움직이기
wasd 로 상하좌우 움직인다.
keys 에 배열로 키 입력 상태값을 나타낸다.
playpos에 player 위치를 저장한다.
키 이벤트에 키가 눌러졌을때 어떤 키인지 불러들여서 배열의 상태를 True로 바꾼다. K_w 뜻은 Key w 라는 의미로 w키를 뜻한다.
아래에서 keys 리스트의 각 원소 상태가 True일 때 playpos 의 값을 변환한다.
# 1. 파이게임 모듈을 불러온다.
import pygame
# 2. 초기화 시킨다.
pygame.init()
width, height = 640, 480
screen = pygame.display.set_mode((width, height))
# 3. 이미지를 가져온다.
player = pygame.image.load("resources/images/dude.png")
grass = pygame.image.load("resources/images/grass.png")
castle = pygame.image.load("resources/images/castle.png")
keys = [False, False, False, False]
playpos = [100,100]
# 4. 계속 화면이 보이도록 한다.
while True:
# 5. 화면을 깨끗하게 한다.
screen.fill((0,0,0)) # (R,G,B)
# 6. 모든 요소들을 다시 그린다.
for x in range(width//grass.get_width()+1):
for y in range(height//grass.get_height()+1):
screen.blit(grass, (x*100,y*100))
screen.blit(castle, (0, 30))
screen.blit(castle, (0, 135))
screen.blit(castle, (0, 240))
screen.blit(castle, (0, 345))
screen.blit(player, playpos)
# 7. 화면을 다시 그린다.
pygame.display.flip()
# 8. 게임을 종료
for event in pygame.event.get():
# X 를 눌렀으면,
if event.type == pygame.QUIT:
# 게임종료한다
pygame.quit()
exit(0)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
keys[0] = True
elif event.key == pygame.K_a:
keys[1] = True
elif event.key == pygame.K_s:
keys[2] = True
elif event.key == pygame.K_d:
keys[3] = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_w:
keys[0] = False
elif event.key == pygame.K_a:
keys[1] = False
elif event.key == pygame.K_s:
keys[2] = False
elif event.key == pygame.K_d:
keys[3] = False
# 9 - Move player
if keys[0]:
playpos[1] = playpos[1] - 5
elif keys[2]:
playpos[1] = playpos[1] + 5
elif keys[1]:
playpos[0] = playpos[0] - 5
elif keys[3]:
playpos[0] = playpos[0] + 5
5단계 - 마우스로 그림 회전하기
6.1 pygame.mouse.get_pos() 로 마우스의 위치를 가져온다.
import math 를 먼저 하고 angle 에 math 사용한다. atan2 라는 아크탄젠트 관련 함수를 사용한다.
position[1]-(playpos[1]+32) 와 position[0]-(playpos[0]+26) 는 플레이어의 이미지 중심을 고려하여 계산한 값이다.
angle 을 근거로 player 객체를 회전시킨다. angle 은 라디안 단위이므로 *57.29 를 해서 도 단위로 변환한다.
playerpos1 에 위치 값을 저장하고 새로 그린다. 이미지의 중심을 정확히 위치시키기 위해 이미지 너비의 절반과 높이의 절반을 빼주어 계산한다.
# 1. 파이게임 모듈을 불러온다.
import pygame
import math
# 2. 초기화 시킨다.
pygame.init()
width, height = 640, 480
screen = pygame.display.set_mode((width, height))
# 3. 이미지를 가져온다.
player = pygame.image.load("resources/images/dude.png")
grass = pygame.image.load("resources/images/grass.png")
castle = pygame.image.load("resources/images/castle.png")
keys = [False, False, False, False]
playpos = [100,100]
# 4. 계속 화면이 보이도록 한다.
while True:
# 5. 화면을 깨끗하게 한다.
screen.fill((0,0,0)) # (R,G,B)
# 6. 모든 요소들을 다시 그린다.
for x in range(width//grass.get_width()+1):
for y in range(height//grass.get_height()+1):
screen.blit(grass, (x*100,y*100))
screen.blit(castle, (0, 30))
screen.blit(castle, (0, 135))
screen.blit(castle, (0, 240))
screen.blit(castle, (0, 345))
# 6.1 - Set player position and rotation
position = pygame.mouse.get_pos()
angle = math.atan2(position[1]-(playpos[1]+32), position[0]-(playpos[0]+26))
playerrot = pygame.transform.rotate(player, 360-angle*57.29)
playerpos1 = (playpos[0]-playerrot.get_rect().width//2, playpos[1]-playerrot.get_rect().height//2)
screen.blit(playerrot, playerpos1)
# 7. 화면을 다시 그린다.
pygame.display.flip()
# 8. 게임을 종료
for event in pygame.event.get():
# X 를 눌렀으면,
if event.type == pygame.QUIT:
# 게임종료한다
pygame.quit()
exit(0)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
keys[0] = True
elif event.key == pygame.K_a:
keys[1] = True
elif event.key == pygame.K_s:
keys[2] = True
elif event.key == pygame.K_d:
keys[3] = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_w:
keys[0] = False
elif event.key == pygame.K_a:
keys[1] = False
elif event.key == pygame.K_s:
keys[2] = False
elif event.key == pygame.K_d:
keys[3] = False
# 9 - Move player
if keys[0]:
playpos[1] = playpos[1] - 5
elif keys[2]:
playpos[1] = playpos[1] + 5
elif keys[1]:
playpos[0] = playpos[0] - 5
elif keys[3]:
playpos[0] = playpos[0] + 5
수학 공식 설명
angle 의 각도는 atan2 로 구한다.
playerpos1 으로 위치를 다시 지정하는 이유는 그림은 좌상단인 0, 0 를 중심을 회전하기 때문에 삐걱거리며 회전한다. 이를 그림 중심으로 부터 회전하도록 한다.
6단계 - 화살 발사
화살의 발사 각도는 플레이어의 중심에서 마우스까지의 각도이다.
2. arrows 배열을 초기화한다.
3. arrow 그림을 불러온다.
6-2 발사한 화살을 움직이면서 계속 그린다.
8. 마우스를 클릭하면 배열의 원소에 [플레이어 중심에서 마우스까지 각도, 플레이어 중심 x좌표, 플레이어 중심 y좌표] 를 저장한다.
# 1. 파이게임 모듈을 불러온다.
import pygame
import math
# 2. 초기화 시킨다.
pygame.init()
width, height = 640, 480
screen = pygame.display.set_mode((width, height))
acc = [0,0]
arrows = []
# 3. 이미지를 가져온다.
player = pygame.image.load("resources/images/dude.png")
grass = pygame.image.load("resources/images/grass.png")
castle = pygame.image.load("resources/images/castle.png")
arrow = pygame.image.load("resources/images/bullet.png")
keys = [False, False, False, False]
playpos = [100,100]
# 4. 계속 화면이 보이도록 한다.
while True:
# 5. 화면을 깨끗하게 한다.
screen.fill((0,0,0)) # (R,G,B)
# 6. 모든 요소들을 다시 그린다.
for x in range(width//grass.get_width()+1):
for y in range(height//grass.get_height()+1):
screen.blit(grass, (x*100,y*100))
screen.blit(castle, (0, 30))
screen.blit(castle, (0, 135))
screen.blit(castle, (0, 240))
screen.blit(castle, (0, 345))
# 6.1 - Set player position and rotation
position = pygame.mouse.get_pos()
angle = math.atan2(position[1]-(playpos[1]+32), position[0]-(playpos[0]+26))
playerrot = pygame.transform.rotate(player, 360-angle*57.29)
playerpos1 = (playpos[0]-playerrot.get_rect().width//2, playpos[1]-playerrot.get_rect().height//2)
screen.blit(playerrot, playerpos1)
# 6.2 - Draw arrows
for bullet in arrows: # bullet <== [각도, 플레이어의 x좌표, 플레이어의 y좌표]
index=0
velx=math.cos(bullet[0])*10
vely=math.sin(bullet[0])*10
bullet[1]+=velx
bullet[2]+=vely
if bullet[1]<-64 or bullet[1]>640 or bullet[2]<-64 or bullet[2]>480:
arrows.pop(index)
index+=1
for projectile in arrows:
arrow1 = pygame.transform.rotate(arrow, 360-projectile[0]*57.29)
screen.blit(arrow1, (projectile[1], projectile[2]))
# 7. 화면을 다시 그린다.
pygame.display.flip()
# 8. 게임을 종료
for event in pygame.event.get():
# X 를 눌렀으면,
if event.type == pygame.QUIT:
# 게임종료한다
pygame.quit()
exit(0)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
keys[0] = True
elif event.key == pygame.K_a:
keys[1] = True
elif event.key == pygame.K_s:
keys[2] = True
elif event.key == pygame.K_d:
keys[3] = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_w:
keys[0] = False
elif event.key == pygame.K_a:
keys[1] = False
elif event.key == pygame.K_s:
keys[2] = False
elif event.key == pygame.K_d:
keys[3] = False
if event.type == pygame.MOUSEBUTTONDOWN:
position = pygame.mouse.get_pos()
acc[1] = acc[1]+1
arrows.append([math.atan2(position[1]-(playpos[1]+32), position[0]-(playpos[0]+26)), \
playerpos1[0]+32, playerpos1[1]+32])
# 9 - Move player
if keys[0]:
playpos[1] = playpos[1] - 5
elif keys[2]:
playpos[1] = playpos[1] + 5
elif keys[1]:
playpos[0] = playpos[0] - 5
elif keys[3]:
playpos[0] = playpos[0] + 5
7단계 - 다가오는 적들
2. badtimer, badtimer1, badguys, healthvalue 를 추가한다.
4. badtimer 를 계속 -1씩 한다.
6.3 badtimer 가 0이면 적을 출현시킨다. y좌표 위치는 랜덤이므로 위에 import random으로 모듈을 불러온다. 그 후 badtimer에 적절한 숫자를 넣는다.
badguy의 x좌표 위치가 -64 보다 작으면 badguys 배열에서 제거한다.
6.3.1 castle 을 공격하였으면 healthvalue 를 랜덤하게 감소하고 badguys 배열에서 제거한다.
# 1. 파이게임 모듈을 불러온다.
import pygame
import math
import random
# 2. 초기화 시킨다.
pygame.init()
width, height = 640, 480
screen = pygame.display.set_mode((width, height))
acc = [0,0]
arrows = []
badtimer = 100
badtimer1 = 0
badguys = [[640,100]]
healthvalue = 194
# 3. 이미지를 가져온다.
player = pygame.image.load("resources/images/dude.png")
grass = pygame.image.load("resources/images/grass.png")
castle = pygame.image.load("resources/images/castle.png")
arrow = pygame.image.load("resources/images/bullet.png")
badguyimg = pygame.image.load("resources/images/badguy.png")
keys = [False, False, False, False]
playpos = [100,100]
# 4. 계속 화면이 보이도록 한다.
while True:
badtimer-=1
# 5. 화면을 깨끗하게 한다.
screen.fill((0,0,0)) # (R,G,B)
# 6. 모든 요소들을 다시 그린다.
for x in range(width//grass.get_width()+1):
for y in range(height//grass.get_height()+1):
screen.blit(grass, (x*100,y*100))
screen.blit(castle, (0, 30))
screen.blit(castle, (0, 135))
screen.blit(castle, (0, 240))
screen.blit(castle, (0, 345))
# 6.1 - Set player position and rotation
position = pygame.mouse.get_pos()
angle = math.atan2(position[1]-(playpos[1]+32), position[0]-(playpos[0]+26))
playerrot = pygame.transform.rotate(player, 360-angle*57.29)
playerpos1 = (playpos[0]-playerrot.get_rect().width//2, playpos[1]-playerrot.get_rect().height//2)
screen.blit(playerrot, playerpos1)
# 6.2 - Draw arrows
for bullet in arrows: # bullet <== [각도, 플레이어의 x좌표, 플레이어의 y좌표]
index=0
velx=math.cos(bullet[0])*10
vely=math.sin(bullet[0])*10
bullet[1]+=velx
bullet[2]+=vely
if bullet[1]<-64 or bullet[1]>640 or bullet[2]<-64 or bullet[2]>480:
arrows.pop(index)
index+=1
for projectile in arrows:
arrow1 = pygame.transform.rotate(arrow, 360-projectile[0]*57.29)
screen.blit(arrow1, (projectile[1], projectile[2]))
# 6.3 - Draw Badguys
if badtimer==0:
badguys.append([640, random.randint(50,430)])
badtimer=100-(badtimer1*2)
if badtimer1>=35:
badtimer1=35
else:
badtimer1+=5
index=0
for badguy in badguys:
if badguy[0]<-64:
badguys.pop(index)
else:
badguy[0]-=7
# 6.3.1 - Attack castle
badrect=pygame.Rect(badguyimg.get_rect())
badrect.top=badguy[1]
badrect.left=badguy[0]
if badrect.left<64:
healthvalue -= random.randint(5,20)
badguys.pop(index)
# 6.3.3 - Next bad guy
index+=1
for badguy in badguys:
screen.blit(badguyimg, badguy)
# 7. 화면을 다시 그린다.
pygame.display.flip()
# 8. 게임을 종료
for event in pygame.event.get():
# X 를 눌렀으면,
if event.type == pygame.QUIT:
# 게임종료한다
pygame.quit()
exit(0)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
keys[0] = True
elif event.key == pygame.K_a:
keys[1] = True
elif event.key == pygame.K_s:
keys[2] = True
elif event.key == pygame.K_d:
keys[3] = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_w:
keys[0] = False
elif event.key == pygame.K_a:
keys[1] = False
elif event.key == pygame.K_s:
keys[2] = False
elif event.key == pygame.K_d:
keys[3] = False
if event.type == pygame.MOUSEBUTTONDOWN:
position = pygame.mouse.get_pos()
acc[1] = acc[1]+1
arrows.append([math.atan2(position[1]-(playpos[1]+32), position[0]-(playpos[0]+26)), \
playerpos1[0]+32, playerpos1[1]+32])
# 9 - Move player
if keys[0]:
playpos[1] = playpos[1] - 5
elif keys[2]:
playpos[1] = playpos[1] + 5
elif keys[1]:
playpos[0] = playpos[0] - 5
elif keys[3]:
playpos[0] = playpos[0] + 5
8단계 - 화살에 맞은 적 소멸 (충돌)
6.3.2 화살에 맞은 적을 체크하고 소멸시킨다.
bullrect=pygame.Rect(arrow.get_rect()): 화살의 충돌 박스를 생성합니다. 그리고 x, y 좌표를 할당한다.
충돌 여부를 검사해서 충돌시 처리를 한다.
# 1. 파이게임 모듈을 불러온다.
import pygame
import math
import random
# 2. 초기화 시킨다.
pygame.init()
width, height = 640, 480
screen = pygame.display.set_mode((width, height))
acc = [0,0]
arrows = []
badtimer = 100
badtimer1 = 0
badguys = [[640,100]]
healthvalue = 194
# 3. 이미지를 가져온다.
player = pygame.image.load("resources/images/dude.png")
grass = pygame.image.load("resources/images/grass.png")
castle = pygame.image.load("resources/images/castle.png")
arrow = pygame.image.load("resources/images/bullet.png")
badguyimg = pygame.image.load("resources/images/badguy.png")
keys = [False, False, False, False]
playpos = [100,100]
# 4. 계속 화면이 보이도록 한다.
while True:
badtimer-=1
# 5. 화면을 깨끗하게 한다.
screen.fill((0,0,0)) # (R,G,B)
# 6. 모든 요소들을 다시 그린다.
for x in range(width//grass.get_width()+1):
for y in range(height//grass.get_height()+1):
screen.blit(grass, (x*100,y*100))
screen.blit(castle, (0, 30))
screen.blit(castle, (0, 135))
screen.blit(castle, (0, 240))
screen.blit(castle, (0, 345))
# 6.1 - Set player position and rotation
position = pygame.mouse.get_pos()
angle = math.atan2(position[1]-(playpos[1]+32), position[0]-(playpos[0]+26))
playerrot = pygame.transform.rotate(player, 360-angle*57.29)
playerpos1 = (playpos[0]-playerrot.get_rect().width//2, playpos[1]-playerrot.get_rect().height//2)
screen.blit(playerrot, playerpos1)
# 6.2 - Draw arrows
for bullet in arrows: # bullet <== [각도, 플레이어의 x좌표, 플레이어의 y좌표]
index=0
velx=math.cos(bullet[0])*10
vely=math.sin(bullet[0])*10
bullet[1]+=velx
bullet[2]+=vely
if bullet[1]<-64 or bullet[1]>640 or bullet[2]<-64 or bullet[2]>480:
arrows.pop(index)
index+=1
for projectile in arrows:
arrow1 = pygame.transform.rotate(arrow, 360-projectile[0]*57.29)
screen.blit(arrow1, (projectile[1], projectile[2]))
# 6.3 - Draw Badguys
if badtimer==0:
badguys.append([640, random.randint(50,430)])
badtimer=100-(badtimer1*2)
if badtimer1>=35:
badtimer1=35
else:
badtimer1+=5
index=0
for badguy in badguys:
if badguy[0]<-64:
badguys.pop(index)
else:
badguy[0]-=7
# 6.3.1 - Attack castle
badrect=pygame.Rect(badguyimg.get_rect())
badrect.top=badguy[1]
badrect.left=badguy[0]
if badrect.left<64:
healthvalue -= random.randint(5,20)
badguys.pop(index)
# 6.3.2 - Check for collisions
index1=0
for bullet in arrows:
bullrect=pygame.Rect(arrow.get_rect())
bullrect.left=bullet[1]
bullrect.top=bullet[2]
if badrect.colliderect(bullrect):
acc[0]+=1
badguys.pop(index)
arrows.pop(index1)
index1+=1
# 6.3.3 - Next bad guy
index+=1
for badguy in badguys:
screen.blit(badguyimg, badguy)
# 7. 화면을 다시 그린다.
pygame.display.flip()
# 8. 게임을 종료
for event in pygame.event.get():
# X 를 눌렀으면,
if event.type == pygame.QUIT:
# 게임종료한다
pygame.quit()
exit(0)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
keys[0] = True
elif event.key == pygame.K_a:
keys[1] = True
elif event.key == pygame.K_s:
keys[2] = True
elif event.key == pygame.K_d:
keys[3] = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_w:
keys[0] = False
elif event.key == pygame.K_a:
keys[1] = False
elif event.key == pygame.K_s:
keys[2] = False
elif event.key == pygame.K_d:
keys[3] = False
if event.type == pygame.MOUSEBUTTONDOWN:
position = pygame.mouse.get_pos()
acc[1] = acc[1]+1
arrows.append([math.atan2(position[1]-(playpos[1]+32), position[0]-(playpos[0]+26)), \
playerpos1[0]+32, playerpos1[1]+32])
# 9 - Move player
if keys[0]:
playpos[1] = playpos[1] - 5
elif keys[2]:
playpos[1] = playpos[1] + 5
elif keys[1]:
playpos[0] = playpos[0] - 5
elif keys[3]:
playpos[0] = playpos[0] + 5
9단계 - 남은 시간과 생명력 표시
6.4 시계를 그린다. 폰트와 크기 객체를 생성하고 그린다.
textRect 객체를 생성해서 위치를 지정해서 screen.blit 으로 그린다.
6.5 남은 생명력을 그린다. 이를 위해서 3. 에 healthbar, health 이미지를 객체로 생성한다.
전체는 검정 테두리에 빨간색 배경이고, 체력 1당 1픽셀의 초록색 칸이 되도록 한다.
# 1. 파이게임 모듈을 불러온다.
import pygame
import math
import random
# 2. 초기화 시킨다.
pygame.init()
width, height = 640, 480
screen = pygame.display.set_mode((width, height))
acc = [0,0]
arrows = []
badtimer = 100
badtimer1 = 0
badguys = [[640,100]]
healthvalue = 194
# 3. 이미지를 가져온다.
player = pygame.image.load("resources/images/dude.png")
grass = pygame.image.load("resources/images/grass.png")
castle = pygame.image.load("resources/images/castle.png")
arrow = pygame.image.load("resources/images/bullet.png")
badguyimg = pygame.image.load("resources/images/badguy.png")
healthbar = pygame.image.load("resources/images/healthbar.png")
health = pygame.image.load("resources/images/health.png")
keys = [False, False, False, False]
playpos = [100,100]
# 4. 계속 화면이 보이도록 한다.
while True:
badtimer-=1
# 5. 화면을 깨끗하게 한다.
screen.fill((0,0,0)) # (R,G,B)
# 6. 모든 요소들을 다시 그린다.
for x in range(width//grass.get_width()+1):
for y in range(height//grass.get_height()+1):
screen.blit(grass, (x*100,y*100))
screen.blit(castle, (0, 30))
screen.blit(castle, (0, 135))
screen.blit(castle, (0, 240))
screen.blit(castle, (0, 345))
# 6.1 - Set player position and rotation
position = pygame.mouse.get_pos()
angle = math.atan2(position[1]-(playpos[1]+32), position[0]-(playpos[0]+26))
playerrot = pygame.transform.rotate(player, 360-angle*57.29)
playerpos1 = (playpos[0]-playerrot.get_rect().width//2, playpos[1]-playerrot.get_rect().height//2)
screen.blit(playerrot, playerpos1)
# 6.2 - Draw arrows
for bullet in arrows: # bullet <== [각도, 플레이어의 x좌표, 플레이어의 y좌표]
index=0
velx=math.cos(bullet[0])*10
vely=math.sin(bullet[0])*10
bullet[1]+=velx
bullet[2]+=vely
if bullet[1]<-64 or bullet[1]>640 or bullet[2]<-64 or bullet[2]>480:
arrows.pop(index)
index+=1
for projectile in arrows:
arrow1 = pygame.transform.rotate(arrow, 360-projectile[0]*57.29)
screen.blit(arrow1, (projectile[1], projectile[2]))
# 6.3 - Draw Badguys
if badtimer==0:
badguys.append([640, random.randint(50,430)])
badtimer=100-(badtimer1*2)
if badtimer1>=35:
badtimer1=35
else:
badtimer1+=5
index=0
for badguy in badguys:
if badguy[0]<-64:
badguys.pop(index)
else:
badguy[0]-=7
# 6.3.1 - Attack castle
badrect=pygame.Rect(badguyimg.get_rect())
badrect.top=badguy[1]
badrect.left=badguy[0]
if badrect.left<64:
healthvalue -= random.randint(5,20)
badguys.pop(index)
# 6.3.2 - Check for collisions
index1=0
for bullet in arrows:
bullrect=pygame.Rect(arrow.get_rect())
bullrect.left=bullet[1]
bullrect.top=bullet[2]
if badrect.colliderect(bullrect):
acc[0]+=1
badguys.pop(index)
arrows.pop(index1)
index1+=1
# 6.3.3 - Next bad guy
index+=1
for badguy in badguys:
screen.blit(badguyimg, badguy)
# 6.4 - Draw clock
font = pygame.font.Font(None, 24)
survivedtext = font.render(str(int((90000-pygame.time.get_ticks())/60000))+":"\
+str(int((90000-pygame.time.get_ticks())/1000%60)).zfill(2), True, (0,0,0))
textRect = survivedtext.get_rect()
textRect.topright=[635,5]
screen.blit(survivedtext, textRect)
# 6.5 - Draw health bar
screen.blit(healthbar, (5,5))
for health1 in range(healthvalue):
screen.blit(health, (health1+8,8))
# 7. 화면을 다시 그린다.
pygame.display.flip()
# 8. 게임을 종료
for event in pygame.event.get():
# X 를 눌렀으면,
if event.type == pygame.QUIT:
# 게임종료한다
pygame.quit()
exit(0)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
keys[0] = True
elif event.key == pygame.K_a:
keys[1] = True
elif event.key == pygame.K_s:
keys[2] = True
elif event.key == pygame.K_d:
keys[3] = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_w:
keys[0] = False
elif event.key == pygame.K_a:
keys[1] = False
elif event.key == pygame.K_s:
keys[2] = False
elif event.key == pygame.K_d:
keys[3] = False
if event.type == pygame.MOUSEBUTTONDOWN:
position = pygame.mouse.get_pos()
acc[1] = acc[1]+1
arrows.append([math.atan2(position[1]-(playpos[1]+32), position[0]-(playpos[0]+26)), \
playerpos1[0]+32, playerpos1[1]+32])
# 9 - Move player
if keys[0]:
playpos[1] = playpos[1] - 5
elif keys[2]:
playpos[1] = playpos[1] + 5
elif keys[1]:
playpos[0] = playpos[0] - 5
elif keys[3]:
playpos[0] = playpos[0] + 5
# 10 - Win/Lose check
10단계 - 조건에 따른 승리 또는 패
10 90초가 넘었을때 running=0, exitcode=1 로 종료한다.
healthvalue<=0 일때 running=0, exitcode=0 으로 종료한다.
정확도를 출력해준다.
11 exitcode=0 (game over) 로 종료되면 정확도와 game over 화면을 출력한다.
exitcode=1 (you win) 로 종료되면 정확도와 you win 화면을 출력한다.
while 1: 로 마지막 화면을 계속 표시하며 닫힘 버튼을 눌렀는지 검사한다.
# 1. 파이게임 모듈을 불러온다.
import pygame
import math
import random
# 2. 초기화 시킨다.
pygame.init()
width, height = 640, 480
screen = pygame.display.set_mode((width, height))
acc = [0,0]
arrows = []
badtimer = 100
badtimer1 = 0
badguys = [[640,100]]
healthvalue = 194
# 3. 이미지를 가져온다.
player = pygame.image.load("resources/images/dude.png")
grass = pygame.image.load("resources/images/grass.png")
castle = pygame.image.load("resources/images/castle.png")
arrow = pygame.image.load("resources/images/bullet.png")
badguyimg = pygame.image.load("resources/images/badguy.png")
healthbar = pygame.image.load("resources/images/healthbar.png")
health = pygame.image.load("resources/images/health.png")
gameover = pygame.image.load("resources/images/gameover.png")
youwin = pygame.image.load("resources/images/youwin.png")
keys = [False, False, False, False]
playpos = [100,100]
# 4. 계속 화면이 보이도록 한다.
running = 1
exitcode = 0
while running:
badtimer-=1
# 5. 화면을 깨끗하게 한다.
screen.fill((0,0,0)) # (R,G,B)
# 6. 모든 요소들을 다시 그린다.
for x in range(width//grass.get_width()+1):
for y in range(height//grass.get_height()+1):
screen.blit(grass, (x*100,y*100))
screen.blit(castle, (0, 30))
screen.blit(castle, (0, 135))
screen.blit(castle, (0, 240))
screen.blit(castle, (0, 345))
# 6.1 - Set player position and rotation
position = pygame.mouse.get_pos()
angle = math.atan2(position[1]-(playpos[1]+32), position[0]-(playpos[0]+26))
playerrot = pygame.transform.rotate(player, 360-angle*57.29)
playerpos1 = (playpos[0]-playerrot.get_rect().width//2, playpos[1]-playerrot.get_rect().height//2)
screen.blit(playerrot, playerpos1)
# 6.2 - Draw arrows
for bullet in arrows: # bullet <== [각도, 플레이어의 x좌표, 플레이어의 y좌표]
index=0
velx=math.cos(bullet[0])*10
vely=math.sin(bullet[0])*10
bullet[1]+=velx
bullet[2]+=vely
if bullet[1]<-64 or bullet[1]>640 or bullet[2]<-64 or bullet[2]>480:
arrows.pop(index)
index+=1
for projectile in arrows:
arrow1 = pygame.transform.rotate(arrow, 360-projectile[0]*57.29)
screen.blit(arrow1, (projectile[1], projectile[2]))
# 6.3 - Draw Badguys
if badtimer==0:
badguys.append([640, random.randint(50,430)])
badtimer=100-(badtimer1*2)
if badtimer1>=35:
badtimer1=35
else:
badtimer1+=5
index=0
for badguy in badguys:
if badguy[0]<-64:
badguys.pop(index)
else:
badguy[0]-=3
# 6.3.1 - Attack castle
badrect=pygame.Rect(badguyimg.get_rect())
badrect.top=badguy[1]
badrect.left=badguy[0]
if badrect.left<64:
healthvalue -= random.randint(5,20)
badguys.pop(index)
# 6.3.2 - Check for collisions
index1=0
for bullet in arrows:
bullrect=pygame.Rect(arrow.get_rect())
bullrect.left=bullet[1]
bullrect.top=bullet[2]
if badrect.colliderect(bullrect):
acc[0]+=1
badguys.pop(index)
arrows.pop(index1)
index1+=1
# 6.3.3 - Next bad guy
index+=1
for badguy in badguys:
screen.blit(badguyimg, badguy)
# 6.4 - Draw clock
font = pygame.font.Font(None, 24)
survivedtext = font.render(str(int((90000-pygame.time.get_ticks())/60000))+":"\
+str(int((90000-pygame.time.get_ticks())/1000%60)).zfill(2), True, (0,0,0))
textRect = survivedtext.get_rect()
textRect.topright=[635,5]
screen.blit(survivedtext, textRect)
# 6.5 - Draw health bar
screen.blit(healthbar, (5,5))
for health1 in range(healthvalue):
screen.blit(health, (health1+8,8))
# 7. 화면을 다시 그린다.
pygame.display.flip()
# 8. 게임을 종료
for event in pygame.event.get():
# X 를 눌렀으면,
if event.type == pygame.QUIT:
# 게임종료한다
pygame.quit()
exit(0)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
keys[0] = True
elif event.key == pygame.K_a:
keys[1] = True
elif event.key == pygame.K_s:
keys[2] = True
elif event.key == pygame.K_d:
keys[3] = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_w:
keys[0] = False
elif event.key == pygame.K_a:
keys[1] = False
elif event.key == pygame.K_s:
keys[2] = False
elif event.key == pygame.K_d:
keys[3] = False
if event.type == pygame.MOUSEBUTTONDOWN:
position = pygame.mouse.get_pos()
acc[1] = acc[1]+1
arrows.append([math.atan2(position[1]-(playpos[1]+32), position[0]-(playpos[0]+26)), \
playerpos1[0]+32, playerpos1[1]+32])
# 9 - Move player
if keys[0]:
playpos[1] = playpos[1] - 5
elif keys[2]:
playpos[1] = playpos[1] + 5
elif keys[1]:
playpos[0] = playpos[0] - 5
elif keys[3]:
playpos[0] = playpos[0] + 5
# 10 - Win/Lose check
if pygame.time.get_ticks()>90000:
running=0
exitcode=1
if healthvalue<=0:
running=0
exitcode=0
if acc[1]!=0:
accuracy=round(acc[0]*1.0/acc[1]*100)
else:
accuracy=0
# 11 = Win/Lose display
if exitcode==0:
pygame.font.init()
font = pygame.font.Font(None, 24)
text = font.render("Accuracy: "+str(accuracy)+"%", True, (255,0,0))
textRect = text.get_rect()
textRect.centerx = screen.get_rect().centerx
textRect.centery = screen.get_rect().centery+24
screen.blit(gameover, (0,0))
screen.blit(text, textRect)
else:
pygame.font.init()
font = pygame.font.Font(None, 24)
text = font.render("Accuracy: "+str(accuracy)+"%", True, (255,0,0))
textRect = text.get_rect()
textRect.centerx = screen.get_rect().centerx
textRect.centery = screen.get_rect().centery+24
screen.blit(youwin, (0,0))
screen.blit(text, textRect)
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit(0)
pygame.display.flip()
11단계 - 배경음악
배경음악 및 효과음을 넣는다.
2. pygame.mixer.init() 으로 초기화한다.
3.1 audio 를 불러들인다.
6.3.1 성이 공격 받았을때 효과음을 플레이한다.
6.3.2 적이 화살을 맞았을때 효과음을 플레이한다.
8. 마우스를 클릭했을 때 효과음을 플레이한다.
# 1. 파이게임 모듈을 불러온다.
import pygame
import math
import random
# 2. 초기화 시킨다.
pygame.init()
width, height = 640, 480
screen = pygame.display.set_mode((width, height))
acc = [0,0]
arrows = []
badtimer = 100
badtimer1 = 0
badguys = [[640,100]]
healthvalue = 194
pygame.mixer.init()
# 3. 이미지를 가져온다.
player = pygame.image.load("resources/images/dude.png")
grass = pygame.image.load("resources/images/grass.png")
castle = pygame.image.load("resources/images/castle.png")
arrow = pygame.image.load("resources/images/bullet.png")
badguyimg = pygame.image.load("resources/images/badguy.png")
healthbar = pygame.image.load("resources/images/healthbar.png")
health = pygame.image.load("resources/images/health.png")
gameover = pygame.image.load("resources/images/gameover.png")
youwin = pygame.image.load("resources/images/youwin.png")
keys = [False, False, False, False]
playpos = [100,100]
# 3.1 - Load audio
hit = pygame.mixer.Sound("resources/audio/explode.wav")
enemy = pygame.mixer.Sound("resources/audio/enemy.wav")
shoot = pygame.mixer.Sound("resources/audio/shoot.wav")
hit.set_volume(0.05)
enemy.set_volume(0.05)
shoot.set_volume(0.05)
pygame.mixer.music.load('resources/audio/moonlight.wav')
pygame.mixer.music.play(-1, 0.0)
pygame.mixer.music.set_volume(0.25)
# 4. 계속 화면이 보이도록 한다.
running = 1
exitcode = 0
while running:
badtimer-=1
# 5. 화면을 깨끗하게 한다.
screen.fill((0,0,0)) # (R,G,B)
# 6. 모든 요소들을 다시 그린다.
for x in range(width//grass.get_width()+1):
for y in range(height//grass.get_height()+1):
screen.blit(grass, (x*100,y*100))
screen.blit(castle, (0, 30))
screen.blit(castle, (0, 135))
screen.blit(castle, (0, 240))
screen.blit(castle, (0, 345))
# 6.1 - Set player position and rotation
position = pygame.mouse.get_pos()
angle = math.atan2(position[1]-(playpos[1]+32), position[0]-(playpos[0]+26))
playerrot = pygame.transform.rotate(player, 360-angle*57.29)
playerpos1 = (playpos[0]-playerrot.get_rect().width//2, playpos[1]-playerrot.get_rect().height//2)
screen.blit(playerrot, playerpos1)
# 6.2 - Draw arrows
for bullet in arrows: # bullet <== [각도, 플레이어의 x좌표, 플레이어의 y좌표]
index=0
velx=math.cos(bullet[0])*10
vely=math.sin(bullet[0])*10
bullet[1]+=velx
bullet[2]+=vely
if bullet[1]<-64 or bullet[1]>640 or bullet[2]<-64 or bullet[2]>480:
arrows.pop(index)
index+=1
for projectile in arrows:
arrow1 = pygame.transform.rotate(arrow, 360-projectile[0]*57.29)
screen.blit(arrow1, (projectile[1], projectile[2]))
# 6.3 - Draw Badguys
if badtimer==0:
badguys.append([640, random.randint(50,430)])
badtimer=100-(badtimer1*2)
if badtimer1>=35:
badtimer1=35
else:
badtimer1+=5
index=0
for badguy in badguys:
if badguy[0]<-64:
badguys.pop(index)
else:
badguy[0]-=2
# 6.3.1 - Attack castle
badrect=pygame.Rect(badguyimg.get_rect())
badrect.top=badguy[1]
badrect.left=badguy[0]
if badrect.left<64:
hit.play()
healthvalue -= random.randint(5,20)
badguys.pop(index)
# 6.3.2 - Check for collisions
index1=0
for bullet in arrows:
bullrect=pygame.Rect(arrow.get_rect())
bullrect.left=bullet[1]
bullrect.top=bullet[2]
if badrect.colliderect(bullrect):
enemy.play()
acc[0]+=1
badguys.pop(index)
arrows.pop(index1)
index1+=1
# 6.3.3 - Next bad guy
index+=1
for badguy in badguys:
screen.blit(badguyimg, badguy)
# 6.4 - Draw clock
font = pygame.font.Font(None, 24)
survivedtext = font.render(str(int((90000-pygame.time.get_ticks())/60000))+":"\
+str(int((90000-pygame.time.get_ticks())/1000%60)).zfill(2), True, (0,0,0))
textRect = survivedtext.get_rect()
textRect.topright=[635,5]
screen.blit(survivedtext, textRect)
# 6.5 - Draw health bar
screen.blit(healthbar, (5,5))
for health1 in range(healthvalue):
screen.blit(health, (health1+8,8))
# 7. 화면을 다시 그린다.
pygame.display.flip()
# 8. 게임을 종료
for event in pygame.event.get():
# X 를 눌렀으면,
if event.type == pygame.QUIT:
# 게임종료한다
pygame.quit()
exit(0)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
keys[0] = True
elif event.key == pygame.K_a:
keys[1] = True
elif event.key == pygame.K_s:
keys[2] = True
elif event.key == pygame.K_d:
keys[3] = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_w:
keys[0] = False
elif event.key == pygame.K_a:
keys[1] = False
elif event.key == pygame.K_s:
keys[2] = False
elif event.key == pygame.K_d:
keys[3] = False
if event.type == pygame.MOUSEBUTTONDOWN:
shoot.play()
position = pygame.mouse.get_pos()
acc[1] = acc[1]+1
arrows.append([math.atan2(position[1]-(playpos[1]+32), position[0]-(playpos[0]+26)), \
playerpos1[0]+32, playerpos1[1]+32])
# 9 - Move player
if keys[0]:
playpos[1] = playpos[1] - 5
elif keys[2]:
playpos[1] = playpos[1] + 5
elif keys[1]:
playpos[0] = playpos[0] - 5
elif keys[3]:
playpos[0] = playpos[0] + 5
# 10 - Win/Lose check
if pygame.time.get_ticks()>90000:
running=0
exitcode=1
if healthvalue<=0:
running=0
exitcode=0
if acc[1]!=0:
accuracy=round(acc[0]*1.0/acc[1]*100)
else:
accuracy=0
# 11 = Win/Lose display
if exitcode==0:
pygame.font.init()
font = pygame.font.Font(None, 24)
text = font.render("Accuracy: "+str(accuracy)+"%", True, (255,0,0))
textRect = text.get_rect()
textRect.centerx = screen.get_rect().centerx
textRect.centery = screen.get_rect().centery+24
screen.blit(gameover, (0,0))
screen.blit(text, textRect)
else:
pygame.font.init()
font = pygame.font.Font(None, 24)
text = font.render("Accuracy: "+str(accuracy)+"%", True, (255,0,0))
textRect = text.get_rect()
textRect.centerx = screen.get_rect().centerx
textRect.centery = screen.get_rect().centery+24
screen.blit(youwin, (0,0))
screen.blit(text, textRect)
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit(0)
pygame.display.flip()