SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

レトロ風ゲームを作って学ぶPython入門

【作って学ぶPython】バトル画面を実装させ、レトロ風RPGを完成させよう!

レトロ風ゲームを作って学ぶPython入門 第5回

  • X ポスト
  • このエントリーをはてなブックマークに追加

s_battle/proc_hero.py

 主人公側の進行を管理するs_battle/proc_hero.pyモジュールです。かなりボリュームがあるので、全体を掲載したあと、部分を分割しながら説明します。

s_battle/proc_hero.py
import pygame, data, hero, enemy, dialog, audio
from random import randrange

# 開始
def start():
    action = data.menu_texts[data.menu_sel]     # 選択行動取得

    # 逃走
    if action == "ESCAPE":  # 選択行動が ESCAPE の場合
        if randrange(2) == 0:   # 1/2の確率
            dialog.show("逃げるのに\n成功しました") # ダイアログ表示
            data.scene_next = "map"     # シーンをマップに
        else:
            dialog.show("逃げるのに\n失敗しました") # ダイアログ表示
            data.proc = "enemy_start"   # 進行を敵開始に
        return  # 処理を打ち切る

    # 通常攻撃
    at = randrange(hero.at // 2, hero.at)   # 半分以上、1倍未満

    # 魔法
    if action == "MAGIC":   # 選択行動が MAGIC の場合
        if hero.mp == 0:    # MPが0
            dialog.show("MPが足りません")   # ダイアログ表示
            return  # 処理を打ち切る
        at = randrange(hero.at * 2, hero.at * 4)    # 2倍以上、4倍未満
        hero.mp -= 1

    # ダメージ適用
    df = randrange(enemy.df)    # 0以上、1倍未満
    damage = max(1, at - df)    # ダメージ(最小1)
    enemy.hp = max(0, enemy.hp - damage)    # HP減少(HPの最低値は0)

    # 演出と進行
    audio.damage.play()     # ダメージSE再生
    data.ef_enemy = True    # 敵演出ありに
    data.ef_time_start = pygame.time.get_ticks()    # 演出開始時間記録
    data.proc = "hero_draw" # 進行を自描画に

# 描画
def draw():
    time = pygame.time.get_ticks()  # ゲーム開始からの経過時間
    if time >= data.ef_time_start + 500:    # 500ミリ秒以上経過したか
        data.ef_enemy = False   # 敵演出なしに
        end()   # 終了

# 終了
def end():
    data.proc = "enemy_start"   # 進行を敵開始に
    if enemy.hp == 0:   # HPが0か確認
        if enemy.boss:  # ラスボスか確認
            # ラスボス時はエンディング
            audio.play(audio.ENDING)    # エンディングのBGM再生
            dialog.show(f"{enemy.name}を\n倒しました")  # ダイアログ表示
            dialog.show("あなたは王国を\n救いました")   # ダイアログ表示
            dialog.show("Congratulations!") # ダイアログ表示
            data.scene_next = "title"       # シーンをタイトルに
        else:
            audio.play(audio.WIN)   # 勝利のBGM再生
            dialog.show(f"{enemy.name}を\n倒しました")  # ダイアログ表示
            mes = f"経験値 {enemy.exp} 獲得"    # 経験値獲得メッセージ
            if hero.add_exp(enemy.exp):         # 経験値追加(レベルアップ判定)
                mes += f"\nレベル {hero.level} に上昇"  # レベルアップ時メッセージ
            dialog.show(mes)        # ダイアログ表示
            data.scene_next = "map" # シーンをマップに

 インポート部分ではpygame, data, hero, enemy, dialog, audioを読み込みます。また、randomからrandrange関数を読み込みます。randomをインポートしてrandom.randrange()と書いてもよいのですが、プログラムのボリュームが大きいので、少しでも記述量を減らすために関数のみを読み込んでいます。

開始の冒頭

 次は、開始をおこなうstart()関数の冒頭部分です。

開始の冒頭
# 開始
def start():
    action = data.menu_texts[data.menu_sel]     # 選択行動取得

    # 逃走
    if action == "ESCAPE":  # 選択行動が ESCAPE の場合
        if randrange(2) == 0:   # 1/2の確率
            dialog.show("逃げるのに\n成功しました") # ダイアログ表示
            data.scene_next = "map"     # シーンをマップに
        else:
            dialog.show("逃げるのに\n失敗しました") # ダイアログ表示
            data.proc = "enemy_start"   # 進行を敵開始に
        return  # 処理を打ち切る

 選択したメニュー位置data.menu_selに当たるdata.menu_textsのテキストを読み込み、変数actionに代入します。このactionが選択した行動です。

 actionの中身は"SWORD""MAGIC""ESCAPE"のいずれかになります。

 action"ESCAPE"(逃走)のときは、1/2の確率で逃走に成功します。成功した場合はダイアログを表示して、マップ画面に移動します。失敗した場合はダイアログを表示して、進行を敵手番に移します。

攻撃とダメージの適用

 次は攻撃とダメージの適用です。

攻撃とダメージの適用
    # 通常攻撃
    at = randrange(hero.at // 2, hero.at)   # 半分以上、1倍未満

    # 魔法
    if action == "MAGIC":   # 選択行動が MAGIC の場合
        if hero.mp == 0:    # MPが0
            dialog.show("MPが足りません")   # ダイアログ表示
            return  # 処理を打ち切る
        at = randrange(hero.at * 2, hero.at * 4)    # 2倍以上、4倍未満
        hero.mp -= 1

    # ダメージ適用
    df = randrange(enemy.df)    # 0以上、1倍未満
    damage = max(1, at - df)    # ダメージ(最小1)
    enemy.hp = max(0, enemy.hp - damage)    # HP減少(HPの最低値は0)

 まず、通常攻撃("SWORD")の攻撃力atを求めます。ランダムな数値で、主人公の攻撃力の半分以上、1倍未満です。

 次にaction"MAGIC"だった場合は、MPが足りるか確認します。足りないときはダイアログを表示して処理を打ち切ります。

 足りる場合は、攻撃力atを魔法の攻撃力に変更して、mpを1減らします。魔法の攻撃力は、ランダムな数値で、主人公の攻撃力の2倍以上、4倍未満です。

 敵の防御力dfを求めます。0以上、敵の防御力未満です。

 求めた攻撃力から防御力を引いて、ダメージを計算します。その際、1未満にならないように、引数のうち最大の値を返すmax()関数を利用します。

 最後に敵のhpを減らします。こちらもmax()関数を利用して、0未満にならないようにします。

演出と進行、描画

 次は演出と進行、描画です。

演出と進行、描画
    # 演出と進行
    audio.damage.play()     # ダメージSE再生
    data.ef_enemy = True    # 敵演出ありに
    data.ef_time_start = pygame.time.get_ticks()    # 演出開始時間記録
    data.proc = "hero_draw" # 進行を自描画に

# 描画
def draw():
    time = pygame.time.get_ticks()  # ゲーム開始からの経過時間
    if time >= data.ef_time_start + 500:    # 500ミリ秒以上経過したか
        data.ef_enemy = False   # 敵演出なしに
        end()   # 終了

 ダメージのSEを再生して、data.ef_enemyTrueにして敵の演出を有効にします。また、data.ef_time_startにゲーム開始からの経過時間を代入します。

 最後に、進行data.procを、主人公の描画の"hero_draw"にします。

 描画を管理するdraw()関数では、500ミリ秒経過したら描画を終了します。その際、data.ef_enemyFalseにして敵の演出を止めます。そしてend()関数を実行します。

終了処理

 最後は終了をおこなうend()関数です。

終了処理
# 終了
def end():
    data.proc = "enemy_start"   # 進行を敵開始に
    if enemy.hp == 0:   # HPが0か確認
        if enemy.boss:  # ラスボスか確認
            # ラスボス時はエンディング
            audio.play(audio.ENDING)    # エンディングのBGM再生
            dialog.show(f"{enemy.name}を\n倒しました")  # ダイアログ表示
            dialog.show("あなたは王国を\n救いました")   # ダイアログ表示
            dialog.show("Congratulations!") # ダイアログ表示
            data.scene_next = "title"       # シーンをタイトルに
        else:
            audio.play(audio.WIN)   # 勝利のBGM再生
            dialog.show(f"{enemy.name}を\n倒しました")  # ダイアログ表示
            mes = f"経験値 {enemy.exp} 獲得"    # 経験値獲得メッセージ
            if hero.add_exp(enemy.exp):         # 経験値追加(レベルアップ判定)
                mes += f"\nレベル {hero.level} に上昇"  # レベルアップ時メッセージ
            dialog.show(mes)        # ダイアログ表示
            data.scene_next = "map" # シーンをマップに

 進行data.procを敵開始"enemy_start"にしたあと、敵のhp0なら勝利の処理をおこないます。

 勝利の処理は、ラスボスか通常戦闘かで異なります。まずは、それぞれBGMを再生してダイアログを表示します。

 ラスボスのときは、ダイアログを表示したあとタイトル画面に移ります。通常戦闘のときは、経験値を獲得してマップ画面に移ります。

s_battle/proc_enemy.py

 敵側の進行を管理するs_battle/proc_enemy.pyモジュールです。主人公側と関数の構成は同じですが、主人公側に比べてボリュームは少ないです。

s_battle/proc_enemy.py
import pygame, data, hero, enemy, dialog, audio
from random import randrange

# 開始
def start():
    # 攻撃
    at = randrange(enemy.at // 2, enemy.at) # 半分以上、1倍未満
    df = randrange(hero.df)     # 0以上、1倍未満
    damage = max(1, at - df)    # ダメージ(最小1)
    hero.hp = max(0, hero.hp - damage)  # HP減少(HPの最低値は0)

    # 演出と進行
    audio.damage.play()     # ダメージSE再生
    data.ef_hero = True     # 自演出ありに
    data.ef_time_start = pygame.time.get_ticks()    # 演出開始時間記録
    data.proc = "enemy_draw"    # 進行を敵描画に

# 描画
def draw():
    time = pygame.time.get_ticks()  # ゲーム開始からの経過時間
    if time >= data.ef_time_start + 500:    # 500ミリ秒以上経過したか
        data.ef_hero = False    # 自演出なしに
        end()   # 終了

# 終了
def end():
    data.proc = "menu"  # 進行をメニューに
    if hero.hp == 0:    # HPが0か確認
        audio.play(audio.LOSE)  # 敗北のBGM再生
        dialog.show("あなたは死にました\nそして復活しました")   # ダイアログ表示
        mes = "経験値 20 獲得"  # 経験値獲得メッセージ
        if hero.add_exp(20):    # 経験値追加(レベルアップ判定)
            mes += f"\nレベル {hero.level} に上昇"  # レベルアップ時メッセージ
        dialog.show(mes)    # ダイアログ表示

        # スタート位置に移動して回復
        hero.x = hero.next_x = hero.start_x # X位置、次回X位置を開始X位置に
        hero.y = hero.next_y = hero.start_y # Y位置、次回Y位置を開始Y位置に
        hero.hp = hero.hp_max   # HP回復
        hero.mp = hero.mp_max   # MP回復
        data.scene_next = "map" # シーンをマップに

 インポート部分、描画を管理するdraw()関数は主人公側と同じです。開始のstart()関数は、逃走と魔法がないので短くなっています。説明が必要なのは、終了のend()関数だけです。

 end()関数では、進行data.procをメニュー"menu"にしたあと、主人公のhp0なら敗北の処理をおこないます。

 敗北時は、経験値が20固定で入り、ダイアログを表示します。そして、開始位置に移動して、hpmpを最大値まで回復します。

 最後に、マップ画面に移動してバトルを抜けます。

次のページ
s_battle/draw.py

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
レトロ風ゲームを作って学ぶPython入門連載記事一覧

もっと読む

この記事の著者

柳井 政和(ヤナイ マサカズ)

クロノス・クラウン合同会社 代表社員http://crocro.com/オンラインソフトを多数公開。プログラムを書いたり、ゲームを作ったり、記事を執筆したり、マンガを描いたり、小説を書いたりしています。「めもりーくりーなー」でオンラインソフト大賞に入賞。最近は、小説家デビューして小説も書いています(『裏切りのプログラム』他)。面白いことなら何でもOKのさすらいの企画屋です。 

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/19459 2024/06/24 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング