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

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

강의자료/텍스트기반SW

[파이썬] 파이게임 객체 상속

원당컴1 2023. 8. 10. 09:42

2023.07.27 - [강의자료/텍스트기반SW] - [파이썬] 파이게임 객체 생성

지난 시간 Player의 객체를 생성해서 이동하는 것 까지 만들어 보았습니다.

이번 시간에는 고양이 객체를 생성해서 Player의 주변을 따라 다니도록 프로그램을 구현해 보겠습니다.

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

 

GitHub - formazione/pygame_tutorial

Contribute to formazione/pygame_tutorial development by creating an account on GitHub.

github.com

그런데 여기서 고양이와 Player의 속성이 많이 비슷한 것을 알 수 있습니다.

가령 Player도 Walk,Idle,Dead,Jump 등의 행동을 할 수 있고, 생명도 있습니다.

현재 구현하는 것에서 다른것은 그때 그때마다 서로 다른 이미지를 사용하는 것 밖에 없겠네요.

그렇다면 두개의 속성을 같이 갖는 Animal 이라는 객체를 생성하고 그 객체를 상속 받아서 Player 과 Cat 을 별도로 만들어 보는 프로그램을 만들어 보겠습니다.

 

Animal 객체생성

프로퍼티 정의

  • 상태 : Idle(가만히 있기),Walk(걷기),Jump(점프),Run(달리기),Dead(사망)
  • 이동속도 : walkSpeed,jumpSpeed,runSpeed
  • 현재방향 : East,Weast,North,South
  • 현재위치 : x,y
  • 객체크기 : size

일단 위의 정보를 이용하여 객체를 생성해 보자.


class Animal(pygame.sprite.Sprite):
    def __init__(self, location=(0, 0), imgsize=(100, 100), walkSpeed=1, jumpSpeed=2, runSpeed=5):
        self.action = 'Idle'
        self._predir = ''  # 방향이 변경 되면 방향에 맞게 이미지를 새로 로딩하자.
        self._dir = 'W'  # 기본으로 동쪽을 바라보도록 처리하자.
        self.index = 0
        self.size = imgsize
        self.location = location
        self.walkSpeed = walkSpeed
        self.jumpSpeed = jumpSpeed
        self.runSpeed = runSpeed
        self.list_surfaces = []  # 해당 객체의 이미지를 로딩해서 적재하는 리스트
        self.image = None  # 현재 이미지 적재 위치

    def get_walkSpeed(self): return self._walkSpeed
    def set_walkSpeed(self, speed):
        if speed < 0: return  # 음수 속도는 받을 수 없다.
        self._walkSpeed = speed

    def get_jumpSpeed(self): return self._jumpSpeed
    def set_jumpSpeed(self, speed):
        if speed < 0 : return #음수 속도는 받을 수 없다.
        self._jumpSpeed = speed

    def get_runSpeed(self): return self._runSpeed
    def set_runSpeed(self, speed):
        if speed < 0: return  # 음수 속도는 받을 수 없다.
        self._runSpeed = speed


    walkSpeed = property(get_walkSpeed, set_walkSpeed)
    jumpSpeed = property(get_jumpSpeed, set_jumpSpeed)
    runSpeed = property(get_runSpeed, set_runSpeed)

Animal 의 속성 정보를 프로퍼티로 사용하기 위해 위와 같이 각각의 속성을 프로퍼티로 정의 하였다.

프로퍼티로 정의 하면 animal.action = 'Walk' 와 같이 값을 대입하면 set_action 의 메서드를 사용하기 때문에 각각의 메서드에서 추가로 데이터의 오류를 보정할 수 있게 된다.

Animal 에 이미지의 동작을 표현할 수 있도록 update 메서드를 통해서 다음 이미지로 바꿀 수 있도록 만들어 보자.

    def update(self):
        if len(self.list_surfaces) == 0 :
            return #이미지가 적재 되기 전에는 빠져 나가자.

        self.index += 0.5
        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.size)

한 프레임이 동작할때마다 _index를 0.5 씩 증가 시켜서 두 프레임이 동작할 때 다음 이미지를 출력하도록 바꾸었다.

