project/project

미니 프로젝트3 : 파이썬으로 게임 만들어보기

JM Lee 2023. 3. 28. 01:50
728x90

새로운 과제 :  플레이어와 몬스터를 생성하여 1대 1으로 싸우는 상황을 파이썬으로 구현하기

 

목표는 파이썬 기초 문법에 익숙해지고, 파이썬 심화 문법을 자주 접해보기 이다.

 

요구 사항
기본 가이드

다음과 같은 기준을 잡고 우선적으로 게임을 만들어보기로 했다.

 

우선은 기본적인 역할에 충실하기 위해 어떤 방식으로 게임 코드를 만들어볼까 고민을 많이 했는데,

어떠한 방향으로 가든 잘 만들어지면 그만이라고 생각하고 만들어보고자 했다.

우선은 class로 기본 틀을 설정하고 그 다음 그 객체로 'Player'와 'Monster'을 설정했다.

그런데 player와 monster의 공통점이 상당히 많으므로,

class character를 따로 설정한 다음, class Player에는 마법 공격 함수만 넣어보았다.

 

그 결과,

class Character:
    """
    모든 캐릭터의 모체가 되는 클래스
    """
    def __init__(self, name, hp, mp, power, magic_power):
        self.name = name
        self.max_hp = hp
        self.hp = hp
        self.max_mp = mp
        self.mp = mp
        self.power = power
        self.magic_power = magic_power

    # 플레이어의 물리딜
    def attack(self, other):
        damage = random.randint(self.power - 2, self.power + 2)
        other.hp = max(other.hp - damage, 0)
        print(f"{self.name}의 공격! {other.name}에게 {damage}의 데미지를 입혔습니다.")
        if other.hp == 0:
            print(f"{other.name}이(가) 쓰러졌습니다.")

    # 몬스터의 물리딜
    def monster_attack(self, other):
        monster_damage = random.randint(self.power - 1, self.power + 3)
        other.hp = max(other.hp - monster_damage, 0)
        print(f"{other.name}의 공격! {self.name}에게 {monster_damage}의 데미지를 입혔습니다.")
        if self.hp == 0:
            print(f"{self.name}이(가) 쓰러졌습니다.")
    # 몬스터 함수이니까 몬스터 클래스에 넣어서 오버라이딩 해도 좋을것 같아요, 그러면 damage변수를 monster_damage로 새로 쓸 필요없이 그대로 damage로 써도 됩니다.
    # 또 self, other는 항상 함수가 속해있는 클래스 기준이기 때문에 다시 바꿔서 써주시면 될것 같습니다.

    #상태창(플레이어)
    def player_show_status(self):
        print(f"{self.name}의 상태: HP {self.hp}/{self.max_hp}")

    #상태창(몬스터)
    def monster_show_status(self):
        print(f"{self.name}의 상태: HP {self.hp}/{self.max_hp}")


class Player(Character):
    # 모체 캐릭터의 성능을 가진 자식 플레이어의 특성

    # 플레이어의 마법딜
    def magic_attack(self, other):
        magic_damage = random.randint(self.magic_power + 6, self.magic_power + 12)
        other.hp = max(other.hp - magic_damage, 0)
        self.mp = max(self.mp - 10, 0)
        print(f"{self.name}의 공격! {other.name}에게 {magic_damage}의 데미지를 입혔습니다.")
        if other.hp == 0:
            print(f"{other.name}이(가) 쓰러졌습니다.")
        
class Monster(Character):
    # 모체 캐릭터의 성능을 가진 자식 몬스터의 특성 ##
    def monster_attack(self, other):
        damage = random.randint(self.power - 1, self.power + 3)
        other.hp = max(other.hp - damage, 0)
        print(f"{self.name}의 공격! {other.name}에게 {damage}의 데미지를 입혔습니다.")
        if self.hp == 0:
            print(f"{other.name}이(가) 쓰러졌습니다.")

class 부분을 다음과 같이 설정했다.

Player와 Monster는 Character에서 기초 class를 가져온 다음 추가적인 객체의 특성을 정의함으로써

class 함수를 마쳤다.

 


전투창으로 들어갔다.

 

다음과 같은 필수 기능을 넣는 것에 집중했다.

 

1. 클래스 선정 후 바로 전투로 들어갈 것

2. 상대 공격 시 상대 HP 감소

3. 마법 공격 시 내 MP도 같이 감소

4. 몬스터는 물리딜만 가능

5. 둘 중 하나의 피가 0 이하가 되면 경기 종료

6. def show_status가 이루어져야 함

픽 다 했으면 바로 전투로 들어갈 것
전투에서 while 반복문에 따라 턴제공격 실시, = 해결
직업 이름이 왜 틀렸을까? = 해결 (Character_name.name 으로 인자를 추가하면 된다.)
턴제공격
     - 물리공격 or 마법공격 중 선택 = 해결
     - 선택하면 공격이 들어가면서 상대 체력 감소
     - 마법 공격 사용 시 내 mp도 같이 감소 = 해결
     - 몬스터는 물리딜만 가능 = 해결
     - 이 과정을 반복해서 둘 중 하나의 피가 0이 되면 경기 종료 = 해결
     - 내가 이길 시 "you win", 질 시 "you lose" 문구 print = 해결

