[INURoGue] 는 한때 인기였던 pokerogue 를 모티브로 만든 포켓몬 배틀 게임 입니다
LOLEX
Developer 고건우
Type Pokemon battle game
Written in Pygame(Python)
Languages Korean(한국어)
Main System
1. 게임구성
시작 시 인트로가 나오고 시작을 누를시 바로 게임이 시작됩니다.
추후 다양한 모드와 배틀 외 컨텐츠를 위해 배틀만을 위한 게임이 아닌 전체적인 틀로 엔진을 만들었습니다.
2. Intro
게임 시작시 인트로와 함께 시작과 종료를 선택할 수 있습니다.
3. Battle System
핵심이 되는 배틀 시스템입니다.
각각의 포켓몬들을 다루기 쉽게 player_handler , pokemon_handler, 그리고 skill_handler 로 다뤘습니다.
전체적인 구성
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을 길게 코딩한게 아쉬웠고 더 다양한 애니메이션과 기능을 추가하지 못한 것도 아쉽습니다.
하지만 이번 과제를 계기로 만들고 싶었던 걸 만드는 코딩을 해서 재밌었습니다.