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

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

강의자료/텍스트기반SW

[파이썬] 파이게임 객체 임의의 위치로 이동하기

원당컴1 2023. 8. 17. 18:20

2023.08.10 - [강의자료/텍스트기반SW] - [파이썬] 파이게임 객체 상속

 

이전 시간에 만든 프로젝트에서 고양이는 임의의 위치로 계속 이동시키고 사람은 키보드로 이동하도록 변경을 해 봅니다.

 

고양이 임의의 위치로 이동

고양이를 임의의 위치로 계속 이동시키기 위해서는 일정시간마다 동서남북의 방향을 변경해 주고 계속 조금씩 이동하도록 하면 됩니다.

따라서 다음과 같이 Cat 클래스에 dirChange() 메서드를 생성하고 몇프레임마다 바꿀지 설정하는 changeFrame 변수를 init 에서 생성해 줍니다. 또한 자신이 몇프레임이나 호출 되었는지를 확인 할 수 있도록 frameCount 변수를 생성합니다.

전역 변수로 방향을 저장할 수 있는 dirList를 생성하여 W,E,N,S를 저장합니다.


dirList = ['W',"E","N","S"]

class Cat(Animal):
    def __init__(self,location=(0, 0),imgsize=(50,50),walkSpeed=3,jumpSpeed = 5,runSpeed = 7,changeFrame=60):
        ...
        self.changeFrame = changeFrame
        self.frameCount = 0
    
    def dirChange(self):
        self.frameCount += 1 #호출되는 횟수 카운트
        if self.frameCount > self.changeFrame :
            self.dir = random.choice(dirList)
            self.frameCount=0

    ....

다음으로 다음과 같이 고양이 객체를 각 프레임마다 이동 시키면서 dirChange를 호출하면 임의의 장소로 이동하는 것을 확인할 수 있습니다.

while True:
    ...
    cat.dirChange()
    cat.move()
    cat.update()
    screen.blit(person.image, person.rect)
    screen.blit(cat.image, cat.rect)
    ...

실행화면

 

실행해 보면 처음에 Idle 상태에서 action 상태로 변경 될때 이미지가 로딩 되지 않는 것을 확인 할 수 있었다.

다음과 같이 Cat과 Person 에 action 이 변경 될 때 이미지를 다시 로딩 하도록 다음과 같이 변경하자.

- Animal 의 클래스에서 action 변수를 _action 으로 변경 및 _preaction 추가

class Animal(pygame.sprite.Sprite):
    def __init__(self, location=(0, 0), imgsize=(100, 100), walkSpeed=1, jumpSpeed=2, runSpeed=5):
        self._action = 'Idle'
        self._preaction =''
        ...

- Person과 Cat 에서 다음과 같이 메서드 추가


class Person(Animal):
    ...
    def get_action(self): return self._action
    def set_action(self,action):
        self._action = action
        if self._preaction != self.action:
            if (self._preaction!=self.action): #action이 서로 달라지면 새로 로딩하자.
                self._preaction = self.action
                self.list_surfaces = self.ordered_list_of_surfaces()
                #print("action change")

    ...
    action = property(get_action, set_action)

class Cat(Animal):
    ...

    def get_action(self): return self._action
    def set_action(self,action):
        self._action = action
        if self._preaction != self.action:
            if (self._preaction!=self.action): #action이 서로 달라지면 새로 로딩하자.
                self._preaction = self.action
                self.list_surfaces = self.ordered_list_of_surfaces()
                #print("action change")
        
    ...
    action = property(get_action, set_action)

이렇게 하면 action이 변경 되면 해당 action에 맞춰서 이미지가 재 로딩 된다.

사람객체 키보드 이동

이번에는 사람 객체를 키보드로 이동하는 방법을 구현해 보자.

이 부분은 지난번( https://wondangcom.tistory.com/2604 )에 살펴 보았기 때문에 전체 코드 를 살펴 보는것으로 마친다.

현재 까지의 전체 코드

import random

import pygame,sys,glob


class Animal(pygame.sprite.Sprite):
    def __init__(self, location=(0, 0), imgsize=(100, 100), walkSpeed=1, jumpSpeed=2, runSpeed=5):
        self._preaction =''
        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_HEIGHT: 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)


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_action(self): return self._action
    def set_action(self,action):
        self._action = action
        if self._preaction != self.action:
            if (self._preaction!=self.action): #action이 서로 달라지면 새로 로딩하자.
                self._preaction = self.action
                self.list_surfaces = self.ordered_list_of_surfaces()
                #print("action change")

    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()

    def get_dir(self):
        return self._dir

    dir = property(get_dir, set_dir)
    action = property(get_action, set_action)

class Cat(Animal):
    def __init__(self,location=(0, 0),imgsize=(50,50),walkSpeed=3,jumpSpeed = 5,runSpeed = 7,changeFrame=30):
        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
        self.changeFrame = changeFrame
        self.frameCount = 0


    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 dirChange(self):
        self.frameCount += 1 #호출되는 횟수 카운트
        if self.frameCount > self.changeFrame :
            self.dir = random.choice(dirList)
            self.frameCount=0

    def get_action(self): return self._action
    def set_action(self,action):
        self._action = action
        if self._preaction != self.action:
            if (self._preaction!=self.action): #action이 서로 달라지면 새로 로딩하자.
                self._preaction = self.action
                self.list_surfaces = self.ordered_list_of_surfaces()
                #print("action change")

    def get_dir(self): return self._dir
    def set_dir(self,dir):
        self._dir = dir
        #print(self._predir,self.dir)
        if self._predir != self.dir:
            if (self._predir=='' or 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()
                print("dir change")


    dir = property(get_dir, set_dir)
    action = property(get_action, set_action)




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))
dirList = ['W',"E","N","S"]

while True:
    screen.fill((255, 255, 255))
    person.update()
    cat.action = "Walk"
    cat.dirChange()
    cat.move()
    cat.update()
    screen.blit(person.image, person.rect)
    screen.blit(cat.image, cat.rect)

    # 키보드 눌렀을때 True
    keys = pygame.key.get_pressed()
    # 왼쪽 화살표를 눌렀다면
    if keys[pygame.K_LEFT]:
        person.dir = "W"
        person.action = "Walk"
        person.move()
    # 오른쪽 화살표를 눌렀다면
    elif keys[pygame.K_RIGHT]:
        person.dir = "E"
        person.action = "Walk"
        person.move()
    # 위쪽 화살표를 눌렀다면
    elif keys[pygame.K_UP]:
        person.dir = "N"
        person.action = "Walk"
        person.move()
    # 아래쪽 화살표를 눌렀다면
    elif keys[pygame.K_DOWN]:
        person.dir = "S"
        person.action = "Walk"
        person.move()
    else:
        person.action = "Idle"

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

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

 

실행 화면

다음 시간에는 고양이를 여러마리를 임의의 위치에서 생성하여 임의의 위치로 이동하는 것을 만들어 보겠습니다.

 

 

 

 

 

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