敵が出る迷路ゲームを作ろう
今回は前回のトラップの代わりに敵が出る迷路ゲームを作ります。
敵が出現すると戦闘になり、プレイヤーと敵がランダムで攻撃を行います。
どちらかのHPが0になると戦闘は終了して、プレイヤーが負けた場合はそこでゲームオーバーになります。
敵を倒すとゴールドを取得できます。
ゴールに到着するまでに合計でいくらゴールドが貯まるかを競います。
なお、迷路に敵が無限にいるのはおかしいので、出現する敵の数には最大数を設定しています。
ゲームの仕様は、以下のようになります。
仕様
- 2次元リストを使って迷路のイメージを定義する
- 配列の要素の種類は0、1、2、3として、0は通行不可、1は通行可能、2はゴール、3は回復ポイントとする
- 移動キーは、wは上移動、sは下移動、aは左移動、dは右移動とする
- qキーでスクリプトを終了する
- キャラクターにHPを設定する
- 敵がランダムに出現して戦闘を行う
- 敵を倒すとゴールドが得られ、プレイヤーが負けるとゲームオーバーとなる
- 回復ポイントを設定して、そのマスに入るとキャラクターのHPが全快する
- ゴールに到達したらスクリプトを終了する
実行イメージ
実行イメージは、以下のようになります。
現在地は、2次元リストのインデックスで、[縦/横]という意味です。
qを入力するとゲームは終了します。
実行例
> python maze3.py
++ 操作方法 [上:w][下:s][左:a][右:d][終了:q]
++ 現在地 [00/00]
>>> d
++ 現在地 [00/01]
>>> d
++ 現在地 [00/02]
>>> d
++ 現在地 [00/03]
>>> d
++ 現在地 [00/04]
>>> s
++ 現在地 [01/04]
>>> d
+++ 盗賊があらわれた!
+ [1]冒険者は0のダメージ
+ [2]盗賊は17のダメージ
+++ 冒険者は盗賊を倒しました!
+++ 冒険者の残りのHPは200です
+++ 冒険者は399のゴールドを得た
:
:
+++ ゴールに到着しました!
+++ 冒険者は合計4144ゴールド取得しました
Pythonスクリプト
ゲームのPythonスクリプトは、以下のようになります。
今回の迷路は、16 x 16 のマスを定義しています。
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 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
### インポート import random ### キー操作 UP, DOWN, LEFT, RIGHT = range(4) KEY_DIC = {"w":UP, "s":DOWN, "a":LEFT, "d":RIGHT} ### マップ ####### 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 ##### MAP = [[1,1,1,1,1,0,3,0,0,0,0,1,1,1,1,3], # 0 [1,0,0,0,1,1,1,0,0,0,0,1,1,0,0,0], # 1 [1,1,1,1,1,0,1,1,1,1,1,1,1,0,0,0], # 2 [0,0,1,1,1,1,1,0,0,0,0,0,1,1,1,1], # 3 [0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,1], # 4 [0,0,1,1,1,1,1,0,0,0,0,0,0,3,0,1], # 5 [0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1], # 6 [0,1,0,0,0,1,1,1,0,0,1,0,0,0,0,0], # 7 [1,1,1,1,1,1,1,0,1,1,1,0,0,3,0,0], # 8 [1,0,0,1,1,1,1,0,1,1,1,0,0,1,0,0], # 9 [1,3,0,1,1,0,1,1,1,1,1,1,1,1,0,0], # 10 [1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1], # 11 [1,0,0,0,1,1,1,1,1,1,0,0,1,1,1,0], # 12 [1,1,1,0,1,0,0,0,1,3,0,0,1,1,1,0], # 13 [1,1,1,0,1,0,0,0,1,0,0,0,1,1,1,1], # 14 [0,1,1,1,1,0,0,1,1,1,1,1,1,1,1,2]] # 15 ### メッセージ MES_N_1 = "++ 操作方法 [上:w][下:s][左:a][右:d][終了:q]" MES_N_2 = "++ 現在地 [{:02d}/{:02d}]" MES_N_3 = "+++ ゴールに到着しました!" MES_N_4 = "+++ {}があらわれた!" MES_N_5 = "+ [{}]{}は{}のダメージ" MES_N_6 = "+++ {}の残りのHPは{}です" MES_N_7 = "+++ {}は{}のゴールドを得た" MES_N_8 = "+++ {}は{}を倒しました!" MES_N_9 = "+++ {}は{}に倒されました..." MES_N_10 = "+++ {}は合計{}ゴールド取得しました" MES_N_11 = "+++ {}のHPが全回復しました" MES_E_1 = "!!! キーが違います" MES_E_2 = "!!! 移動できません" ### 定数 U_HP_MAX = 200 # プレイヤーHP ENEMY_MAX = 10 # 最大敵数 E_HP_MIN = 8 # 敵HP最小値 E_HP_MAX = 20 # 敵HP最大値 E_GOLD_MAX = 1000 # 敵最大所持金 DAMAGE_MAX = 20 # ダメージ最大値 ### 迷路クラス class Maze: ### 初期化メソッド def __init__(self, now_h, now_w): ### クラス変数 self.now_h = now_h # 現在地:縦座標 self.now_w = now_w # 現在地:横座標 self.enemy_num = ENEMY_MAX # 敵数 self.step = 1 # 歩数 ### 現在地表示 def draw(self): print(MES_N_2.format(self.now_h, self.now_w)) ### 移動 def move(self, u_input): ### 次位置 next_h = self.now_h next_w = self.now_w ### 上移動 if u_input == UP: next_h -= 1 if (next_h < 0) or (MAP[next_h][next_w] == 0): print(MES_E_2) return False else: self.now_h -= 1 ### 下移動 elif u_input == DOWN: next_h += 1 if (next_h > len(MAP)-1) or (MAP[next_h][next_w] == 0): print(MES_E_2) return False else: self.now_h += 1 ### 左移動 elif u_input == LEFT: next_w -= 1 if (next_w < 0) or (MAP[next_h][next_w] == 0) : print(MES_E_2) return False else: self.now_w -= 1 ### 右移動 elif u_input == RIGHT: next_w += 1 if (next_w > len(MAP[next_h])-1) or (MAP[next_h][next_w] == 0): print(MES_E_2) return False else: self.now_w += 1 ### ゴール確認 if MAP[self.now_h][self.now_w] == 2: print(MES_N_3) print(MES_N_10.format(user.name, user.gold)) return True ### HP回復 if MAP[self.now_h][self.now_w] == 3: user.hp = U_HP_MAX print(MES_N_11.format(user.name)) ### エンカウント計算 encount = (self.step + random.randrange(300) / 100) * random.randint(1, 5) ### 敵エンカウント if (self.enemy_num > 0) and (encount > 19) and (MAP[self.now_h][self.now_w] == 1): ### 盗賊インスタンス生成 enemy = Character("盗賊", random.randint(E_HP_MIN, E_HP_MAX), random.randrange(E_GOLD_MAX)) char_list.append(enemy) print(MES_N_4.format(enemy.name)) ### 戦闘開始 turn = 1 while True: ### ランダムでどちらかが選択 rc = battle(random.choice(char_list), turn) ### どちらかのHPが0なら戦闘終了 if rc == True: break else: turn += 1 ### プレイヤー勝利 if user.hp > 0: ### 敵削除 print(MES_N_8.format(user.name, enemy.name)) del char_list[1] ### プレイヤー敗北 else: print(MES_N_9.format(user.name, enemy.name)) return True ### 戦後処理 user.gold += enemy.gold print(MES_N_6.format(user.name, user.hp)) print(MES_N_7.format(user.name, enemy.gold)) ### 歩数初期化 self.step = 0 ### 敵数を減らす self.enemy_num -= 1 ### 歩数カウントアップ self.step += 1 return False ### キャラクタークラス class Character: ### 初期化メソッド def __init__(self, name, hp, gold): ### ステータス self.name = name self.hp = hp self.gold = gold ### 戦闘関数 def battle(arg, turn): ### ダメージ計算 f_damage = random.randrange(DAMAGE_MAX) ### 対象キャラのHPからダメージを引く arg.hp -= f_damage print(MES_N_5.format(turn, arg.name, f_damage)) ### 対象キャラのHPを確認 if arg.hp > 0: return False else: return True #################### ### メイン処理 #################### ### スタート地点 now_h = 0 now_w = 0 ### 迷路クラス生成 maze = Maze(now_h, now_w) ### プレイヤーキャラ生成 user = Character("冒険者", U_HP_MAX, 0) char_list = [user] ### 操作方法表示 print(MES_N_1) ### メインループ while True: ### 位置表示 maze.draw() ### 行動入力 input_key = input(">>> ") ### ゲーム終了 if input_key == "q": break ### 入力確認 for x in list(KEY_DIC.keys()): if input_key == x: break else: print(MES_E_1) continue ### 移動 rc = maze.move(KEY_DIC[input_key]) ### 終了確認 if rc == True: ### 終了 break |
スクリプト解説
今回は前回と同じ個所は割愛しています。
前回のスクリプトは、以下を参照してください。
121行目
敵とのエンカウントするタネの値を計算します。
歩数に0~299に100を割り算した値を足し、それに1~5を掛けます。
124行目
以下の条件で敵とエンカウントします。
・敵が残っている
・エンカウント値が19以上
・マスの値が1
127行目
敵キャラクターのインスタンスを生成します。
HPと所持金をランダムに設定します。
128行目
キャラクターリストに敵のインスタンスを追加します。
134~143行目
プレイヤーか敵のHPが0になるまで無限ループで、戦闘関数を呼び出します。
137行目
キャラクターリストからランダムでプレイヤーか敵のどちらかが選択して、戦闘関数を呼び出します。
150行目
プレイヤーが勝った場合は、キャラクターリストから敵のインスタンスを削除します。
158行目
プレイヤーの所持金に敵の所持金を追加します。
174~182行目
キャラクタークラスを定義します。
185~198行目
戦闘関数を定義します。
引数で渡されたキャラクターのHPをランダムでダメージ値を引き算します。
212行目
プレイヤーキャラクターのインスタンスを生成します。
213行目
キャラクターリストにプレイヤーキャラクターを定義します。