ターン制戦闘ゲームを作ろう
前回作ったゲームでは、プレイヤーとモンスターのダメージ判定を同時に行っていました。
今回はキャラクターの素早さによって、順番にダメージ判定を行うターン制の戦闘ゲームを作ります。
ゲームのルールは、以下のようになります。
なお、ダメージの計算方法は前回と同じです。
ルール
- ユーザー側がプレイヤー、コンピューター側がモンスターとなる
- ユーザー、コンピューターが同時に「攻撃」「防御」「魔法」のどれかを選択する
- 選んだ行動の組み合わせによって、ダメージの判定を行う
- キャラクターの素早さに乱数を掛けた値の順に行動する
- 先にHPが0になった方が負けとなる
前回は、同時にダメージ計算をしていたので相討ちがありましたが、今回は素早さに応じて順番にダメージを与えるので、先に行動するキャラクターが有利になります。
実行イメージ
実行イメージは、以下のようになります。
ユーザーはa(攻撃)、b(防御)、c(魔法)のどれかを入力します。
qを入力するとゲームは終了します。
実行例
> python game2.py
>>> 行動を選択してください
>>> a:攻撃 b:防御 c:魔法 q:終了
>>> a
++ プレイヤーは攻撃を実行! モンスターは1のダメージ
++ モンスターは防御を実行! プレイヤーは3のダメージ
:
:
>>> a
++ プレイヤーは攻撃を実行! モンスターは4のダメージ
++ モンスターを倒しました! ++
ダメージ判定マトリックス
ダメージ判定マトリックスは、以下のようになります。
たとえば、ユーザーが攻撃をしてコンピューターが魔法を使った場合、プレイヤーのHPが2、モンスターのHPが4減ります。
遊ぶときに、色々と変えてみると面白いでしょう。
ダメージ判定 | コンピューターの行動 | ||||||
攻撃 | 防御 | 魔法 | |||||
PのHP | MのHP | PのHP | MのHP | PのHP | MのHP | ||
ユーザーの行動 | 攻撃 | 3 | 3 | 3 | 1 | 2 | 4 |
防御 | 1 | 3 | 0 | 0 | 3 | 0 | |
魔法 | 4 | 2 | 0 | 3 | 1 | 1 |
メモ
PのHP:プレイヤーのHP
MのHP:モンスターのHP
Pythonスクリプト
ゲームのPythonスクリプトは、以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
### インポート import sys import random ### 行動パターン act_dic = {"a":"攻撃", "b":"防御", "c":"魔法"} ### ダメージマトリックス arr = ([[3,3],[3,1],[2,4]], # プレイヤー攻撃 [[1,3],[0,0],[3,0]], # プレイヤー防御 [[4,2],[0,3],[1,1]]) # プレイヤー魔法 ### HP初期値 play_hp = 20 mons_hp = 20 ### 素早さ play_agi = 8 mons_agi = 7 ### 関数定義 def battle(arg): ### ダメージマトリックスの配列 if arg == "プレイヤー": f_idx = 1 else: f_idx = 0 if play_act == "攻撃" and mons_act == "攻撃": f_damage = arr[0][0][f_idx] elif play_act == "攻撃" and mons_act == "防御": f_damage = arr[0][1][f_idx] elif play_act == "攻撃" and mons_act == "魔法": f_damage = arr[0][2][f_idx] elif play_act == "防御" and mons_act == "攻撃": f_damage = arr[1][0][f_idx] elif play_act == "防御" and mons_act == "防御": f_damage = arr[1][1][f_idx] elif play_act == "防御" and mons_act == "魔法": f_damage = arr[1][2][f_idx] elif play_act == "魔法" and mons_act == "攻撃": f_damage = arr[2][0][f_idx] elif play_act == "魔法" and mons_act == "防御": f_damage = arr[2][1][f_idx] elif play_act == "魔法" and mons_act == "魔法": f_damage = arr[2][2][f_idx] ### ダメージを返す return f_damage ### 戦闘が終了するまでループ while True: ### 行動入力 print(">>> 行動を選択してください") print(">>> a:攻撃 b:防御 c:魔法 q:終了") player = input(">>> ") ### 終了 if player == "q": break ### 入力エラー elif player not in list(act_dic.keys()): print("++ a:攻撃 b:防御 c:魔法 q:終了 を入力してください") print() continue ### 行動保存 play_act = act_dic[player] mons_act = act_dic[random.choice(list(act_dic.keys()))] ### 戦闘順決定 play_agi2 = play_agi * (1 + random.randrange(100) / 100) mons_agi2 = mons_agi * (1 + random.randrange(100) / 100) char_dic = {"プレイヤー":play_agi2, "モンスター":mons_agi2} ### 行動順設定 for character in sorted(char_dic.items(), key=lambda arg: arg[1], reverse=True): ### 行動判定 damage = battle(character[0]) ### 行動結果を表示 if character[0] == "プレイヤー": mons_hp -= damage mons_hp = max(0, mons_hp) print("++ プレイヤーは{}を実行! モンスターは{}のダメージ".format(play_act, damage)) else: play_hp -= damage play_hp = max(0, play_hp) print("++ モンスターは{}を実行! プレイヤーは{}のダメージ".format(mons_act, damage)) ### HP判定 if mons_hp == 0: print() print("++ モンスターを倒しました! ++") sys.exit() elif play_hp == 0: print() print("++ プレイヤーは倒されました... ++") sys.exit() ### 空行 print() |
スクリプト解説
2行目
exit()関数を使うので、sysライブラリーをインポートします。
3行目
random()関数を使うので、randomライブラリーをインポートします。
6行目
行動パターンの辞書を定義します。
aを入力したら「攻撃」、bを入力したら「防御」、cを入力したら「魔法」を実行します。
9行目~11行目
ダメージ判定マトリックスの値を3次元のリストで表しています。
14、15行目
プレイヤーとモンスターのHPを定義します。
それぞれ20を設定しています。
18、19行目
プレイヤーとモンスターの素早さを定義します。
プレイヤーが若干有利になるように、プレイヤーは8、モンスターは7を設定しています。
22~50行目
プレイヤーとモンスターの行動をif文で判定して、その行動に対応するダメージを戻り値として返す関数を定義します。
53行目
while文を使ってループ処理に入ります。条件にTrueを使っているので、無限ループとなります。
どちらかのキャラクターのHPが0になるとexit()関数を呼び出して、スクリプトが終了します。
また、行動選択で、qを入力するとwhileループが終了します。
58行目
input()関数を使って、プレイヤーの行動を入力します。
61行目
qが入力された場合は、break文によりwhileループを抜けてスクリプトが終了します。
65行目
key()メソッドを使ってact_dic辞書からキーを抜き出し、list()関数でリストに変換しています。
そのリストをnot in条件で、a、b、c以外が入力された場合は、continue文によりwhileループの先頭に戻ります。
71行目
ユーザーが入力したキー(a、b、c)を元に、act_dic辞書からキーに対応した値(攻撃、防御、魔法)をplay_act変数に代入します。
72行目
random.choice()関数によりact_dic辞書のキー(a、b、c)の中からランダムに取得して、その値(攻撃、防御、魔法)をmonst_act変数に代入します。
75、76行目
プレイヤーとモンスターの素早さの値に、1.00~1.99の範囲で掛け算します。
77行目
キーを「キャラクター」、値を「素早さ」にした辞書を定義します。
80行目
77行目で定義した辞書を素早さの高い順で並べ替えて、for文でループします。
character変数には、タプルに変換された要素([0]がキャラクター、[1]が素早さ)が代入されます。
83行目
キャラクターを引数としたbattle()関数を呼び出して、相手に与えたダメージを取得します。
86~93行目
if文によりキャラクターごとに、以下の処理を行います。
・対応するキャラクターのHPを、battle関数で取得したダメージで引き算する
・max()関数でHPの値がマイナスならば0にする
・対応するキャラクターの行動と残りのHPの値を表示する
96~103行目
どちらかのHPが0だった場合は、対応するメッセージを表示して、exit()関数でスクリプトを終了します。