主人公とモンス 9 ーのオフジェワトき作 3 つま 7 - 3 羊人公とモンスターの一 クラスを使って主人公とモンスターのデータと機能をま とめていきます。すべてのキャラクターに共通の機能は 「継承」という機能を使って 1 つにします。 キャラク 9 ーのクラスに必要なデー 9 と機能を考える 主人公とモンスターのクラスを作り、その後戦闘できるようにしてゲームを完成させ ましよう。さて、主人公やモンスターにはどんなデータを持たせればいいでしようか ? 表にまとめてみましよう。 ( hap 「 7 モンスター 2 主人公 モンスター 1 勇者ハル 30 マコデビル 名前 体力 (HP) 20 攻撃力 (ATK) 1 5 防御カ (DFS) これらのデータを属性で持たせればよさそうですね。では、関数についてはどうでしよ うか ? リリースネーク ・乱数で攻撃力を求める関数 ・乱数で防御力を求める関数 ・体力を減らし、 O になったかどうかを確認する関数 この 3 つの関数は主人公もモンスターも共通でよさそうです。属性に持たせるデータ 217
本番の戦闘画面き作成しよう「 - ・ = - ツ - 4 3 攻撃する場合 b 「 ave ー atk が 0 以上なら攻撃なので、「勇者は攻撃した」というテキストを labeltext に代入し、ラベルにセットします。 dO ー tu 「 n 関数の中にいる間は tkinte 「のメインループ に戻らないのでラベルが更新されません。 update 関数で画面を更新します。 0 戦闘結果を表示する 2 秒待ってから b 「 ave ー atk から m 〇 nste 「一 dfs を引いてダメージを求め、 0 以下なら「防 がれた」、 O より大きければ「〇〇のダメージを与えた」というテキストを labeltext に 追加します。 このとき M 〇 nste 「クラスの cu に一 hp 関数を呼び出して体力も変化させておきます。 ⑤モンスターの残り体力を表示する ②または④の [ abe [ text でラベルを更新し、また 2 秒待ってモンスターの残り体力を表 示します。 ′タンジョン & バイソン ロ ^ hap 「 7 勇者は攻撃した 9 のダメージを与えた モンスターの残り体力は 11 0 主人公が攻撃した場合の結果表示 次はモンスターのターンです。モンスターも攻撃するか、力をためるか選択するので、 乱数を使って決めます。そこから先は主人公のターンとほぼ同じです。 chap7fight . py self . dialog . update() # モンスターのターン time . sleep(2) # 2 秒待ち self . brave . get_dfs() brave dfs i f 「 a n d om . 「 a nd om ( ) く 0 . 2 : labeltext = labeltext + ” \ n \ n モンスターは力をためた " self . monster . reserve() @ 8 8 @8 9 @91 @9 2 @9 3 @9 4 235
e 15 e : @9 5 @9 6 @9 7 @9 8 @9 9 1 @@ 1@ 1 1 @2 1 @3 104 1@5 1 @ 6 1 @ 7 1 @8 1 @9 11@ 114 labeltext labeltext + ” \ n \ n モンスターの攻撃 " self . label["text"] labeltext self . dialog. update() # モンスターの攻撃の結果表示 time . sIeep(2) # 2 秒待ち monster atk self . monster . get_atk() dmg monster atk brave dfs self. brave . culc_hp(monster atk, brave dfs) labeltext labeltext + ” \ n 防いだ” e 1 5 e : labeltext labeltext + ”のダメージを受けた” # ラベル更新、残り体力表示 self . label["text"l labeltext self. dialog. update() time . sleep(2) # 2 秒待ち labeltext labeltext + \ ハ n 勇者の残り体力は " + 5t「(5e1f . brave . hp) self . label["text"] labeltext self . dialog. update() ′タンジョン & バイソン ロ 勇者は攻撃した 4 のダメージを与えた モンスターの残り体力は 16 モンスターの攻撃 1 のダメージを受けた 勇者の残り体力は 29 0 モンスターが攻撃した場合の結果表示 236
′タンジョン & バイソン 勇者は攻撃した 9 のタメージを与えた モンスターの残り体力は 0 力をためる ′タンジョン & バイソン 0 000000 00 000 0 今 0 S 0 000300 00000000 0 モンスターの残り体力が 0 になるとマップ画面に戻る 負ける場合もちゃんとテストします。主人公にかなり有利な設定なので、負けるほう が難しいですが、「力をためる」をずっと選び続ければいずれ負けます。 ′ダンジョンをバイソン 勇各は力をためた モンスターの残り体力は 20 モンスターの攻 11 のダメージを受けた 舅者の残り体力は 0 力をためる フロクラなのバクを探す 0 主人公の残り体力が 0 になるとバッドエンド ′タンション & バインン 勇者は負けてしまった . 最初からやり直して、れたまえ . これで完成したように思えますが、モンスターをすべて倒してゴールまで進めてみ てください。なぜか工ンディング画面が表示されません。何が悪いのでしようか ? chap7. py は約 1 20 行、 chap7fight. py は約 190 行もあるので間違いを探すのも大変で す。こういうときはデバッグ機能を使って問題を探しましよう。バグ (Bug) とは英語 で虫のことで、プログラムの中に潜んで悪さしている虫を意味しています。それを取り 除くのがデバッグです。 まずプログラムのバグが潜んでいそうな部分にあたりを付け、そこに「プレークポイ 238 Chapter
マップ上にモンスターを配置し、それと重なると戦闘画面が表示されるようにしてみ ましよう。マップデータにはモンスターの位置の情報はなく、 O ~ 3 までが地面の情 報のために使われています。また 4 は主人公用です。そこで、モンスター用に 5 と 6 を 使うことにします。モンスター用の画像はく img6 〉フォルダーの中に用意しているので ( P. 171 参照 ) 、それを読み込むようにします。 にできません。 テストのために p [ ace 」 0 「 get 関数はコメントアウトしておきましよう。 [tkinter . PhotoImage(fi1e="img6/chap6-mapfield . png"), tkinter . PhotoImage(fi1e="img6/chap6-mapwall . png"), tkinter . PhotoImage(fi1e="img6/chap6-mapgoa1. png"), tkinter . PhotoImage(file="img6/chap6-mapkey . png"), tkinter . PhotoImage(fi1e="img6/chap6-mapman . png"), chap7fight . py 確認したら p [ ace ー fo 「 get 関数のコメントを外してフレームを非表示にします。 ロロ ′タンジョン & イソン 配置された 0 キャンバスとホタンが ロ X @ 1 6 @ 1 7 # 非表示 self . dialog. place_forget() マッフにモンスターを配置する chap7. py 088 # 画像データを読み込み @8 9 lmages @ 9 1 @9 2 @9 3 @9 4 png")l 208 Chapter tkinter . PhotoImage(file="img6/chap7 -mapmonster .
7 - 4 本番の戦闘画面き作成しよっ 勝ち負けをチェックして次のターンに進む 主人公が攻撃して勝った場合、つまりモンスターの HP が O になった場合、戦闘画面を 消してマップ画面に戻ります。このチェックをするのは主人公のターンとモンスターの ターンの間です。 次の戦闘のためにボタンの無効化を解除しておき、 fight-win 関数を呼び出して retu 「 n 文で脱出します。 chap7fight . py labeltext 1 a b e 1 t e x t + \ ハ n モンスターの残り体力は” + str(self . monster . hp) s e 1 f . 1 a be 1 [ " t ex t " ] 1 a b e 1 t e x t self . dialog . update() i f 5 e 1 f. mon 5 t e 「 . hp く 1 : time . sIeep(2) # 2 秒待ち self . fbutton["state"l self . rbutton["state"l self . fight_win() 「 e t u 「 n # モンスターのターン モンスターが攻撃して勝った場合、つまり主人公の HP が O になった場合、バッドエン ディング画面を表示します。主人公の HP がまだ残っている場合は、ボタンを有効化し て関数を終了します。主人公の HP をチェックするのはモンスターのターンのあとです。 @8 5 @8 6 @8 7 @8 8 089 @91 @9 2 @9 3 @9 4 @9 5 ” no 「 maI ” "normal" ( hap 「 7 chap7fight . py 1 a b e 1 t e x t 1 a be 1 t e x t + \ " \ n 勇者の残り体力は " + str(self . brave . hp) 5 e 1 f . 1 a be 1 [ ” t e x t ” ] 1 a b e 1 t e x t self . dialog . update() i f 5e1 f . brave . hp く 1 : time . s1eep(2) # 2 秒待ち self. fight_lose() # ボタンを有効化して次のターンへ self . fbutton["state"l “ no 「 mal ” self . rbutton["state"l ” no 「 maI ” モンスターと戦って結果を確認してみましよう。ちゃんと倒せましたか ? 119 12@ 1 2 4 12 6 12 7 12 8 12 9 else: 23 /
オフジクト指向とクラス います。先に基本を覚えてしまいましよう。 ゲームを作りながら説明するとわかりにくくなってしま プログラムを書いていきますが、少し複雑なものなので、 、今回のゲームではオプジェクト指向とクラスを使用して でした。今度は迷路内にモンスターを出現させ、勇者と戦闘できるようにして、より口一 6 章で作成したゲームは、ロールプレイングゲーム風といいつつも実質は迷路ゲーム オフジェクト指向って何 ? ルプレイングゲームらしいものに発展させていきます。 ′連第グ - ム 0 0000000 0 3 鬮 3 00 000 0 0 0 000000 000000003 0 モンスターと接融すると戦闘画面が表示される ′タンジョン & バイソン 勇者は力をためた モンスターの残り体力は 20 モンスターの攻 11 のダメージを受けた 勇者の残り体力は 0 力をためる この戦闘画面を作るために、今回は「オプジェクト指向」と「クラス」というものを勉強 します。オプジェクト指向というのはプログラムを設計する考え方の一種です。いくつ かの関数とデータをまとめて 1 つのオプジェクト ( 物体 ) とし、オプジェクトを組み合わ せてプログラムを作成します。これだと、ちょっとわかるようでわからないかもしれま せんね。 1 9 イ
fight ー sta 「 t 関数を書き替えて、モンスターの種類によって表示する画像が切り替わる ようにしましよう。モンスターのマップデータは 5 か 6 なので、 5 引けば O か 1 となり、 images 属性に記録しておいた画像のリストの添字として使えます。 chap7fight . py # 戦闘開始 d e f f i gh t_s t a 「 t ( 5 e 1 f , m a pd a t a , x , y , b r a v e ) : self . dialog . place(x=l@, y = 10 ) self . map_data mapdata 5 e 1 f . b r a v e x self . brave_y = Y 5 e 1 f . b 「 a v e brave # モンスターの画像を表示 self. map_data[y] [x] P self . canvas . delete("all") self. canvas. create_rectangle(), 0 , 620 , 434 , fill="black ” ) self. canvas. create_image(180, 160 , image=self. images[p-51) self . label["text"] # モンスターのオブジェクトを作成 5 : self . monster = Monster1() el i f p 6 : s e 1 f . mon 5 t e 「 Monster2 ( ) self . label["text"] self . monster . name + ”がれた” また、モンスターのオプジェクトもこの段階で作っておきます。マップデータが 5 な ら Monste 「 1 ワラスのオプジェクトを、 6 なら Monste 「 2 クラスのオプジェクトを作成 し、 monste 「属性に代入しておきます。 ′ダンジョン & バイソン @3 2 @3 3 @3 4 @3 5 @3 6 @ 3 7 @3 8 @3 9 @41 042 043 e44 @4 5 046 047 048 049 ロ リリースネークが現れた 力をためる 攻撃 0 マップテータにあわ せて画像が切り替わる 232
Cha 「 73 12 歳から覚える Python は「オプジェクト指向」と「クラス」を利用します。 ルプレイングゲームに発展させましよう。戦闘の機能を追加するために、今回 6 章で作った迷路ゲームをベースに、モンスターとの戦闘画面を追加してロー 戦聞しよう モンスターと
- 4 本番の戦闘画面き作成しよう 7 3 モンスターの画像を読み込む モンスターの画像を読み込み、 images 属性に記憶しておきましよう。読み込み方は マップ用の画像データと同じです。 また、配置を確認するために c 「 ate ー image 関数を使って ( 180 , 160 ) の位置に表示し ます。 ④ラベルを配置 メッセージを表示するためのラベルを表示します。 戦闘画面を確認したいので、クリックイベントに割り当てる click-fight 関数と click- 「 ese 「 ve 関数を追加しておきます。内容はあとで加えるのでとりあえず pass とだけ書 バス いておきます。 pass 文は何もしませんが、書いておけば関数の中身がないために起きる 工ラーを回避できます。 chap7fight . py b 「 a V e 5 e 1 f . b r a v e # 攻撃ボタン def click_fight(self): paSS # 力をためるボタン def click_reserve(self) : p a 5 5 プログラムを実行 1 したらモンスターと重なるところまで移動して、戦闘画面を確認 しましよう。 ′ダンジョン & バイソン @3 8 @3 9 041 042 043 044 ( hap 「 7 ロ ラベ丿レ 0 力をためる 攻撃 0 モンスターに重なる と戦闘画面が表示され る 231