2025년, 코딩은 선택이 아닌 필수!

2025년 모든 학교에서 코딩이 시작 됩니다. 먼저 준비하는 사람만이 기술을 선도해 갑니다~

강의자료/텍스트기반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 | 통신판매신고번호 : 호 | 사이버몰의 이용약관 바로가기