필수 추가 사항
 1. 한 쪽이 죽으면 턴제와 게임이 종료되도록 해야 함 = 해결 (if 문에 break를 쓰면 해결됨.)
 2. def show_status가 이루어져야 함 = 해결 Character_name.player_show_status(), m1.monster_show_status()
 
 
print("플레이어의 이름을 입력하세요!!")
Player_name = input("Player name: ") 

# #각 캐릭터별 능력치 (name, hp, mp, power, magic_power)                  #아래에서 클래스를 지정해주기 때문에 주석처리했습니다!
# P1 = Player('Warrior', 100, 40, 15, 20)
# P2 = Player('Assassin', 70, 40, 25, 15)
# P3 = Player('Wizard', 80, 60, 10, 30)

m1 = Monster('Killer', 120, 0, 20, 0)                #몬스터는 그대로 변수에 넣었습니다! M1으로 해도 상관없으실것 같은데 저는 파란색뜨는게 거슬려서 바꿨습니다!

# 플레이어 1, 2, 3 중에 픽할 것
print('플레이어를 선택하시오')
print('1. Warrior')
print('2. Assassin')
print('3. Wizard')

# 번호값 input할 시 캐릭터 배정
Player_select = int(input('플레이어를 선택하시오. '))
if Player_select == 1:
    Character_name = Player('Warrior', 100, 40, 15, 20)
elif Player_select == 2:
    Character_name = Player('Assassin', 70, 40, 25, 15)
elif Player_select == 3:
    Character_name = Player('Wizard', 80, 60, 10, 30)
print(f'{Player_name} 님의 캐릭터는 {Character_name.name}입니다.')
                                                                # 여기서 바로 클래스를 지정해서 생성하면 좋을 것 같습니다.
                                                                # Character_name = Player('Warrior', 100, 40, 15, 20) 이런식으로 하시면
                                                                # 바로 클래스에서 인스턴스를 생성하면서 Character_name 변수에 넣을 수 있습니다.



# turn을 짝수 홀수로 하여 플레이어와 몬스터의 순번을 정함
turn = 1

# 플레이어 차례
print('fight!')
while True:
    if turn % 2 == 1:
        print('My turn!')
        print('몬스터에게 어떤 공격을 하시겠습니까?')
        player_action = int(input("1.일반공격 2.마법공격 ")) #int빠짐. player_action이라는 함수명이 위에 있어서 변수명으로 작동하지 않았음.
        if player_action == 1:
            Character_name.attack(m1) 
        elif player_action == 2:
            if Character_name.mp < 10:
                print('마나도 없는 게 공격을?')
            else:
                Character_name.magic_attack(m1)

        m1.monster_show_status()

        if m1.hp <= 0:
            print('Game over')
            print('You win!')
            break
        else:
            turn += 1

# 몬스터 차례
    elif turn % 2 == 0:
        print('Monster turn!')
        m1.monster_attack(Character_name)
        Character_name.player_show_status()
        if Character_name.hp <= 0:
            print('Game over')
            print('You lose..')
            break
        else:
            turn += 1

깨달은 점

 1. 파이썬 단독 파일은 처음 만들어서 터미널만으로 모든 과정을 진행하는 것에 적응

 2. 턴제를 멈추는 용어로는 break가 있다 (break 용어에 대해서는 내일 더 알아볼 예정)

 3. class <캐릭터>와 <몬스터, 플레이어>의 관계에 대해 이해, __init__ 함수에서 self가 가지는 역할

 4. class에서 정의와 호출이 가져다주는 의미

   - 호출 : 본래 class에서 현 class로 가져오는 것(5개를 호출했으면 5개만 와야 한다. 고로 호출 시에는 self를 뺄 것)

   - 정의 :  n = m 과 같이 m이 의미하는 것을 n에 대입하는 과정

 5. 함수를 가져다주는 인자가 하는 역할 이해

 


코드 개선사항

기본만 만들었기 때문에 추가적인 첨부가 필요

1. HP, MP 외 캐릭터의 능력치 추가 검토

2. 몬스터에게 확률적 회피 기능 검토

3. 가능하다면 몬스터 여러 마리 생성

4. 기타 등등..아이디어


노력할 점

 1. 개념을 이해만 하고 막상 적절한 타이밍에 적절하게 떠올리지 못한 점

 2. 적절한 코드 구상, 코드 투입이 머릿속에 잘 그려지지 않음

 3. 강의와 개인 공부할 때 좀 더 집중력이 필요함을 여실히 느낌

 4. 최대한 팀원, 매니저님, 튜터님 등 주변 분들께 질문해야 빠르게 도움이 될 수 있음