강의자료/텍스트기반SW

[파이썬] 파이게임 객체 생성

원당컴1 2023. 7. 27. 09:35

지난 시간에 파이게임 사용법을 살펴 보았습니다.

https://wondangcom.tistory.com/2597

오늘은 파이게임에서 객체를 생성하고 키보드를 이용하여 이동하는 방법을 살펴 보도록 하겠습니다.

객체를 만들기 위한 이미지는 파이게임 튜토리얼(https://github.com/formazione/pygame_tutorial)에 있는 이미지를 사용하겠습니다.

이미지를 보면 각 행동에 대한 이미지가 여러개 있는 것을 확인 할 수 있습니다.

여기서 Dead 를 선택한다면 Dead(1) ~ Dead(15) 까지 적당한 시간을 두고 이미지를 변경 한다면 마치 쓰러지는 사람처럼 보일것입니다.

 

 

객체생성

1. 파이썬 객체 생성

- 플레이어를 관리할 수 있는 객체를 생성하고 객체를 이용해서 인스턴스를 만드는 방법을 살펴 보자.

  • 클래스 생성 : pygme의 sprite를 상속받아서 객체를 생성한다

class Player(pygame.sprite.Sprite):
    def __init__(self,location=(0, 0),imgsize=(100,100)):
        self.action = 'Idle' #최초 생성될때 상태
        self.index = 0
        self.imgsize=imgsize
        # if you use more istance with the same image
        # if MySprite.image is None
        self.list_surfaces = self.ordered_list_of_surfaces()
        self.image = self.list_surfaces[0]
        self.image = pygame.transform.scale(self.image,self.imgsize)
        self.rect = self.image.get_rect()
        self.rect.topleft = location

    def ordered_list_of_surfaces(self):
        self.los = [
            pygame.image.load(img)
            for img in glob.glob(f"png\\{self.action}*.png")
        ]
        return self.los

Player 의 최초 상태는 대기 상태로 생성을 한다.

ordered_list_of_surfaces 메서드를 이용해서 png 디렉토리에 있는 Idle*.png 이미지 파일을 모두 읽어서 리스트로 반환한다.

이미지를 읽어온 첫번째 이미지를 이용하여 생성한다.

 

클래스를 만들었다면 이 클래스를 이용하여 인스턴스를 생성해 보자.

  • 인스턴스 생성
player1 = Player()

이렇게 생성된 player1이 처음 대기 상태로 화면에 출력 되기 위해서는 앞에서 살펴 보았던 파이게임을 이용한 화면 출력이 필요하다.

 

2. 화면에 객체 띄우기

다음과 같이 화면에 출력하는 프로그램을 작성하자.

import pygame,sys,glob

#파이게임 초기화하기
pygame.init()

# 게임 화면 초기화 하기
screen = pygame.display.set_mode((1024,768))

#제목 표시줄 설정하기
pygame.display.set_caption("pygame test")

#프레임 매니저 초기화하기
clock = pygame.time.Clock()
#프레임 레이트 설정하기
clock.tick(60)

#배경색상 설정하기
screen.fill((255,255,255))

player1 = Player()

while True:
    screen.fill((255, 255, 255))
    screen.blit(player1.image, player1.rect)

    #이벤트 확인하기
    for event in pygame.event.get():
        #닫기 버튼을 눌렀는지
        if event.type == pygame.QUIT:
            #게임 끝내기
            pygame.quit()
            sys.exit()
    #화면 업데이트하기
    pygame.display.update()

    #프레임 레이트 설정하기
    clock.tick(60)

화면에 Idle 첫번째 이미지만 고정적으로 출력된다. 동적으로 움직이는 것처럼 만들어 보자.

클래스에 다음과 같이 메서드를 추가한다.

class Player(pygame.sprite.Sprite):
    ...
    def update(self):
        self.index += 0.2
        if self.index >= len(self.list_surfaces):
            self.index = 0
        self.image = self.list_surfaces[int(self.index)]
        self.image = pygame.transform.scale(self.image, self.imgsize) #이미지 크기변경

player의 update를 실행하면 5번 호출 될때 마다 다음 이미지로 이미지를 변경한다.

그 다음 파이게임이 호출되는 무한반복 안에서 update를 호출한다.

while True:
    screen.fill((255, 255, 255))
    player1.update() #추가
    screen.blit(player1.image, player1.rect)
    ...

쉬고 있는 이미지가 반복해서 출력 되는 것을 확인할 수 있다.

플레이어를 R 키를 눌렀을때는 Run 이미지로, J키를 눌렀을 때는 Jump, D 키를 눌렀을 때는 Dead, W키를 눌렀을 때는 Walk,I를 눌렀을 때 Idle 상태로 동작 상태를 변경하도록 하자.

클래스에 다음과 같이 action_change를 추가하자.

class Player(pygame.sprite.Sprite):
    ...
    def action_change(self,action):
        self.action =action
        self.index = 0
        # if you use more istance with the same image
        # if MySprite.image is None
        self.list_surfaces = self.ordered_list_of_surfaces()
        self.image = self.list_surfaces[0]
        self.image = pygame.transform.scale(self.image, self.imgsize) #이미지 크기 변경
        self.rect = self.image.get_rect()

action_change 에 action을 호출하면 이미지 리스트를 action에 맞는 이미지로 변경한다.

파이게임에서 호출되는 위치에서 이벤트를 입력 받아 각각의 키값에 따라 액션을 바꿔 보자.

while True:

    #이벤트 확인하기
    for event in pygame.event.get():
        #닫기 버튼을 눌렀는지
        if event.type == pygame.QUIT:
            #게임 끝내기
            pygame.quit()
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_r : #r키가 눌렸을때
                player1.action_change('Run')
            elif event.key == pygame.K_j : #j키가 눌렸을때
                player1.action_change('Jump')
            elif event.key == pygame.K_d : #d키가 눌렸을때
                player1.action_change('Dead')
            elif event.key == pygame.K_w : #d키가 눌렸을때
                player1.action_change('Walk')
            elif event.key == pygame.K_i : #i키가 눌렸을때
                player1.action_change('Idle')

    screen.fill((255, 255, 255))
    player1.update()
    screen.blit(player1.image, player1.rect)
    #화면 업데이트하기
    pygame.display.update()

    #프레임 레이트 설정하기
    clock.tick(60)

키보드가  눌렸는지를 판단해서 각각의 키값에 따라 action 값을 변경해 주면 해당 action에 맞는 이미지를 리스트에 로딩하기 때문에 아래와 같이 변경이 되는 것을 확인할 수 있다. 

이제 키값이 들어 왔을때 플레이어를 이동시켜 보자.

 

객체이동

1. 이동 방향에 따라 이미지를 반전시키자.

왼쪽 오른쪽 방향키에 따라 이동하고 이동하는 동안은 걷는 모양, 서 있을 때는 Idle 모양으로 변경 해 보자

단 왼쪽 방향키를 눌렀을때 이미지의 방향을 반전시켜야 한다. 반전시키기 위해 다음과 같이 프로그램을 수정하자.

class Player(pygame.sprite.Sprite):
    def __init__(self,location=(0, 0),imgsize=(100,100)):
        ...
        self.flipped = False #False 일때는 반전하지 않는다.
        ...
        self.list_surfaces = self.ordered_list_of_surfaces(self.flipped)
        ...

    def ordered_list_of_surfaces(self,flipped=False):
        if flipped :
            self.los = [
                pygame.transform.flip(pygame.image.load(img), True, False)
                for img in glob.glob(f"png\\{self.action}*.png")
            ]
        else :
            self.los = [
                pygame.image.load(img)
                for img in glob.glob(f"png\\{self.action}*.png")
            ]

        return self.los
    
    ...
    
    def action_change(self,action,flipped=False):
        ...
        self.list_surfaces = self.ordered_list_of_surfaces(flipped)
        ...

flipped= True 일때 이미지를 로딩할 때 반전 이미지를 로딩한다.

2. 방향키에 따라 이동하도록 만들자.

moveSpeed = 2
direct = False

while True:

    # 키보드 눌렀을때 True
    keys = pygame.key.get_pressed()

    # 왼쪽 화살표를 눌렀다면
    if keys[pygame.K_LEFT] and player1.rect.left - moveSpeed > 0:
        direct = True
        player1.move(-moveSpeed, 0)
        player1.action_change('Walk', direct)
    # 오른쪽 화살표를 눌렀다면
    elif keys[pygame.K_RIGHT] and player1.rect.right + moveSpeed < SCREEN_WIDTH:
        direct = False
        player1.move(moveSpeed, 0)
        player1.action_change('Walk', direct)
    else:
        #print(direct)
        player1.action_change('Idle', direct)

    #이벤트 확인하기
    for event in pygame.event.get():
        #닫기 버튼을 눌렀는지
        if event.type == pygame.QUIT:
            #게임 끝내기
            pygame.quit()
            sys.exit()

    screen.fill((255, 255, 255))
    player1.update() #다음 이미지로 처리 하기 위해 처리
    screen.blit(player1.image, player1.rect)
    #화면 업데이트하기
    pygame.display.update()

    #프레임 레이트 설정하기
    clock.tick(60)

moveSpeed 의 값을 설정하고 왼쪽 키를 눌렀을때 화면 밖으로 나가지 않는 동안 왼쪽으로 이동한다. 이때는 방향을 변경해 주기 위해 direct = True 로 변경해서 방향을 변경해서 이미지를 읽어 왔다.

이 때 키를 누르고 있으면 이미지가 다음 이미지로 이동하지 않고 처음이미지만 나오는 현상이 발생한다. 

또한 이동하지 않는다.

이것은 action_change를 호출 할 때마다 index가 0으로 설정 되기 때문이다.

이때 기존의 index를 유지하는 형태로 처리해 보자.

class Player(pygame.sprite.Sprite):
    ...
    def action_change(self,action,flipped=False):
        self.action =action
        #self.index = 0
        self.list_surfaces = self.ordered_list_of_surfaces(flipped)
        if self.index >= len(self.list_surfaces):
            self.index = 0
        self.image = self.list_surfaces[int(self.index)]
        self.image = pygame.transform.scale(self.image, self.imgsize)
        #self.rect = self.image.get_rect()

self.index = 0 을 주석 처리하고 새로 읽어온 이미지의 길이보다 더 크다면 0으로 변경 후에 해당 이미지를 처리했다.

self.rect 에 이미지의 get_rect()를 가져 오므로 move 를 해도 처음 위치로 되돌아 가기 때문에 self.rect 를 설정하는 부분을 주석 처리 했다.

이상으로 파이게임 객체를 생성해서 이동하는 것을 살펴 보았습니다.

다음시간에는 동물 객체를 만들어서 사람과 고양이가 서로 상속 받아서 움직이는 방법을 살펴 보도록 하겠습니다.

사업자 정보 표시펼치기/접기
원당컴퓨터학원 | 기희경 | 인천 서구 당하동 1028-2 장원프라자 502호 | 사업자 등록번호 : 301-96-83080 | TEL : 032-565-5497 | Mail : icon001@naver.com | 통신판매신고번호 : 호 | 사이버몰의 이용약관 바로가기