여기서 Animal에 움직일 수 있도록 move() 메서드를 생성한다. 이때 상태에 따라 해당 속도 만큼 이동시켜 주자.

    def move(self):
        if self.image == None: return

        speed = 0
        if self.action == 'Idle':
            speed = 0
        elif self.action == 'Walk':
            speed = self.walkSpeed
        elif self.action == 'Jump':
            speed = self.jumpSpeed
        elif self.action == 'Run':
            speed = self.runSpeed

        x = 0
        y = 0
        if self.dir == 'W':  # 서쪽 방향이면
            x = -speed
        elif self.dir == 'E':  # 동쪽이면
            x = speed
        elif self.dir == 'N':  # 북쪽이면
            y = -speed
        elif self.dir == 'S':  # 서쪽이면
            y = speed

        if self.rect.left + x < 0: return
        if self.rect.top + y < 0: return
        if self.rect.right + x > SCREEN_WIDTH: return
        if self.rect.bottom + y > SCREEN_HEIGH: return
        self.rect.move_ip(x, y)

현재 상태에 따라 속도를 정해 주고 방향에 따라 x,y 축에 속도만큼의 크기를 설정 후에 범위를 넘어 가지 않는다면 해당 위치로 이동시켜 주자.

Animal 객체 전체 코드

더보기
class Animal(pygame.sprite.Sprite):
    def __init__(self, location=(0, 0), imgsize=(100, 100), walkSpeed=1, jumpSpeed=2, runSpeed=5):
        self.action = 'Idle'
        self._predir = ''  # 방향이 변경 되면 방향에 맞게 이미지를 새로 로딩하자.
        self._dir = 'W'  # 기본으로 동쪽을 바라보도록 처리하자.
        self.index = 0
        self.size = imgsize
        self.location = location
        self.walkSpeed = walkSpeed
        self.jumpSpeed = jumpSpeed
        self.runSpeed = runSpeed
        self.list_surfaces = []  # 해당 객체의 이미지를 로딩해서 적재하는 리스트
        self.image = None  # 현재 이미지 적재 위치


    def update(self):
        if len(self.list_surfaces) == 0 :
            return #이미지가 적재 되기 전에는 빠져 나가자.

        self.index += 0.5
        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.size)

    def move(self):
        if self.image == None: return

        speed = 0
        if self.action == 'Idle':
            speed = 0
        elif self.action == 'Walk':
            speed = self.walkSpeed
        elif self.action == 'Jump':
            speed = self.jumpSpeed
        elif self.action == 'Run':
            speed = self.runSpeed

        x = 0
        y = 0
        if self.dir == 'W':  # 서쪽 방향이면
            x = -speed
        elif self.dir == 'E':  # 동쪽이면
            x = speed
        elif self.dir == 'N':  # 북쪽이면
            y = -speed
        elif self.dir == 'S':  # 서쪽이면
            y = speed

        if self.rect.left + x < 0: return
        if self.rect.top + y < 0: return
        if self.rect.right + x > SCREEN_WIDTH: return
        if self.rect.bottom + y > SCREEN_HEIGH: return
        self.rect.move_ip(x, y)



    def get_walkSpeed(self): return self._walkSpeed
    def set_walkSpeed(self, speed):
        if speed < 0: return  # 음수 속도는 받을 수 없다.
        self._walkSpeed = speed

    def get_jumpSpeed(self): return self._jumpSpeed
    def set_jumpSpeed(self, speed):
        if speed < 0 : return #음수 속도는 받을 수 없다.
        self._jumpSpeed = speed

    def get_runSpeed(self): return self._runSpeed
    def set_runSpeed(self, speed):
        if speed < 0: return  # 음수 속도는 받을 수 없다.
        self._runSpeed = speed


    walkSpeed = property(get_walkSpeed, set_walkSpeed)
    jumpSpeed = property(get_jumpSpeed, set_jumpSpeed)
    runSpeed = property(get_runSpeed, set_runSpeed)

 

Person 객체생성

Person객체는 Animal 객체를 상속 받아 놓은 후 이미지 디렉토리 중 사람에 해당하는 이미지 디렉토리의 이미지를 적재해 놓는다.

