이전 글에 이어서 작성하도록 하겠다.
이전 글은 아래에 첨부할테니,
혹시나 이전부터 참고하고자 한다면 이전 글을 참고해주길 바란다.\
[Python] pygame 모듈 / 파이썬 게임 배경 및 캐릭터 설정하기
그러면 이제는 이벤트를 설정할 것이다.
1. pygame 이벤트 설정하기
(1) 키보드의 키가 눌렸을 때 이벤트
우선 pygame의 키보드 이벤트 타입에는 무엇이 있는지 알아야 한다.
아래의 표로 남겨놓을 것인데, 이것 이외에 다른 이벤트 타입들이 있다.
여기서 pygame.KEYDOWN 키가 눌렸을 때의 이벤트를 작성할 것이다.
이벤트 타입 | 이벤트 동작 | 이벤트 속성 |
pygame.QUIT | 윈도우의 x 버튼, 창 닫기 버튼 눌림 | none |
pygame.ACTIVEEVENT | 마우스가 화면에 들어가거나 나가면 발생 gain : 0 - 마우스가 화면에 들어올때 gain : 1 - 마우스가 화면에서 나갔을 때 state : 1 - 창이 활성화 state : 2 - 창이 비활성화 state : 6 - 비활성화된 창이 활성화 될때 |
gain, state |
pygame.KEYDOWN | 키가 눌렸을 때 | key, mod, unicode, scancode |
pygame.KEYUP | 키가 올라갔을 때 | key, mod |
pygame.MOUSEMOTION | 마우스 움직일때 | pos, rel, buttons |
pygame.MOUSEBUTTONUP | 마우스 버튼 뗄 때 | pos, button |
pygame.MOUSEBUTTONDOWN | 마우스 버튼 눌렀을 때 | pos, button |
이벤트 루프에 if event.type == pygame.KEYDOWN: 을 추가해준다.
그리고 키가 눌렸을 때 어떤 키가 눌렸는 지를 조건문을 사용해서 표현을 해주는데,
pygame.K_LEFT 와 같이 방향키가 눌렸을 때 캐릭터의 이동을 설정해줄 것이다.
갑자기 pygame.K_LEFT 값이 나와서 당황했을텐데, 이는 공식 사이트에서 보도록 하자. 아래 링크를 달아두겠다.
#이벤트 루프
running = True #게임 진행 여부에 대한 변수 True : 게임 진행 중
while running:
for event in pygame.event.get(): #이벤트의 발생 여부에 따른 반복문
if event.type == pygame.QUIT: #창을 닫는 이벤트 발생했는가?
running = False
if event.type == pygame.KEYDOWN: #키보드의 키가 눌러졌을 경우
if event.key == pygame.K_LEFT: #왼쪽 방향키가 눌렸을 때
pass
elif event.key == pygame.K_RIGHT: #오른쪽 방향키가 눌렸을 때
pass
elif event.key == pygame.K_DOWN: #아래쪽 방향키가 눌렸을 때
pass
elif evnet.key == pygame.K_UP: #위쪽 방향키가 눌렸을 때
pass
screen.blit(background, (0, 0)) #배경에 이미지 그려주고 위치 지정
screen.blit(character, (character_x_pos - character_width / 2, character_y_pos - character_height)) #배경에 캐릭터 그려주기
pygame.display.update()
아래의 pygame 공식 사이트에 들어가게 되면,
pygame 모듈의 key 값들을 보여준다.
긁어서 오자면 아래와 같은 키 값들을 가진다.
Description을 보고 어떤 키 값을 가져오고 싶은 지 확인해보도록 하자.
pygame
Constant ASCII Description
---------------------------------
K_BACKSPACE \b backspace
K_TAB \t tab
K_CLEAR clear
K_RETURN \r return
K_PAUSE pause
K_ESCAPE ^[ escape
K_SPACE space
K_EXCLAIM ! exclaim
K_QUOTEDBL " quotedbl
K_HASH # hash
K_DOLLAR $ dollar
K_AMPERSAND & ampersand
K_QUOTE quote
K_LEFTPAREN ( left parenthesis
K_RIGHTPAREN ) right parenthesis
K_ASTERISK * asterisk
K_PLUS + plus sign
K_COMMA , comma
K_MINUS - minus sign
K_PERIOD . period
K_SLASH / forward slash
K_0 0 0
K_1 1 1
K_2 2 2
K_3 3 3
K_4 4 4
K_5 5 5
K_6 6 6
K_7 7 7
K_8 8 8
K_9 9 9
K_COLON : colon
K_SEMICOLON ; semicolon
K_LESS < less-than sign
K_EQUALS = equals sign
K_GREATER > greater-than sign
K_QUESTION ? question mark
K_AT @ at
K_LEFTBRACKET [ left bracket
K_BACKSLASH \ backslash
K_RIGHTBRACKET ] right bracket
K_CARET ^ caret
K_UNDERSCORE _ underscore
K_BACKQUOTE ` grave
K_a a a
K_b b b
K_c c c
K_d d d
K_e e e
K_f f f
K_g g g
K_h h h
K_i i i
K_j j j
K_k k k
K_l l l
K_m m m
K_n n n
K_o o o
K_p p p
K_q q q
K_r r r
K_s s s
K_t t t
K_u u u
K_v v v
K_w w w
K_x x x
K_y y y
K_z z z
K_DELETE delete
K_KP0 keypad 0
K_KP1 keypad 1
K_KP2 keypad 2
K_KP3 keypad 3
K_KP4 keypad 4
K_KP5 keypad 5
K_KP6 keypad 6
K_KP7 keypad 7
K_KP8 keypad 8
K_KP9 keypad 9
K_KP_PERIOD . keypad period
K_KP_DIVIDE / keypad divide
K_KP_MULTIPLY * keypad multiply
K_KP_MINUS - keypad minus
K_KP_PLUS + keypad plus
K_KP_ENTER \r keypad enter
K_KP_EQUALS = keypad equals
K_UP up arrow
K_DOWN down arrow
K_RIGHT right arrow
K_LEFT left arrow
K_INSERT insert
K_HOME home
K_END end
K_PAGEUP page up
K_PAGEDOWN page down
K_F1 F1
K_F2 F2
K_F3 F3
K_F4 F4
K_F5 F5
K_F6 F6
K_F7 F7
K_F8 F8
K_F9 F9
K_F10 F10
K_F11 F11
K_F12 F12
K_F13 F13
K_F14 F14
K_F15 F15
K_NUMLOCK numlock
K_CAPSLOCK capslock
K_SCROLLOCK scrollock
K_RSHIFT right shift
K_LSHIFT left shift
K_RCTRL right control
K_LCTRL left control
K_RALT right alt
K_LALT left alt
K_RMETA right meta
K_LMETA left meta
K_LSUPER left Windows key
K_RSUPER right Windows key
K_MODE mode shift
K_HELP help
K_PRINT print screen
K_SYSREQ sysrq
K_BREAK break
K_MENU menu
K_POWER power
K_EURO Euro
K_AC_BACK Android back button
(2) 키보드 방향키가 눌렸을 때 캐릭터 이동시키기
다시 돌아와서
해당 이벤트 루프 코드에서 pass 부분에 방향키를 눌렀을 때
캐릭터의 좌표이동을 설정해줄 것이다.
#이벤트 루프
running = True #게임 진행 여부에 대한 변수 True : 게임 진행 중
while running:
for event in pygame.event.get(): #이벤트의 발생 여부에 따른 반복문
if event.type == pygame.QUIT: #창을 닫는 이벤트 발생했는가?
running = False
if event.type == pygame.KEYDOWN: #키보드의 키가 눌러졌을 경우
if event.key == pygame.K_LEFT: #왼쪽 방향키가 눌렸을 때
pass
elif event.key == pygame.K_RIGHT: #오른쪽 방향키가 눌렸을 때
pass
elif event.key == pygame.K_DOWN: #아래쪽 방향키가 눌렸을 때
pass
elif evnet.key == pygame.K_UP: #위쪽 방향키가 눌렸을 때
pass
screen.blit(background, (0, 0)) #배경에 이미지 그려주고 위치 지정
screen.blit(character, (character_x_pos, character_y_pos)) #배경에 캐릭터 그려주기
pygame.display.update()
그럼 위의 코드에서
캐릭터 이동 좌표를 to_x, to_y 변수로 두고 키보드 방향키가 눌림에 따라
캐릭터의 좌표에서 빼거나 더해줄 것이다.
학교에서 수학시간에 배운 x, y좌표와는 다르다. 아래 사진을 참고하자
왼쪽 상단이 (0, 0)이며,
x좌표 기준으로 오른쪽은 +, 왼쪽은 -이고
y좌표 기준으로 위쪽은 -, 아래쪽은 +이다.
if event.key == pygame.K_LEFT:
to_x -= 0.5
코드를 보면 왼쪽 방향키가 눌렸을 때 x좌표를 -0.5 만큼 빼서 왼쪽으로 이동시켜주는 것이다.
그리고
if event.type == pygame.KEYUP 이란 조건문을 두어
사용자가 키보드에서 손을 뗐을 때, 캐릭터의 이동이 멈추어야 하므로
좌표 이동 변수 to_x, to_y를 0으로 설정해준다.
해당 좌표 이동 변수를 character_x_pos, character_y_pos에 더해줌으로써
캐릭터의 이동이 이루어지는 것이다.
#캐릭터 이동 좌표
to_x = 0
to_y = 0
#이벤트 루프
running = True #게임 진행 여부에 대한 변수 True : 게임 진행 중
while running:
for event in pygame.event.get(): #이벤트의 발생 여부에 따른 반복문
if event.type == pygame.QUIT: #창을 닫는 이벤트 발생했는가?
running = False
if event.type == pygame.KEYDOWN: #키보드의 키가 눌러졌을 경우
if event.key == pygame.K_LEFT: #왼쪽 방향키가 눌렸을 때
to_x -= 0.5
elif event.key == pygame.K_RIGHT: #오른쪽 방향키가 눌렸을 때
to_x += 0.5
elif event.key == pygame.K_DOWN: #아래쪽 방향키가 눌렸을 때
to_y += 0.5
elif event.key == pygame.K_UP: #위쪽 방향키가 눌렸을 때
to_y -= 0.5
if event.type == pygame.KEYUP: #방향키를 뗐을 때 캐릭터 멈춤
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
to_x = 0
elif event.key == pygame.K_UP or event.key == pygame.K_DOWN:
to_y = 0
character_x_pos += to_x
character_y_pos += to_y
그런데 위와 같이 코드를 작성하게 되면
캐릭터를 이동 시키다보면 화면 밖으로 나가게 된다.
이때 조건문을 설정해주어 캐릭터가 화면 밖으로 나가지 않도록 해주어야 한다.
해당 조건문을 이벤트 루프 안에 작성해주어야 한다.
캐릭터 좌표와 스크린 좌표 값을 비교하여, 해당 값을 벗어났을 때
캐릭터 좌표의 값을 그 값에 머물게 함으로써 넘어가지 못 하는 듯한 느낌을 준다.
#왼쪽, 오른쪽 경계 정하기
if character_x_pos < 0:
character_x_pos = 0
elif character_x_pos > screen_width - character_width:
character_x_pos = screen_width - character_width
#위, 아래쪽 경계 정하기
if character_y_pos < 0:
character_y_pos = 0
elif character_y_pos > screen_height - character_height:
character_y_pos = screen_height - character_height
경계선을 설정해주면 아래와 같이
캐릭터가 스크린 밖으로 넘어가지 않는 것을 확인할 수 있다.
2. FPS 설정하기
fps는 frame per second의 약자로 주사율, 즉 초당 몇 번의 이미지를 나타내어 주는 지에 대한 척도이다.
fps를 10으로 설정하면 초당 10번의 화면을 출력한다는 의미이다.
해당 값이 높을수록 화면에 부드럽게 출력이 되지만 CPU를 많이 사용하게 됨으로
주로 10, 30, 60을 주로 쓰니 너무 높은 fps 설정은 하지 않는 것이 좋다.
fps의 설정은 pygame.time.Clock() 을 변수에 넣고 해당 변수의 메소드로 .tick()을 사용한다.
clock.tick(60)으로 설정을 하게 되면 1초당 60프레임을 화면에 보여주는 것이다.
숫자가 커질수록 캐릭터의 모션이 부드럽게 출력이 된다.
#FPS 설정
clock = pygame.time.Clock()
#이벤트 루프
running = True #게임 진행 여부에 대한 변수 True : 게임 진행 중
while running:
dt = clock.tick(60) #초당 프레임 수 fps 설정
for event in pygame.event.get(): #이벤트의 발생 여부에 따른 반복문
if event.type == pygame.QUIT: #창을 닫는 이벤트 발생했는가?
running = False
#아랫 부분 생략..
그런데, 여기서 한가지 문제가 발생한다.
캐릭터의 속도를 조절하는 것이 아닌
프레임만을 조절했을 때 한 번 방향키를 클릭할 때의
캐릭터의 이동 거리가 달라지게 된다.
왼쪽 : clock.tick(60) / 오른쪽 : clock.tick(10)
캐릭터의 속도가 같아지게 해줘야 한다. 예를 한번 들어보자.
캐릭터가 1초 동안 100만큼 이동을 해야 하는데,
fps가 10일 때는 1초에 10번 동작을 하게 된다. 그렇다면 1번에 10만큼 이동을 해야 1초에 100만큼 이동할 수 있다.
fps가 50일 때는 1초에 50번 동작을 하게 된다. 그렇다면 1번에 2만큼 이동을 해야 1초에 100만큼 이동할 수 있다.
그렇다면 어떻게 해줘야 할까?
프레임이 달라졌을 때 캐릭터의 1번 클릭했을 때 이동 거리를 바꿔주면 된다.
-> 이렇게 해줘야 하는 이유는
컴퓨터가 프레임 수가 안 나올 때 캐릭터의 이동속도가 달라져 버리면 형평성이 떨어진다.
fps가 낮더라도 캐릭터의 이동 속도가 같아야 이동하는 거리가 같아진다.
아래와 같이 캐릭터가 이동하는 거리에 프레임 수를 곱해주면 된다.
그러면 캐릭터 프레임에 맞게 캐릭터가 이동속도를 가지게 된다.
60프레임에서는 to_x * 60
10프레임에서는 to_y * 10
프레임에 맞는 이동속도를 가지게 되어 같은 속도처럼 보인다.
character_x_pos += to_x * dt
character_y_pos += to_y * dt
아래를 참고하면
10fps는 조금 끊기는 감이 있긴 하지만 같은 속도로 움직이게 된다.
왼쪽 : clock.tick(60) / 오른쪽 : clock.tick(10)
아래는 전체 코드이다.
import pygame
pygame.init() #초기화
#화면 크기 설정
screen_width = 480 #가로 크기
screen_height = 640 #세로 크기
screen = pygame.display.set_mode((screen_width, screen_height))
#화면 타이틀 설정
pygame.display.set_caption("HwanE Game")
#FPS 설정
clock = pygame.time.Clock()
#배경 이미지 불러오기
background = pygame.image.load("C:/Users/A/Desktop/PythonWorkSpace/pygame_basic/background.png")
#캐릭터 불러오기
character = pygame.image.load("C:/Users/A/Desktop/PythonWorkSpace/pygame_basic/character.png")
character_size = character.get_rect().size #캐릭터 이미지 사이즈 구하기
character_width = character_size[0] #캐릭터 가로 크기
character_height = character_size[1] #캐릭터 세로 크기
#캐릭터의 기준 좌표를 캐릭터의 왼쪽 상단으로 둔다.
character_x_pos = (screen_width / 2) - (character_width / 2) #화면 가로 절반의 중간에 위치. 좌우로 움직이는 변수
character_y_pos = screen_height - character_height #이미지가 화면 세로의 가장 아래 위치
#캐릭터 이동 좌표
to_x = 0
to_y = 0
#캐릭터 이동 속도 변수
charcter_speed = 1
#이벤트 루프
running = True #게임 진행 여부에 대한 변수 True : 게임 진행 중
while running:
dt = clock.tick(10) #초당 프레임 수 fps 설정
for event in pygame.event.get(): #이벤트의 발생 여부에 따른 반복문
if event.type == pygame.QUIT: #창을 닫는 이벤트 발생했는가?
running = False
if event.type == pygame.KEYDOWN: #키보드의 키가 눌러졌을 경우
if event.key == pygame.K_LEFT: #왼쪽 방향키가 눌렸을 때
to_x -= charcter_speed
elif event.key == pygame.K_RIGHT: #오른쪽 방향키가 눌렸을 때
to_x += charcter_speed
elif event.key == pygame.K_DOWN: #아래쪽 방향키가 눌렸을 때
to_y += charcter_speed
elif event.key == pygame.K_UP: #위쪽 방향키가 눌렸을 때
to_y -= charcter_speed
if event.type == pygame.KEYUP: #방향키를 뗐을 때 캐릭터 멈춤
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
to_x = 0
elif event.key == pygame.K_UP or event.key == pygame.K_DOWN:
to_y = 0
character_x_pos += to_x * dt
character_y_pos += to_y * dt
#왼쪽, 오른쪽 경계 정하기
if character_x_pos < 0:
character_x_pos = 0
elif character_x_pos > screen_width - character_width:
character_x_pos = screen_width - character_width
#위, 아래쪽 경계 정하기
if character_y_pos < 0:
character_y_pos = 0
elif character_y_pos > screen_height - character_height:
character_y_pos = screen_height - character_height
screen.blit(background, (0, 0)) #배경에 이미지 그려주고 위치 지정
screen.blit(character, (character_x_pos, character_y_pos)) #배경에 캐릭터 그려주기
pygame.display.update()
#pygame 종료
pygame.quit()
댓글