こんにちは。
「Pythonでつくる ゲーム開発 入門講座」のChapter11,12(本格RPGを作ろう!全編・後編)を基にRPGを作っていきます。
前回は新しい戦闘コマンドから「こうげき」と「にげる」を選択できるようにしました。
今回は「ぼうぎょ」を選択できるようにします。
また、「こうげき」のダメージの計算方法を変えます。
ダメージに影響あるのは攻撃力のみですが、受ける側の防御力も考慮した計算に変更します。
目次
ぼうぎょ
元のコマンドには「ぼうぎょ」が無く、新しく追加したコマンドなので、
まず「ぼうぎょ」の概念についてです。

「ぼうぎょ」を選択すると、そのターンのみ自身の防御力を2倍にすることにします。
仲間がいないとあまり意味が無いコマンドですが、
そこは追い追い、できるかな・・?(;^_^A
何にしても変更して行きます。
最初に「chara.py」です。
class Brave():
def __init__(self):
self.name = chara1_name
self.lv = int(chara1_lv)
self.maxhp = int(chara1_maxhp)
self.hp = int(chara1_hp)
self.maxmp = int(chara1_maxmp)
self.mp = int(chara1_mp)
self.atk = int(chara1_atk)
self.dfs = int(chara1_dfs) # 防御力
def reset(self):
self.hp = self.maxhp
self.mp = self.maxmp
特に使っていませんでしたが、第3回でクラスを作った時に防御力の変数だけは
作っていましたので、これを使います。
このクラスの中にメソッドを作って、その中で防御力を2倍にします。
(追加)
def defense(self):
self.dfs *= 2 # 防御力2倍
def re_defense(self):
self.dfs = int(chara1_dfs) # 防御力を元に戻す
見たままですが、defenseメソッドで防御力を2倍にします。
コマンド「ぼうぎょ」の効果は1ターンのみの為、
防御力を元に戻す必要があります。
なので、re_defenseメソッドで元に戻します。
理由は後述しますが、1/2にして戻すのではなく、
最初の防御力を入れることで防御力を戻します。
これで防御力を2倍にする準備はできたので、次に「one_hour_dungeon.py」です。
def main(): # メイン処理
(省略)
elif idx == 11: # プレイヤーのターン(入力待ち)
(省略)
if COM[btl_cmd_y][btl_cmd_x] == "ぼうぎょ": # 追加
idx = 18
tmr = 0
if COM[btl_cmd_y][btl_cmd_x] == "にげる":
idx = 14
tmr = 0
# コマンドの位置のリセット
btl_cmd_x = 0
btl_cmd_y = 0
「ぼうぎょ」選択の判断は「こうげき」や「にげる」と同じように
if COM[btl_cmd_y][btl_cmd_x] == "ぼうぎょ":
です。
今回、新しく追加した「ぼうぎょ」は、idx = 18で処理します。
elif idx == 18: # ぼうぎょ
draw_battle(screen, fontS)
if tmr == 1:
player.defense() # 防御力2倍
set_message(player.name + "は みをまもっている。")
if tmr == 5:
idx = 13 # モンスターのターン(攻撃)
tmr = 0
「char.py」で作ったdefenseメソッドを使って2倍にして、
戦闘メッセージも表示させます。
これで「ぼうぎょ」を選択すると防御力が2倍になりますが、
ターンが終わると元に戻さないといけないので、
同じく「chara.py」で作ったre_defenseメソッドを以下に追加しました。
elif idx == 11: # プレイヤーのターン(入力待ち)
player.re_defense() # ぼうぎょを元に戻す(ぼうぎょ効果を消す)
draw_battle(screen, fontS)
if tmr == 1:
set_message(player.name + " のターン")
ターン開始の前ならモンスターの攻撃も終わっています。
また、これが先程少し述べた1/2にして戻すのではなく、
最初の防御力を入れることで防御力を戻した理由です。
1/2にして戻すと、戦闘が開始した時や「ぼうぎょ」していない時も
防御力が1/2になってしまいます。
なので、最初の防御力を入れることで防御力を元に戻します。
これなら戦闘開始時や「ぼうぎょ」していなくても影響ありません。

elif idx == 11: # プレイヤーのターン(入力待ち)
player.re_defense() # ぼうぎょを元に戻す
print(f"ターン開始時:{player.dfs}")
### 結果 → ターン開始時:10 ###
(省略)
elif idx == 18: # ぼうぎょ
draw_battle(screen, fontS)
if tmr == 1:
player.defense()
set_message(player.name + "は みをまもっている!")
print(f"ぼうぎょ時:{player.dfs}")
### 結果 → ぼうぎょ時:20 ###
こうげきのダメージ計算
「ぼうぎょ」を選択できるようになりました。
ただ、先程はサラッと記載しましたが、防御力の変数は今まで使っていませんでした。
つまり防御力が2倍になったところで、受けるダメージが半減するわけではありません。
それは攻撃のダメージ計算が以下のようになっている為です。
elif idx == 12: # プレイヤーの攻撃
draw_battle(screen, fontS)
if tmr == 1:
set_message(player.name + " の攻撃!")
# se[0].play()
dmg = player.atk + random.randint(0, 9) # ダメージ計算
dmg = player.atk + random.randint(0, 9)
→攻撃力 + ランダム(0〜9)
なので、防御力を考慮したダメージ計算に変更します。
ダメージ計算はこちらを利用させて頂きました。
基本ダメージ = (自分の攻撃力 - 相手の守備力 / 2) / 2
乱数幅 = 基本ダメージ/16 + 1
実ダメージ = 基本ダメージ ± 乱数幅内で生成された乱数
というわけで、これを計算する関数を「one_hour_dungeon.py」に作りました。
def battle_cal(obj1, obj2): # コマンドの入力と表示
base_dmg = obj1.atk/2 - obj2.dfs/4
if base_dmg <= 0: # 基本ダメージが0以下の(防御力の方が圧倒的に大きい)場合、ダメージは0か1
return random.randint(0, 1)
width_dmg = base_dmg/16 + 1
min_dmg = int(base_dmg - width_dmg) # 最小値
max_dmg = int(base_dmg + width_dmg) # 最大値
print(f"{min_dmg} 〜 {max_dmg}")
# 結果 攻撃力:1000,防御力:15の時 → 464 〜 528
return random.randint(min_dmg, max_dmg) # min_dmg〜max_dmgのランダム値
2つのオブジェクトを引数に持ちます。
obj1が攻撃する側、obj2が攻撃される側です。
戻り値をmin_dmg〜max_dmgの範囲のランダム値にして、
これをダメージとして取得します。
また、防御力の方が圧倒的に大きい場合のダメージは0か1にしました。
このbattle_cal関数をプレイヤーの攻撃時とモンスターの攻撃時に呼び出します。
elif idx == 12: # プレイヤーの攻撃
draw_battle(screen, fontS)
if tmr == 1:
set_message(player.name + " の攻撃!")
# se[0].play()
# dmg = player.atk + random.randint(0, 9) (削除)
dmg = battle_cal(player, monster) # 追加
(省略)
elif idx == 13: # モンスターのターン、攻撃
draw_battle(screen, fontS)
if tmr == 1:
set_message(monster.name + " のターン")
if tmr == 5:
set_message(monster.name + " の攻撃!")
# se[0].play()
emy_step = 30
if tmr == 9:
# dmg = monster.atk + random.randint(0, 9) (削除)
dmg = battle_cal(monster, player) # 追加
これで防御力も考慮した攻撃ができるようになりました。
モンスターの攻撃もオブジェクトを入れ替えるだけです。
なお、プレイヤーの防御力の変数は作っていましたが、
モンスター側は作っていなかったので、作っておきます。
(chara.py)
mon_atk = ws_mon.col_values(8) # H列
mon_dfs = ws_mon.col_values(9) # I列 追加(スプレッドシートのI列に防御力のステータスを追加)
class Monster():
def __init__(self, num):
self.img = pygame.image.load("image/enemy"+str(num)+".png")
self.name = mon_name[num]
self.maxhp = int(mon_maxhp[num])
self.hp = self.maxhp
self.atk = int(mon_atk[num])
self.dfs = int(mon_dfs[num]) # 追加
最後にもう1つ、ダメージが「0」の時はメッセージを変えます。
elif idx == 12: # プレイヤーの攻撃
draw_battle(screen, fontS)
if tmr == 1:
set_message(player.name + " の攻撃!")
# se[0].play()
dmg = battle_cal(player, monster)
if 2 <= tmr and tmr <= 4:
screen.blit(imgEffect[0], [600-tmr*100, tmr*100])
if tmr == 5:
emy_blink = 5
###追加###
if dmg > 0:
set_message(monster.name + "に " + str(dmg)+"ポイントの ダメージ!!")
else:
set_message("ミス!" + monster.name + "に ダメージを あたえられない!")
(省略)
elif idx == 13: # 敵のターン、敵の攻撃
draw_battle(screen, fontS)
if tmr == 1:
set_message(monster.name + " のターン")
if tmr == 5:
set_message(monster.name + " の攻撃!")
# se[0].play()
emy_step = 30
if tmr == 9:
dmg = battle_cal(monster, player)
###追加###
if dmg > 0:
set_message(player.name + "は " + str(dmg) + "ポイントの ダメージを うけた!")
else:
set_message("ミス!" + player.name + " は ダメージを うけない!")

という感じで、今回は以上です!(`・ω・´)
最後に
今回は「ぼうぎょ」コマンドを選択できるようにしたことと
それに伴い防御力を考慮したダメージ計算に変更しました。
次回はコマンドの選択はいったん置いておいて、
コマンド表示の時、その横にモンスターの名前を表示させようと思います。
【ご注意】
プログラムやデータなどは著作権法により保護されています。
著作者の許諾を得ずに、プログラムおよびデータそのものまたは改変したものを
配布したり販売したりすることはできません。
また、これらを利用して発生した損害などに関して、著作者は一切責任を負いません。