class Person(Animal):
    def __init__(self,location=(0, 0),imgsize=(100,100),walkSpeed=1,jumpSpeed = 2,runSpeed = 3):
        super().__init__(location,imgsize,walkSpeed,jumpSpeed,runSpeed) #상속정보를 설정해 주자.
        self.action = 'Idle'  # 최초 생성 될 때 상태
        self.flipped = True
        self.list_surfaces = self.ordered_list_of_surfaces()
        self.image = self.list_surfaces[0]
        self.image = pygame.transform.scale(self.image, self.size)
        self.rect = self.image.get_rect()
        self.rect.center = location


    def ordered_list_of_surfaces(self):
        if self.dir == 'W' : self.flipped=True
        elif self.dir == 'E' : self.flipped = False
        self.los =[]
        if self.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")
            ]
        print('image Loading')
        return self.los

    def get_dir(self): return self._dir
    def set_dir(self,dir):
        self._dir = dir
        if self._predir != self.dir:
            if (self._predir=='W' or self._predir=='E') and (self.dir=='W' or self.dir=='E'): #동,서로 변경이 되는 경우에 이미지를 다시 로딩하자.
                self._predir = self.dir
                self.list_surfaces = self.ordered_list_of_surfaces()


    dir = property(get_dir, set_dir)

ordered_list_of_surfaces 에서 동쪽과 서쪽에 한해서 이미지를 반전으로 로딩 할 것인지 아닌지 판단하고 또한 방향을 바꿀때(dir 변경시)  predir 에 동/서 만 기록한 다음 동/서의 방향이 바뀌는 경우에만 이미지를 다시 로딩하도록 처리하였다.

Person 이미지는 자신의 png 디렉토리에 있는 이미지를 로딩 하였다.

 

Cat 객체생성

Cat객체는 Person 객체와 동일한데 이미지 로딩 부분만 서로 다른 디렉토리에서 읽어 오도록 처리 했다.

class Cat(Animal):
    def __init__(self,location=(0, 0),imgsize=(50,50),walkSpeed=3,jumpSpeed = 5,runSpeed = 7):
        super().__init__(location,imgsize,walkSpeed,jumpSpeed,runSpeed) #상속정보를 설정해 주자.
        self.action = 'Idle'  # 최초 생성 될 때 상태
        self.flipped = True
        self.list_surfaces = self.ordered_list_of_surfaces()
        self.image = self.list_surfaces[0]
        self.image = pygame.transform.scale(self.image, self.size)
        self.rect = self.image.get_rect()
        self.rect.topleft = location


    def ordered_list_of_surfaces(self):
        if self.dir == 'W':self.flipped=True
        elif self.dir == 'E': self.flipped = False
        self.los =[]
        if self.flipped :
            self.los = [
                pygame.transform.flip(pygame.image.load(img), True, False)
                for img in glob.glob(f"cat\\{self.action}*.png")
            ]
        else :
            self.los = [
                pygame.image.load(img)
                for img in glob.glob(f"cat\\{self.action}*.png")
            ]
        print('image Loading')
        return self.los

    def get_dir(self): return self._dir
    def set_dir(self,dir):
        self._dir = dir
        if self._predir != self.dir:
            if (self._predir=='W' or self._predir=='E') and (self.dir=='W' or self.dir=='E'): #동,서로 변경이 되는 경우에 이미지를 다시 로딩하자.
                self._predir = self.dir
                self.list_surfaces = self.ordered_list_of_surfaces()


    dir = property(get_dir, set_dir)

이렇게 생성한 두개의 객체를 이용하여 사람과 동물을 화면에 띄워 보자.

 

Pygame 에서 두 객체의 인스턴스를 화면에 띄우기

SCREEN_WIDTH = 1024
SCREEN_HEIGHT = 768
#파이게임 초기화하기
pygame.init()

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

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

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

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



personX = SCREEN_WIDTH // 2 # 스크린 중앙 위치
personY = SCREEN_HEIGHT // 2

person = Person( (personX,personY) )
cat = Cat((personX - 100,personY))

while True:
    screen.fill((255, 255, 255))
    person.update()
    cat.update()
    screen.blit(person.image, person.rect)
    screen.blit(cat.image, cat.rect)

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

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

마지막으로 두 객체의 인스턴스를 pygame에 띄워 보았다.

객체가 생성하는 위치는 사람은 스크린의 중앙, 고양이는 사람의 왼쪽에서 100 떨어진 위치에 생성을 했다.

실행결과

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