본문 바로가기
Python/pygame

03-python 게임 만들기-키보드 입력하기

by To올라운더 2024. 2. 6.
반응형

이전 2개의 포스팅을 통해 게임 화면은 구성했고,

우리가 원하는대로 별주부를 움직여보는 코드를 구성할 예정이다.

 

이전 포스팅에서 while 문 안에 있는 pygame.event.get() 를 통해

키보드나 마우스의 움직임을 입력 받을 수 있다고 하였는데,

2024.02.03 - [Python/pygame] - python 게임만들기 - 기초 작업

 

python 게임만들기 - 기초 작업

앞선 포스팅에서 간략히 소개한 내용과 같이 python에는 게임을 만들기에 유용한 pygame 이라는 좋은 모듈이 있다. 그런데 아무리 좋은 모듈도 사용법을 모르면 쓸모가 없는 법. 하나씩 우리가 원하

to-all-rounder.tistory.com

 

 

while 문 안에 키보드 입력을 확인하는 코드를 추가해 보자.

 

1. 키보드 입력

 - 일반적으로 키보드 같은 버튼을 우리는 누른다고 생각한다.

    (나중에 추가 설명을 하겠지만, 누르는 것과 눌렀다가 떼는 것은 엄연히 다른 행동(event)이다.)

 - 그런 키보드를 누르는 이벤트를 확인하는 것이 오늘의 포스팅 목적이다.

 - 아래와 같이 for 반복문 으로 event.type 가 키보드를 누른 상태인지 확인을 하고,

    입력된 event.key 가 키보드의 위쪽 화살표 이면 별주부의 세로 위치 값(turtle_pos_y) 을 1 픽셀씩 감소한다.

 - 아래쪽 화살표도 동일하게 적용한 뒤, 변경된 사항을 pygame 화면(surface) 에 적용해 주기 위해 pygame.display.update() 를 진행해 주면 캐릭터가 움직이게 된다.

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_UP:
                turtle_pos_y -= 1

            if event.key == pygame.K_DOWN:
                turtle_pos_y += 1


    
    background.blit(turtle_img, (turtle_pos_x, turtle_pos_y))
    pygame.display.update()

 - 그런데 이렇게 입력하게 되면 생각지 못한 장애가 2가지 발생하는데, 

   1) 이동할 때 마다 배경이 뭉게진다는 것과

   2) 키보드를 누를 때에는 적용이 되는데, 화살표를 계속 누르고 있을 때 위치가 반영이 되지 않는 것이다.

   

 

 

2. 코드 수정하기

  - 위의 2가지 증상을 처리하기 위한 방법을 찾아보면

 

1) 계속 누르면 이동하기

 - 해당 증상은 생각보다 쉽게 수정할 수 있다.

 - 이동한 별주부의 위치를 반영하기 전 배경화면을 먼저 그려주면 된다.

 - 배경 이미지를 blit 해주는 한 줄의 코드 추가만으로 해당 내용은 처리되며,

   이동을 하더라도 검은 잔상과 같은 이미지가 남지 않게 된다.

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_UP:
                turtle_pos_y -= 1

            if event.key == pygame.K_DOWN:
                turtle_pos_y += 1



    # 화면 갱신 하기
    background.blit(background_img_resize,(0,0))    
    background.blit(turtle_img, (turtle_pos_x, turtle_pos_y))
    pygame.display.update()

  

2) 연속적으로 위치 이동하기

 - 키보드를 누르고 있을 때 계속 위치의 변화를 주기 위해 캐릭터의 위치 값에 event를 바로 적용시키는 대신

   이동과 관련된 새로운 변수를 선언한다.

running = True # 동작 상태
to_x = 0
to_y = 0

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_UP:
                to_y -= 1

            if event.key == pygame.K_DOWN:
                to_y += 1


        # 키보드에서 입력을 멈췄을 때
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_UP:
                to_y = 0

            if event.key == pygame.K_DOWN:
                to_y = 0

    # 캐릭터 이동
    turtle_pos_x += to_x
    turtle_pos_y += to_y

    # 화면 갱신 하기
    background.blit(background_img_resize,(0,0))    
    background.blit(turtle_img, (turtle_pos_x, turtle_pos_y))
    pygame.display.update()

 

 - 서두에 사람들이 키보드를 누른다고만 잘못 생각한다고 말한 부분이 있듯이

  실제는 키보드는 누르는 동작(KEYDOWN) 과 키보드를 떼는 동작(KEYUP)이 있다.

  (주황색 영역과 노란색 영역)

 

 - 이 두가지를 분리하여 키보드를 누를 때에는 가로 또는 세로로 이동을 할 to_x, to_y 변수 값을 변경하고,

   키보드에서 손을 떼게되면 to_y를 다시 0으로 초기화한다.(초록색 영역)

 

 - 해당 기능을 추가하면 이제 키보드를 누르고 있어도 자연스럽게 별주부가 연속으로 움직이는 것을 확인할 수 있는데,

   이제 가로로 이동할 수 있도록 K_LEFT와 K_RIGHT가 포함한 전체 코드를 작성해보면 아래와 같다.

 

