[INURoGue] 는 한때 인기였던 pokerogue 를 모티브로 만든 포켓몬 배틀 게임 입니다

image

LOLEX

Developer      고건우
Type    Pokemon battle game
Written in      Pygame(Python)
Languages     Korean(한국어)

Main System

1. 게임구성

시작 시 인트로가 나오고 시작을 누를시 바로 게임이 시작됩니다.
추후 다양한 모드와 배틀 외 컨텐츠를 위해 배틀만을 위한 게임이 아닌 전체적인 틀로 엔진을 만들었습니다.

2. Intro

게임 시작시 인트로와 함께 시작과 종료를 선택할 수 있습니다.

image

3. Battle System

핵심이 되는 배틀 시스템입니다.
각각의 포켓몬들을 다루기 쉽게 player_handler , pokemon_handler, 그리고 skill_handler 로 다뤘습니다.

image

전체적인 구성

image

class Battle:
    def __init__(self, game):

    def select_logic(self):

    def intro(self):

    def pokemon_draw(self):

    def battle_logic(self):
        if self.battle:
            self.back_draw()

            if self.intro:
                self.base_ui_draw()
                self.intro()
                
            else:
                self.pokemon_draw()
                self.status_draw()
                self.base_ui_draw()
                self.draw_hp()

                self.select_logic()        

    def back_draw(self):

    def base_ui_draw(self):

    def ui_1_draw(self):

    def ui_2_draw(self):

    def ui_3_draw(self):        

    def fight_draw(self):

    def init(self):

    def c_init(self):

    def ec_init(self):

    def player_change(self):
        
    def enemy_change(self):

    def status_draw(self):     

    def draw_hp(self):

    def draw_cursor(self):

    def update(self):
        self.battle_logic()

    

3. Pokemon

각각의 포켓몬들은 위에 말했듯 player_handler , pokemon_handler 로 다뤄집니다.
또한 포켓몬들은 각각의 레벨, 타입, 체력, 스킬들을 가지고 있습니다

class Pikachu(Pokemon):
    def __init__(self, game, pokemon = 'pikachu', path = 'asset/images/pokemon/pikachu/0.png', scale = 3.2, animation_time = 250):
        super().__init__(game=game, path=path, scale=scale, animation_time = animation_time)
        self.game = game
        self.x, self.y = 21.5,5
        self.image_size = 34,34

        self.pokemon = pokemon

        self.path = 'asset/images/pokemon/{}'.format(self.pokemon)
        self.pokemon_images = self.get_images(self.path)

        self.idle_image = self.img_update(self.pokemon_images, 1.5)

        self.type = 'electric'

        self.level = 50
        self.hp = 95
        self.max = 95

        self.skill = ['thunder', "crossthunder", 'ironhead']

4. Skill

마찬가지로 스킬들도 skill_handler로 관리가 됩니다. 하지만 포켓몬과 달리 적과 플레이어의 스킬을 같이 관리합니다.
각각의 스킬은 타입과 데미지를 갖고 있습니다.

class Thunder(Skill):
    def __init__(self, game, skill = 'thunder', path = 'asset/images/skill/thunder/0.png', scale = 7.0, animation_time = 200):
        super().__init__(game=game, path=path, scale=scale, animation_time = animation_time)
        self.game = game
        self.x, self.y = 5,11
        self.image_size = 34,34

        self.skill = skill

        self.path = 'asset/images/skill/{}'.format(self.skill)
        self.skill_images = self.get_images(self.path)

        self.idle_image = self.img_update(self.skill_images, 1.5)

        self.type = 'eletric'
        self.damage = 50

또한 skill들은 데미지를 입힐때 수식에 맞춰서 데미지를 입힙니다.

def cal_damage(skill, type1, type2):
    damage = skill.damage
    add = 'none'

    if type1 == 'ghost' :
        if type2 =='normal':
            damage= 0.5 * damage
            add = 'weak'
        else:
            add = 'none'

    if type1 == 'eletric':
        if type2 == 'air':
            damage= 2.0 * damage
            add = 'strong'

    if type1 == 'steel':
        if type2 == 'eletric':
            damage= 0.5 * damage
            add = 'weak'
        else:
            add = 'none'

    if type1 == 'ground':
        if type2 == 'eletric':
            damage= 2.0 * damage
            add = 'strong'
        else:
            add = 'none'

    return damage, add

5. Enemy

적 포켓몬은 짜여진 틀에 맞춰서 움직이지만, 더 유동적으로 작동시키기 위해 softmax를 이용해서 학습시킵니다.
배틀 할수록 더 데미지 효율에 맞춰서 스킬을 사용합니다

def skill_algorithm(self):
        state = self.get_state()

        enemy_skill_idx, probs = choose_skill(state)

        enemy_skill_name = self.pokemon.skill[enemy_skill_idx]
        enemy_skill_key = skill_dict[enemy_skill_name]
        enemy_skill = self.skill_handler.skill_list[enemy_skill_key]

        result = cal_damage(enemy_skill, enemy_skill.type, self.player.pokemon.type)

        reward = result[0]

        update_weights(state, enemy_skill_idx, reward, probs)

        self.dealt = True

        return enemy_skill_name, result

후기

처음에는 class와 함수를 잘 쪼개가면서 만들다가 후반에 시간없어서 battle logic을 길게 코딩한게 아쉬웠고 더 다양한 애니메이션과 기능을 추가하지 못한 것도 아쉽습니다.
하지만 이번 과제를 계기로 만들고 싶었던 걸 만드는 코딩을 해서 재밌었습니다.