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

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

강의자료/텍스트기반SW

[파이썬] 클래스별 파일로 관리하기

원당컴1 2023. 10. 13. 12:13

https://wondangcom.tistory.com/2623

지난 시간에 살펴 본 main.py 파일에 클래스를 모두 넣어 놓다 보면 소스코드의 덩어리가 커지면서 실행되는 메인 위치도 찾기 어렵고 클래스가 어디서 부터 어디까지인지 살펴 보기가 어려워 집니다.

클래스별로 각각의 파일로 관리하여 좀 더 관리가 편리하도록 변경을 해 보겠습니다.

먼저 다음과 같이 animal.py 파일을 만들어 Animal 클래스만 별도로 빼서 생성을 합니다.

- animal.py

import pygame

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)

이 때 SCREEN_WIDTH 와 같이 모든 곳에서 공통으로 사용하는 변수를 각각의 파일에서 선언해 준다면 나중에 값을 변경하게 되면 모든 파일을 찾아 다니면서 수정을 해 주어야 합니다.

이렇게 공통으로 사용하는 변수 값을 관리하는 공통 클래스를 하나 생성합니다.

다음과 같이 settings 파일에 객체를 하나 생성하겠습니다.

- settings.py

class Settings:
    def __init__(self):
        self.screen_width = 1024
        self.screen_height = 768
        self.bg_color = (255,255,255)
        self.dirList = ['W',"E","N","S"]

기본적으로 파이게임에 사용되는 설정 정보들을 Settings 라는 객체에 설정하여 필요한 경우 이 곳에서 값을 수정하면 모든 프로젝트에 적용되도록 변경을 해 보겠습니다.

먼저 animal.py 를 위의 Setting 값으로 수정을 합니다.

- animal.py

import pygame
from settings import Settings #settings 파일의 Settings 클래스를 import 

class Animal(pygame.sprite.Sprite):
    def __init__(self, location=(0, 0), imgsize=(100, 100), walkSpeed=1, jumpSpeed=2, runSpeed=5):
        ...
        self.settings = Settings() #setting 객체 생성


    def update(self):
        ...

    def move(self):
        ...
        #SCREEN_WIDTH 를 settings.screen_width 로 변경
        if self.rect.right + x > self.settings.screen_width: return
        if self.rect.bottom + y > self.settings.screen_height: return
        self.rect.move_ip(x, y)



    ...

다음으로 Person 클래스를 person.py 파일로 생성합니다.

- person.py

import random
import pygame,glob
from animal import 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_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)

파일로 만들어진 Animal 클래스를 사용하기 위해서 from animal import Animal 을 추가 했습니다.

 

다음으로 Cat 클래스를 cat.py 파일로 생성하겠습니다.

- cat.py

import random
import pygame,glob
from animal import Animal


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(self.settings.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)

 

마지막으로 Dog 클래스를 dog.py 다음과 같이 파일로 생성합니다.

- dog.py

import random
import pygame,glob
from animal import Animal


class Dog(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"dog\\{self.action}*.png")
            ]
        else :
            self.los = [
                pygame.image.load(img)
                for img in glob.glob(f"dog\\{self.action}*.png")
            ]
        #print('image Loading')
        return self.los

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

 

이렇게 객체 정보를 파일로 생성을 하면 main.py 에서 이 파일들을 참조 해서 객체를 생성하도록 변경하면 됩니다.

다음과 같이 main.py를 수정합니다.

- main.py

import random

import pygame,sys
from person import Person
from dog import Dog
from cat import Cat
from settings import Settings

settings = Settings() # 설정 정보

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

# 게임 화면 초기화 하기
screen = pygame.display.set_mode((settings.screen_width,settings.screen_height))

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

#프레임 매니저 초기화하기
clock = pygame.time.Clock()


personX = settings.screen_width // 2 # 스크린 중앙 위치
personY = settings.screen_height // 2

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

dogcatList = []
for i in range(5): #5번 동작하면서 dog/cat 을 생성하여 dogcatList에 append
    imsiX = random.randrange(100,settings.screen_width - 100)
    imsiY = random.randrange(100, settings.screen_height - 100)
    if i % 2 == 0: #0,2,4 에서 Cat
        dogcatList.append(Cat((imsiX,imsiY)))
    else: # 1,3 에서 Dog
        dogcatList.append(Dog((imsiX, imsiY)))

while True:
    screen.fill(settings.bg_color)
    person.update()
    '''
    cat.action = "Walk"
    cat.dirChange()
    cat.move()
    cat.update()
    '''
    screen.blit(person.image, person.rect)
    for catdog in dogcatList:
        catdog.action = "Walk"
        catdog.dirChange()
        catdog.move()
        catdog.update()
        screen.blit(catdog.image, catdog.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)

위와 같이 지금까지의 프로젝트를 파일로 나누어서 main.py 파일이 단순화 되었습니다.

파일 구조를 살펴 보면 다음과 같습니다.

만약에 우리가 고양이 클래스를 수정해야 한다면 cat.py 파일의 Cat 클래스를 수정하면 되므로 관리가 쉬워집니다.

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