파이썬으로 게임 만들기 튜토리얼
코딩과 교육/파이썬 2017. 6. 4. 21:39Julian Meyer 라는 13세 소년이 만든 pygame 에 대한 튜토리얼이다. 이 게임은 기본적인 슈팅게임의 기본을 담고 있다. 방법을 익혀두면 다양하게 게임을 만들거나 응용이 가능하다. Beginning Game Programming for Teens with Python 이라는 이름으로 과정과 소스가 모두 인터넷에 공개되어 있다. 2.7 버젼으로 된 것을 최신 버젼인 3.6 버젼으로 수정했고, 일부 코드를 이해하기 쉽게 고쳤다.
STEP 0. 파이썬 & pygame 설치, 그래픽파일과 음악파일 준비
이 글은 윈도우 사용자를 위해 쓰였다. 리눅스나 맥은 가지고 있지 않은 관계로 설치해보질 못했으면 과정이 크게 다르지 않으리라는 것은 알지만 여기에 그 내용을 기록하지 않는다. 또한 원글과는 달리 최신 버젼인 파이썬 3.6 을 설치하여 사용하였다. 파이게임은 이글을 쓰는 당시에 있는 버젼인 1.9.3 을 설치하였다. 파이게임의 설치방법은
pip install pygame
으로 설치한다. 혹시 파이썬 설치방법을 모르는 사람은 다른 글을 통해 익히기 바란다.(가까운 시일내 파이썬 기본 강의를 올릴 예정이며 그때 파이썬 설치에 대해서 자세히 기록할 예정)
게임에 사용되는 배경음악과 그래픽 파일은 여기에서 다운로드하여 사용한다.
이후의 과정은 최대한 설명은 생략하고 소스 중심으로 방법만 기술한다.
STEP 1. 토끼 보이기
다음의 코드를 사용한다.
# 1 - Import library
import pygame
from pygame.locals import *
# 2 - Initialize the game
pygame.init()
width, height = 640, 480
screen=pygame.display.set_mode((width, height))
# 3 - Load images
player = pygame.image.load("resources/images/dude.png")
# 4 - keep looping through
while 1:
# 5 - clear the screen before drawing it again
screen.fill(0)
# 6 - draw the screen elements
screen.blit(player, (100,100))
# 7 - update the screen
pygame.display.flip()
# 8 - loop through the events
for event in pygame.event.get():
# check if the event is the X button
if event.type==pygame.QUIT:
# if it is quit the game
pygame.quit()
exit(0)
STEP 2. 장면추가하기
다음 내용을 #3의 마지막 부분에 넣는다.
grass = pygame.image.load("resources/images/grass.png")
castle = pygame.image.load("resources/images/castle.png")
다음 코드를 #6 의 처음 부분에 추가한다.
for x in range(int(width/grass.get_width()+1)):
for y in range(int(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 ))
STEP 3. 토끼전사가 움직이게 하기
#2 의 마지막 부분에 다음 코드를 넣는다.
keys = [False, False, False, False]
playerpos=[100,100]
#6 에서
screen.blit(player, (100,100))
을
screen.blit(player, playerpos)
if event.type == pygame.KEYDOWN:
if event.key==K_w:
keys[0]=True
elif event.key==K_a:
keys[1]=True
elif event.key==K_s:
keys[2]=True
elif event.key==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]:
playerpos[1]-=5
elif keys[2]:
playerpos[1]+=5
if keys[1]:
playerpos[0]-=5
elif keys[3]:
playerpos[0]+=5
여기까지 코드를 실행시켜보면 키보드로 WASD 를 누를때 고양이전사가 움직인다.
STEP 4. 고양이전사 방향전환하기
atan2() 라는 수학함수를 사용한다. atan2 함수는 math 라이브러리를 사용한다.
#1 의 끝 부분에 다음을 추가한다.
import math
# 6.1 - Set player position and rotation
position = pygame.mouse.get_pos()
angle = math.atan2(position[1]-(playerpos[1]+32),position[0]-(playerpos[0]+26))
playerrot = pygame.transform.rotate(player, 360-angle*57.29)
playerpos1 = (playerpos[0]-playerrot.get_rect().width/2, playerpos[1]-playerrot.get_rect().height/2)
screen.blit(playerrot, playerpos1)
STEP 5. 발사 !
#2 의 마지막 부분에 다음 코드를 추가한다.
acc=[0,0]
arrows=[]
#3 의 마지막 부분에 화살 이미지를 넣는 코드를 추가한다.
arrow = pygame.image.load("resources/images/bullet.png")
if event.type==pygame.MOUSEBUTTONDOWN:
position=pygame.mouse.get_pos()
acc[1]+=1
arrows.append([math.atan2(position[1]-(playerpos1[1]+32),position[0]-(playerpos1[0]+26)),playerpos1[0]+32,playerpos1[1]+32])
#6.1 바로 다음에 아래 코드를 추가한다.
# 6.2 - Draw arrows
for bullet in arrows:
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]))
STEP 6. 오소리 출현
#2 마지막 부분에 아래 코드 추가
badtimer=100
badtimer1=0
badguys=[[640,100]]
healthvalue=194
#3 마지막 부분에 다음 코드 추가
badguyimg1 = pygame.image.load("resources/images/badguy.png")
badguyimg=badguyimg1
#6.2 다음에 아래 코드 추가
# 6.3 - Draw badgers
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)
badguy[0]-=7
index+=1
for badguy in badguys:
screen.blit(badguyimg, badguy)
랜덤함수 사용을 위해서 다음 코드를 #1 의 끝 부분에 추가
import random
badtimer-=1
# 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
STEP 7. 오소리와 화살이 만날때
#6.3.1 아래에 다음 코드를 추가
#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
STEP 8. 체력바와 시간 나타내기
#7 의 시작전에 아래 코드를 추가
# 6.4 - Draw clock
font = pygame.font.Font(None, 24)
survivedtext = font.render(str(int(90000-pygame.time.get_ticks()))+":"+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)
#3 의 끝부분에 다음 코드를 추가
healthbar = pygame.image.load("resources/images/healthbar.png")
health = pygame.image.load("resources/images/health.png")
#6.4 다음에 아래 코드를 추가
# 6.5 - Draw health bar
screen.blit(healthbar, (5,5))
for health1 in range(healthvalue):
screen.blit(health, (health1+8,8))
STEP 9. WIN / LOSE
아래 코드를 마지막 부분에 추가
#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=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, (0,255,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()
#3 의 마지막 부분에 아래 코드를 추가
gameover = pygame.image.load("resources/images/gameover.png")
youwin = pygame.image.load("resources/images/youwin.png")
#4의 아래 내용을 수정한다.
[수정전]
# 4 - keep looping through
while 1:
badtimer-=1
[수정후]
# 4 - keep looping through
running = 1
exitcode = 0
while running:
badtimer-=1
STEP 10. 배경음악과 효과음악
#2 마지막 부분에 추가
pygame.mixer.init()
# 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)
#6.3.1 의 if badrect.left<64: 다음에 아래 코드 추가
# section 6.3.1 after if badrect.left<64:
hit.play()
#6.3.2 의 if badrect.colliderect(bullrect): 다음에 아래 코드 추가
# section 6.3.2 after if badrect.colliderect(bullrect):
enemy.play()
#8 의 if event.type==pygame.MOUSEBUTTONDOWN: 다음에 아래 코드 추가
# section 8, after if event.type==pygame.MOUSEBUTTONDOWN:
shoot.play()