s_battle/proc_hero.py
主人公側の進行を管理するs_battle/proc_hero.py
モジュールです。かなりボリュームがあるので、全体を掲載したあと、部分を分割しながら説明します。
import pygame, data, hero, enemy, dialog, audio from random import randrange # 開始 def start(): action = data.menu_texts[data.menu_sel] # 選択行動取得 # 逃走 if action == "ESCAPE": # 選択行動が ESCAPE の場合 if randrange(2) == 0: # 1/2の確率 dialog.show("逃げるのに\n成功しました") # ダイアログ表示 data.scene_next = "map" # シーンをマップに else: dialog.show("逃げるのに\n失敗しました") # ダイアログ表示 data.proc = "enemy_start" # 進行を敵開始に return # 処理を打ち切る # 通常攻撃 at = randrange(hero.at // 2, hero.at) # 半分以上、1倍未満 # 魔法 if action == "MAGIC": # 選択行動が MAGIC の場合 if hero.mp == 0: # MPが0 dialog.show("MPが足りません") # ダイアログ表示 return # 処理を打ち切る at = randrange(hero.at * 2, hero.at * 4) # 2倍以上、4倍未満 hero.mp -= 1 # ダメージ適用 df = randrange(enemy.df) # 0以上、1倍未満 damage = max(1, at - df) # ダメージ(最小1) enemy.hp = max(0, enemy.hp - damage) # HP減少(HPの最低値は0) # 演出と進行 audio.damage.play() # ダメージSE再生 data.ef_enemy = True # 敵演出ありに data.ef_time_start = pygame.time.get_ticks() # 演出開始時間記録 data.proc = "hero_draw" # 進行を自描画に # 描画 def draw(): time = pygame.time.get_ticks() # ゲーム開始からの経過時間 if time >= data.ef_time_start + 500: # 500ミリ秒以上経過したか data.ef_enemy = False # 敵演出なしに end() # 終了 # 終了 def end(): data.proc = "enemy_start" # 進行を敵開始に if enemy.hp == 0: # HPが0か確認 if enemy.boss: # ラスボスか確認 # ラスボス時はエンディング audio.play(audio.ENDING) # エンディングのBGM再生 dialog.show(f"{enemy.name}を\n倒しました") # ダイアログ表示 dialog.show("あなたは王国を\n救いました") # ダイアログ表示 dialog.show("Congratulations!") # ダイアログ表示 data.scene_next = "title" # シーンをタイトルに else: audio.play(audio.WIN) # 勝利のBGM再生 dialog.show(f"{enemy.name}を\n倒しました") # ダイアログ表示 mes = f"経験値 {enemy.exp} 獲得" # 経験値獲得メッセージ if hero.add_exp(enemy.exp): # 経験値追加(レベルアップ判定) mes += f"\nレベル {hero.level} に上昇" # レベルアップ時メッセージ dialog.show(mes) # ダイアログ表示 data.scene_next = "map" # シーンをマップに
インポート部分ではpygame, data, hero, enemy, dialog, audio
を読み込みます。また、random
からrandrange
関数を読み込みます。random
をインポートしてrandom.randrange()
と書いてもよいのですが、プログラムのボリュームが大きいので、少しでも記述量を減らすために関数のみを読み込んでいます。
開始の冒頭
次は、開始をおこなうstart()
関数の冒頭部分です。
# 開始 def start(): action = data.menu_texts[data.menu_sel] # 選択行動取得 # 逃走 if action == "ESCAPE": # 選択行動が ESCAPE の場合 if randrange(2) == 0: # 1/2の確率 dialog.show("逃げるのに\n成功しました") # ダイアログ表示 data.scene_next = "map" # シーンをマップに else: dialog.show("逃げるのに\n失敗しました") # ダイアログ表示 data.proc = "enemy_start" # 進行を敵開始に return # 処理を打ち切る
選択したメニュー位置data.menu_sel
に当たるdata.menu_texts
のテキストを読み込み、変数action
に代入します。このaction
が選択した行動です。
action
の中身は"SWORD"
、"MAGIC"
、"ESCAPE"
のいずれかになります。
action
が"ESCAPE"
(逃走)のときは、1/2の確率で逃走に成功します。成功した場合はダイアログを表示して、マップ画面に移動します。失敗した場合はダイアログを表示して、進行を敵手番に移します。
攻撃とダメージの適用
次は攻撃とダメージの適用です。
# 通常攻撃 at = randrange(hero.at // 2, hero.at) # 半分以上、1倍未満 # 魔法 if action == "MAGIC": # 選択行動が MAGIC の場合 if hero.mp == 0: # MPが0 dialog.show("MPが足りません") # ダイアログ表示 return # 処理を打ち切る at = randrange(hero.at * 2, hero.at * 4) # 2倍以上、4倍未満 hero.mp -= 1 # ダメージ適用 df = randrange(enemy.df) # 0以上、1倍未満 damage = max(1, at - df) # ダメージ(最小1) enemy.hp = max(0, enemy.hp - damage) # HP減少(HPの最低値は0)
まず、通常攻撃("SWORD"
)の攻撃力at
を求めます。ランダムな数値で、主人公の攻撃力の半分以上、1倍未満です。
次にaction
が"MAGIC"
だった場合は、MPが足りるか確認します。足りないときはダイアログを表示して処理を打ち切ります。
足りる場合は、攻撃力at
を魔法の攻撃力に変更して、mp
を1減らします。魔法の攻撃力は、ランダムな数値で、主人公の攻撃力の2倍以上、4倍未満です。
敵の防御力df
を求めます。0以上、敵の防御力未満です。
求めた攻撃力から防御力を引いて、ダメージを計算します。その際、1
未満にならないように、引数のうち最大の値を返すmax()
関数を利用します。
最後に敵のhp
を減らします。こちらもmax()
関数を利用して、0
未満にならないようにします。
演出と進行、描画
次は演出と進行、描画です。
# 演出と進行 audio.damage.play() # ダメージSE再生 data.ef_enemy = True # 敵演出ありに data.ef_time_start = pygame.time.get_ticks() # 演出開始時間記録 data.proc = "hero_draw" # 進行を自描画に # 描画 def draw(): time = pygame.time.get_ticks() # ゲーム開始からの経過時間 if time >= data.ef_time_start + 500: # 500ミリ秒以上経過したか data.ef_enemy = False # 敵演出なしに end() # 終了
ダメージのSEを再生して、data.ef_enemy
をTrue
にして敵の演出を有効にします。また、data.ef_time_start
にゲーム開始からの経過時間を代入します。
最後に、進行data.proc
を、主人公の描画の"hero_draw"
にします。
描画を管理するdraw()
関数では、500
ミリ秒経過したら描画を終了します。その際、data.ef_enemy
をFalse
にして敵の演出を止めます。そしてend()
関数を実行します。
終了処理
最後は終了をおこなうend()
関数です。
# 終了 def end(): data.proc = "enemy_start" # 進行を敵開始に if enemy.hp == 0: # HPが0か確認 if enemy.boss: # ラスボスか確認 # ラスボス時はエンディング audio.play(audio.ENDING) # エンディングのBGM再生 dialog.show(f"{enemy.name}を\n倒しました") # ダイアログ表示 dialog.show("あなたは王国を\n救いました") # ダイアログ表示 dialog.show("Congratulations!") # ダイアログ表示 data.scene_next = "title" # シーンをタイトルに else: audio.play(audio.WIN) # 勝利のBGM再生 dialog.show(f"{enemy.name}を\n倒しました") # ダイアログ表示 mes = f"経験値 {enemy.exp} 獲得" # 経験値獲得メッセージ if hero.add_exp(enemy.exp): # 経験値追加(レベルアップ判定) mes += f"\nレベル {hero.level} に上昇" # レベルアップ時メッセージ dialog.show(mes) # ダイアログ表示 data.scene_next = "map" # シーンをマップに
進行data.proc
を敵開始"enemy_start"
にしたあと、敵のhp
が0
なら勝利の処理をおこないます。
勝利の処理は、ラスボスか通常戦闘かで異なります。まずは、それぞれBGMを再生してダイアログを表示します。
ラスボスのときは、ダイアログを表示したあとタイトル画面に移ります。通常戦闘のときは、経験値を獲得してマップ画面に移ります。
s_battle/proc_enemy.py
敵側の進行を管理するs_battle/proc_enemy.py
モジュールです。主人公側と関数の構成は同じですが、主人公側に比べてボリュームは少ないです。
import pygame, data, hero, enemy, dialog, audio from random import randrange # 開始 def start(): # 攻撃 at = randrange(enemy.at // 2, enemy.at) # 半分以上、1倍未満 df = randrange(hero.df) # 0以上、1倍未満 damage = max(1, at - df) # ダメージ(最小1) hero.hp = max(0, hero.hp - damage) # HP減少(HPの最低値は0) # 演出と進行 audio.damage.play() # ダメージSE再生 data.ef_hero = True # 自演出ありに data.ef_time_start = pygame.time.get_ticks() # 演出開始時間記録 data.proc = "enemy_draw" # 進行を敵描画に # 描画 def draw(): time = pygame.time.get_ticks() # ゲーム開始からの経過時間 if time >= data.ef_time_start + 500: # 500ミリ秒以上経過したか data.ef_hero = False # 自演出なしに end() # 終了 # 終了 def end(): data.proc = "menu" # 進行をメニューに if hero.hp == 0: # HPが0か確認 audio.play(audio.LOSE) # 敗北のBGM再生 dialog.show("あなたは死にました\nそして復活しました") # ダイアログ表示 mes = "経験値 20 獲得" # 経験値獲得メッセージ if hero.add_exp(20): # 経験値追加(レベルアップ判定) mes += f"\nレベル {hero.level} に上昇" # レベルアップ時メッセージ dialog.show(mes) # ダイアログ表示 # スタート位置に移動して回復 hero.x = hero.next_x = hero.start_x # X位置、次回X位置を開始X位置に hero.y = hero.next_y = hero.start_y # Y位置、次回Y位置を開始Y位置に hero.hp = hero.hp_max # HP回復 hero.mp = hero.mp_max # MP回復 data.scene_next = "map" # シーンをマップに
インポート部分、描画を管理するdraw()
関数は主人公側と同じです。開始のstart()
関数は、逃走と魔法がないので短くなっています。説明が必要なのは、終了のend()
関数だけです。
end()
関数では、進行data.proc
をメニュー"menu"
にしたあと、主人公のhp
が0
なら敗北の処理をおこないます。
敗北時は、経験値が20
固定で入り、ダイアログを表示します。そして、開始位置に移動して、hp
とmp
を最大値まで回復します。
最後に、マップ画面に移動してバトルを抜けます。