3. 완성 코드 (+FPS 설정)

import pygame

pygame.init()

SCREEN_WIDTH = 1024
SCREEN_HEIGHT = 780

background = pygame.display.set_mode((SCREEN_WIDTH,SCREEN_HEIGHT))
pygame.display.set_caption('Exciting Pygame by ToAllrounder')


# 배경 화면 나타내기
background_img = pygame.image.load(r'image/sea_backgound.png')
#print(f'backgound_img.get_size() 값 : {background_img.get_size()}')
#print(f'backgound_img.get_rect() 값 : {background_img.get_rect()}')
background_img_resize = pygame.transform.scale(background_img,(SCREEN_WIDTH, SCREEN_HEIGHT))
background.blit(background_img_resize,(0,0))
# pygame.display.update() # 별주부 추가 후 update를 위해 생략


# 별주부 추가하기
turtle_img = pygame.image.load(r'image/rabbit_turtle.png')
#print(f'turtle_img.get_size() 값 : {turtle_img.get_size()}')
#print(f'turtle_img.get_rect() 값 : {turtle_img.get_rect()}')

turtle_pos_x = SCREEN_WIDTH / 2 - turtle_img.get_size()[0] / 2
turtle_pos_y = SCREEN_HEIGHT / 2 - turtle_img.get_size()[1] / 2

background.blit(turtle_img, (turtle_pos_x, turtle_pos_y))
# pygame.display.update() # 상어 추가 후 update를 위해 생략


# 상어 추가하기
shark_img = pygame.image.load(r'image/shark.png')
shark_pos_x = SCREEN_WIDTH  - shark_img.get_size()[0] / 4
shark_pos_y = SCREEN_HEIGHT / 4 - shark_img.get_size()[1] / 2

background.blit(shark_img, (shark_pos_x, shark_pos_y))

pygame.display.update()


running = True # 동작 상태
to_x = 0
to_y = 0

fps = pygame.time.Clock()


while running:
    set_fps = fps.tick(60)
    for event in pygame.event.get():

        if event.type == pygame.QUIT:
            running = False

        # 키보드에서 입력을 할 때
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP:
                to_y -= 1

            if event.key == pygame.K_DOWN:
                to_y += 1

            if event.key == pygame.K_LEFT:
                to_x -= 1

            if event.key == pygame.K_RIGHT:
                to_x += 1
            


        # 키보드에서 입력을 멈췄을 때
        if event.type == pygame.KEYUP:
            if event.key == pygame.K_UP:
                to_y = 0

            if event.key == pygame.K_DOWN:
                to_y = 0

            if event.key == pygame.K_LEFT:
                to_x = 0

            if event.key == pygame.K_RIGHT:
                to_x = 0


    # 캐릭터 이동
    turtle_pos_x += to_x * set_fps
    turtle_pos_y += to_y * set_fps

    # 화면 갱신 하기
    background.blit(background_img_resize,(0,0))    
    background.blit(turtle_img, (turtle_pos_x, turtle_pos_y))
    pygame.display.update()

pygame.quit()

 

 - 코드를 작성하고 난 뒤 조작을 해봤더니 정상적으로 움직이지만...조작에 대한 답답함이 있었다.

 - 그리고 추가로 fps 를 설정해주었는데, fps는 frame per second 의 약자로 1초당 몇개의 frame(화면)을 보여줄지를 설정하는 값이다.

 - 애니메이션이나 영화, 게임 등에서 자주 접해본 단어일텐데, 해당 값이 높을수록 더 자연스러운 움직임이 가능하다.

 - 우리는 pygame.time.Clock()를 통해 fps.tick(60) 을 설정하여 60 fps를 지정하고,

   해당 동작이 캐릭터의 움직임과 연동될 수 있도록 해당 값을 곱해주었다.

   (속도를 조절하는 기능 외에도 컴퓨터 간의 기본 fps가 다를 경우 게임의 속도가 차이날 수 있으나, fps.tick()을 고정함으로써 어떤 컴퓨터에서는 동일한 속도로 동작하게 되었다.)

 

 

반응형