パラメーターを使った戦闘ゲームを作ろう
前回はキャラクターの行動に対応するマトリックスからダメージ値を決定していました。
今回はキャラクターに攻撃力や防御力といったパラメーターを設定して、その値によってダメージ値を計算する戦闘ゲームを作ります。
ゲームのルールは、以下のようになります。
ルール
- ユーザー側がプレイヤー、コンピューター側がモンスターとなる
- ユーザー、コンピューターが同時に「攻撃」「防御」「魔法」のどれかを選択する
- コンピューターの行動はランダムだが、行動に重みをつける
- キャラクターの素早さに乱数を掛けた値の順に行動する
- キャラクターの行動とパラメーターによってダメージ値を計算する
- 先にHPが0になった方が負けとなる
実行イメージ
実行イメージは、以下のようになります。
ユーザーはa(攻撃)、b(防御)、c(魔法)のどれかを入力します。
qを入力するとゲームは終了します。
実行例
> python game3.py
>>> 行動を選択してください
>>> a:攻撃 b:防御 c:魔法 q:終了
>>> a
++ プレイヤーは攻撃を実行! モンスターは3のダメージ
++ モンスターは攻撃を実行! プレイヤーは6のダメージ
:
:
>>> c
++ モンスターは攻撃を実行! プレイヤーは4のダメージ
++ プレイヤーは魔法を実行! モンスターは11のダメージ
++ モンスターを倒しました!!!!! ++
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 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
### インポート import sys import random ### 行動パターン act_dic = {"a":"攻撃", "b":"防御", "c":"魔法"} ### キャラクターパラメーター ### 名前,HP,攻撃力,防御力,魔力,素早さ play_lst = ["プレイヤー", 20, 6, 6, 6, 6] mons_lst = ["モンスター", 20, 9, 6, 4, 5] ### クラス定義 ### class Charpram: ### 初期化メソッド def __init__(self, name, hitp, atck, dfns, magc, agil): ### パラメーター self.name = name # 名前 self.hitp = hitp # HP self.atck = atck # 攻撃力 self.dfns = dfns # 防御力 self.magc = magc # 魔力 self.agil = agil # 素早さ self.actn = None # 行動 self.stat = None # 状態 ### ダメージ計算メソッド def cal_damage(self): ### ローカル変数 f_damage = 0 ### 行動分岐 if self.actn == "攻撃": f_damage = round(self.atck * (1 + random.randrange(100) / 100)) elif self.actn == "防御": f_damage = 0 elif self.actn == "魔法": f_damage = round(self.magc * (1 + random.randrange(100) / 100)) return f_damage ### 素早さ補正メソッド def cal_agil(self): ### ローカル変数 f_agil = 0 ### 行動分岐 if self.actn == "攻撃": f_agil = self.agil * (1 + random.randrange(100) / 100) elif self.actn == "防御": f_agil = self.agil * 1.5 * (1 + random.randrange(100) / 100) elif self.actn == "魔法": f_agil = self.agil * 0.5 * (1 + random.randrange(100) / 100) return f_agil ### 関数定義 ### def battle(arg1, arg2): ### ローカル変数 f_damage = 0 ### 攻撃 if arg1.stat == "攻撃": ### 相手が防御 if arg2.stat == "防御": dfns = arg2.dfns * 2 else: dfns = arg2.dfns ### ダメージ計算 f_damage = max(0, arg1.cal_damage() - dfns) arg2.hitp -= f_damage arg2.hitp = max(0, arg2.hitp) ### 防御 elif arg1.stat == "防御": ### ダメージ0 f_damage = 0 ### 魔法 elif arg1.stat == "魔法": ### ダメージ計算 f_damage = max(0, arg1.cal_damage()) arg2.hitp -= f_damage arg2.hitp = max(0, arg2.hitp) ### メッセージ表示 print("++ {}は{}を実行! {}は{}のダメージ".format(arg1.name, arg1.actn, arg2.name, f_damage)) ### インスタンス生成 play = Charpram(*play_lst) mons = Charpram(*mons_lst) ### 戦闘が終了するまでループ 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.actn = act_dic[player] play.stat = "待機" mons.actn = act_dic[random.choices(list(act_dic.keys()),weights=[8,1,1])[0]] mons.stat = "待機" ### 素早さ補正 play_agil = play.cal_agil() mons_agil = mons.cal_agil() ### 行動順辞書設定 char_dic = {play.name:play_agil, mons.name:mons_agil} ### 行動 for character in sorted(char_dic.items(), key=lambda arg: arg[1], reverse=True): ### プレイヤー行動 if character[0] == play.name: play.stat = play.actn battle(play, mons) ### モンスター行動 else: mons.stat = mons.actn battle(mons, play) ### 残HP判定 if mons.hitp == 0: print() print("++ {}を倒しました!!!!! ++".format(mons.name)) sys.exit() elif play.hitp == 0: print() print("++ {}は倒されました... ++".format(play.name)) sys.exit() ### 空行 print() |
スクリプト解説
2行目
exit()関数を使うので、sysライブラリーをインポートします。
3行目
random()関数を使うので、randomライブラリーをインポートします。
6行目
行動パターンの辞書を定義します。
aを入力したら「攻撃」、bを入力したら「防御」、cを入力したら「魔法」を実行します。
9、10行目
キャラクターのパラメーターをリストで設定します。
パラメーターの意味は、順に名前、HP、攻撃力、防御力、魔力、素早さです。
14~59行目
キャラクターに関するクラスを定義します。
このクラスは、キャラクターのパラメーターを設定して、ダメージ計算と素早さの補正を行います。
17~27行目
初期化メソッドを定義しています。
引数からキャラクターのパラメーターを受け取り、変数に代入します。
self.actnはキャラクターの「行動」、self.statはキャラクターの「状態」を表します。
self.actnはキャラクターの行動が決まった時に、攻撃、防御、魔法のどれかが代入されますが、self.statは実際に行動する時に攻撃、防御、魔法が代入されます。
それまでは「待機」という文言が代入されます。
初期値で代入している「None」は、値がまだ存在しないというPythonの定数です。
30~43行目
キャラクターが敵に与えるダメージ値を計算するメソッドです。
攻撃はキャラクターの攻撃力に1.00~1.99を掛けた値を返します。
防御は敵にダメージを与えないので0を返します。
魔法はキャラクターの魔力に1.00~1.99を掛けた値を返します。
なお、攻撃と魔法のダメージ値は、round()関数で小数点以下を四捨五入します。
46~59行目
キャラクターの素早さを補正するメソッドです。
ダメージ計算メソッドと同じように乱数を掛けて、さらに素早さが攻撃の場合は1倍、防御の場合は1.5倍、魔法の場合は0.5倍になるようにします。
防御は素早く行動することができますが、魔法は行動するのに時間がかかるということになります。
62~96行目
戦闘を行う関数を定義します。
引数のarg1は行動を実行するキャラクター、arg2は行動を受けるキャラクターです。
68~79行目
このif文は、行動するキャラクターの状態が攻撃の場合の処理です。
相手の状態が防御の場合は、相手の防御力が2倍になります。
相手に与えるダメージは、ダメージ計算メソッドで取得した値に相手の防御力を引いた値になります。
82~85行目
このif文は、行動するキャラクターの状態が防御の場合の処理です。
相手に与えるダメージは0になります。
88~93行目
このif文は、行動するキャラクターの状態が魔法の場合の処理です。
魔法は相手の防御力とは関係なしに、ダメージを与えることができます。
96行目
戦闘の状態を画面に表示します。
99、100行目
プレイヤーとモンスターのインスタンスを生成します。
引数のリストの前に*(アスタリスク)をつけると、リストの要素をひとつひとつの値として関数に渡すことができます。
103行目
while文を使ってループ処理に入ります。条件にTrueを使っているので、無限ループとなります。
どちらかのキャラクターのHPが0になるとexit()関数を呼び出して、スクリプトが終了します。
また、行動選択で、qを入力するとwhileループが終了します。
108行目
input()関数を使って、プレイヤーの行動を入力します。
111行目
qが入力された場合は、break文によりwhileループを抜けてスクリプトが終了します。
115行目
key()メソッドを使ってact_dic辞書からキーを抜き出し、list()関数でリストに変換しています。
そのリストをnot in条件で、a、b、c以外が入力された場合は、continue文によりwhileループの先頭に戻ります。
121行目
ユーザーが入力したキー(a、b、c)を元に、act_dic辞書からキーに対応した値(攻撃、防御、魔法)をplay.actn変数に代入します。
123行目
random.choices()関数によりact_dic辞書のキー(a、b、c)の中からランダムに取得して、その値(攻撃、防御、魔法)をmonst.actn変数に代入します。
また、weightsオプションによって、コンピューターの行動に相対的な重みをつけています。この場合は、攻撃8、防御1、魔法1の確率になります。
なお、random.choices()関数は結果をリストで返すので、[0]をつけて先頭の要素を指定しています。
random.choices()関数は、Pythonのバージョン3.6から追加されていますので、それ以前のバージョンのPythonでは使えません。
127、128行目
素早さ補正メソッドを呼び出して、キャラクターの行動に合わせた素早さの補正を行います。
131行目
キーを「キャラクター」、値を「素早さ」にした辞書を定義します。
134行目
131行目で定義した辞書を素早さの高い順に並び替えて、for文でループします。
character変数には、タプルに変換された要素([0]がキャラクター、[1]が素早さ)が代入されます。
138行目
プレイヤーの「状態」に、ユーザーが選択したプレイヤーの「行動」を設定します。
139行目
第1引数にプレイヤー、第2引数にモンスターのインスタンスを渡して、battle()関数を呼び出します。
143行目
モンスターの「状態」に、コンピューターがランダムで選択したモンスターの「行動」を設定します。
144行目
第1引数にモンスター、第2引数にプレイヤーのインスタンスを渡して、battle()関数を呼び出します。
147~154行目
どちらかのHPが0だった場合は、対応するメッセージを表示して、exit()関数でスクリプトを終了します。