CODE Python RPG

独学でPythonでRPGを作成する(第54回)戦闘(回復呪文の修正)

投稿日:

こんにちは。
Pythonでつくる ゲーム開発 入門講座」の
Chapter11,12(本格RPGを作ろう!全編・後編)を基にRPGを作っていきます。

前回は戦闘に関する修正で、味方全員が物理攻撃を出来るようにしました。

今回から呪文を使えるように修正していきます。
今回は回復など自身や仲間に使う呪文を使えるように修正します。

目次

  1. 呪文の対象
  2. 呪文発動
  3. その他
  4. 最後に

呪文の対象

呪文を使う対象を選択できるようにします。
例:回復呪文の場合は誰を回復するか。

仲間がいない時は選択する必要が
なかったのですが、
仲間を追加したので、
対象を誰にするのか
選択できるようにします。

 

対象を選択している時、
以下箇所の名前を点滅させます。

この例ではハロ3を
選択しているので
決定キーを押下すれば
ハロ3に呪文をかけます。
※回復呪文の時は
 ハロ3を回復

対象の選択は
左右(←→)キーを使います。

 

 

対象を選択

それでは、呪文を使う対象を
選択できるようにします。

 

変更前

def spell_target_select(bg, key, player): # 呪文の対象を選択
    global idx, spell_target_i
    ent = False
    if chara.get_spell_target(player[0].mas_spell[sel_spell_i]) <= 1: # 呪文の対象が味方
        if key[K_SPACE] or key[K_RETURN]: # 決定
            ent = True

変更後

def spell_target_select(key, player): # 呪文の対象を選択 player[btl_player]:呪文選択中のプレイヤー
    global idx, spell_target_i
    ent = False
    if chara.get_spell_target(player[btl_player].mas_spell[sel_spell_i]) == 0:
        if key[K_LEFT] and spell_target_i > 0: # ←キー
            spell_target_i -= 1
        elif key[K_RIGHT] and spell_target_i < len(player)-1: # →キー
            spell_target_i += 1
        elif key[K_SPACE] or key[K_RETURN]: # 決定
            player[btl_player].target = player[spell_target_i] # 対象をセット
            ent = True
    elif chara.get_spell_target(player[btl_player].mas_spell[sel_spell_i]) == 1:
        if key[K_SPACE] or key[K_RETURN]: # 決定
            ent = True

    elif chara.get_spell_target(player[btl_player].mas_spell[sel_spell_i]) == 2: # 呪文の対象がモンスター単体
(省略)
    elif chara.get_spell_target(player[btl_player].mas_spell[sel_spell_i]) == 3: # 呪文の対象がモンスターグループ
(省略)
    elif chara.get_spell_target(player[btl_player].mas_spell[sel_spell_i]) == 4: # 呪文の対象がモンスター全体
(省略)

※spell_target_select関数の引数について
「bg」は不要だったので消しています。
 呼び出す側も消します。
 

前々回、コマンド選択中のキャラの
インデックスをbtl_playerにしたので
player[0]をplayer[btl_player]にしています。
※攻撃呪文についても
 ついでに変更しています。

 

if chara.get_spell_target(player[0].mas_spell[sel_spell_i]) <= 1: # 呪文の対象が味方
        if key[K_SPACE] or key[K_RETURN]: # 決定
            ent = True

変更前は仲間がいないので、
対象が単体でも複数でも
動作は同じだったので、
0と1を同じ処理にしていました。
※対象の選択不要

※get_spell_targetの戻り値
 呪文の対象が
 0→味方単体
 1→味方全員
 2→敵単体
 3→敵グループ
 4→敵全体
 です。

 

if chara.get_spell_target(player[btl_player].mas_spell[sel_spell_i]) == 0:
    if key[K_LEFT] and spell_target_i > 0: # ←キー
        spell_target_i -= 1
    elif key[K_RIGHT] and spell_target_i < len(player)-1: # →キー
        spell_target_i += 1

仲間を追加したので、
対象が味方単体の呪文は
左右(←→)キーで
対象を移動します。
※左右キーを押下すると
 点滅する名前を変更する
※spell_target_iは
 呪文対象のインデックスです。

 

elif key[K_SPACE] or key[K_RETURN]: # 決定
    player[btl_player].target = player[spell_target_i] # 対象をセット

対象を決めたら
対象オブジェクトを
targetに格納します。
※targetは前回追加した
 インスタンス変数です。

 

elif chara.get_spell_target(player[btl_player].mas_spell[sel_spell_i]) == 1:
    if key[K_SPACE] or key[K_RETURN]: # 決定
        ent = True

対象が味方全員の時は
選択不要になります。

 

 

対象を点滅

冒頭に記載したように
誰を選択中なのか
分かるように名前を点滅させます。

変更前

def draw_battle(bg, fnt, obj, player): # 戦闘画面の描画 obj:戦闘で行動中のオブジェクト
(省略)

    for i, p in enumerate(player):
        x_i_t.append(x_i + x_b*i + 10) # テキストのx座標の開始位置
        # 名前の表示(回復呪文の対象を選択中の時は点滅)
        if idx == 25 and chara.get_spell_target(p.mas_spell[sel_spell_i]) == 0: # 呪文の対象の選択中,呪文の対象が味方なら
            draw_text(bg, "{}".format(p.name), x_i_t[i], y_i_t, fnt, BLINK[tmr%6])
        else: # 呪文の対象の選択中でなければ
            draw_text(bg, "{}".format(p.name), x_i_t[i], y_i_t, fnt, col)

変更後

def draw_battle(bg, fnt, obj, player): # 戦闘画面の描画 obj:戦闘で行動中のオブジェクト
(省略)

    for i, p in enumerate(player):
        x_i_t.append(x_i + x_b*i + 10) # テキストのx座標の開始位置
        # 名前の表示(回復呪文の対象を選択中の時は点滅)
        if idx == 25 and ((chara.get_spell_target(p.mas_spell[sel_spell_i]) == 0 and i == spell_target_i) or chara.get_spell_target(p.mas_spell[sel_spell_i]) == 1): # 呪文の対象の選択中,呪文の対象が味方なら、対象が単体の時は対象のみ、対象が全員の時は全員
            draw_text(bg, "{}".format(p.name), x_i_t[i], y_i_t, fnt, BLINK[tmr%6])
        else: # 呪文の対象の選択中でなければ
            draw_text(bg, "{}".format(p.name), x_i_t[i], y_i_t, fnt, col)

点滅の条件を追加しています。

if idx == 25 and ((chara.get_spell_target(p.mas_spell[sel_spell_i]) == 0 and i == spell_target_i) or chara.get_spell_target(p.mas_spell[sel_spell_i]) == 1):

・対象が単体 かつ 選択中 の場合、
・対象が味方全員 の場合、
は名前を点滅するようにしています。
※味方全員の場合は全員の名前が点滅

 

 

対象を確定

呪文の対象を確定したら
行動(act)に26(呪文を使う)を
格納します。

def main(screen, clock, font, fontS, player, area):
(省略)
        elif idx == 25: # 呪文の対象を決める
            draw_battle(screen, fontS, turn_obj, player)
            if spell_target_select(key, player) == True:
                player[btl_player].act = 26 # get_battle_turnの戻り値idxを26
player[btl_player].act = 26 # get_battle_turnの戻り値idxを26

呪文を選択したキャラの
行動(act)についても
player[0]から
player[btl_player]に
変更します。

 

if spell_target_select(key, player) == True:

spell_target_select関数の
引数「bg」を削除したので
呼び出す側も「screen」を
削除しています。

 

 

呪文発動

使った呪文が
正常に動作するように
修正します。

まず、player[0]を
修正します。

ここではplayer[btl_player]ではなく
turn_objに変更しています。

player[btl_player]→コマンド選択中のキャラ
turn_obj→ターン内で行動中のキャラ(モンスター含む)

def main(screen, clock, font, fontS, player, area):
(省略)
        elif idx == 26: # 呪文発動
            draw_battle(screen, fontS, turn_obj, player)
            spell_point = 0 # プレイヤーが与えるダメージ、受けるダメージ 呪文用
            if tmr == 1:
                spell_blink = chara.get_spell_blink(turn_obj.mas_spell[tmp_sel_spell_i]) # 呪文演出(いろ)
                spell_blink = spell_blink.split(",")
                set_message(turn_obj.name + " は " + turn_obj.mas_spell[sel_spell_i] + " となえた!")
            if 2 <= tmr and tmr <= 4:
                print(spell_blink)
                print(tmr)
                print(spell_blink[tmr%3])
                pygame.draw.rect(screen, spell_blink[tmr%3], [0, 0, screen.get_width(), screen.get_height()])
            if tmr == 8:
                if turn_obj.check_mp(turn_obj.mas_spell[sel_spell_i]): # mpが足りていたら
                    spell_target_no = chara.get_spell_target(turn_obj.mas_spell[sel_spell_i]) # 呪文の対象(0:味方単体,1:味方全員,2:敵単体,3:敵グループ,4:敵全体)
                    if spell_target_no == 0: # 呪文の対象が味方単体
                        spell_point, spell_message = turn_obj.use_spell(turn_obj.mas_spell[sel_spell_i], turn_obj.target, spell_target_no)
                        if spell_point != -1: # 回復系、-1は補助系
                            turn_obj.target.hp += spell_point
                            if turn_obj.target.hp > turn_obj.target.maxhp:
                                turn_obj.target.hp = turn_obj.target.maxhp
                        set_message(spell_message)
spell_blink = chara.get_spell_blink(turn_obj.mas_spell[tmp_sel_spell_i]) # 呪文演出(いろ)

player[0]→turn_obj
に修正しています。

if spell_target_no == 0: # 呪文の対象が味方単体
    spell_point, spell_message = turn_obj.use_spell(turn_obj.mas_spell[sel_spell_i], turn_obj.target, spell_target_no)
    if spell_point != -1: # 回復系、-1は補助系
        turn_obj.target.hp += spell_point
        if turn_obj.target.hp > turn_obj.target.maxhp:
            turn_obj.target.hp = turn_obj.target.maxhp

player[0]→turn_obj.target
に修正しています。

ここは呪文を使う側ではなく、
使われる側(呪文の対象)です。

 

次に、味方全員に使う呪文の
処理を追加します。

def main(screen, clock, font, fontS, player, area):
(省略)
        elif idx == 26: # 呪文発動
(省略)
                    if spell_target_no == 0: # 呪文の対象が味方単体
(省略)
                    elif spell_target_no == 1: # 呪文の対象が味方全体
                        for i, p in enumerate(player):
                            spell_point, spell_message = turn_obj.use_spell(turn_obj.mas_spell[sel_spell_i], p, spell_target_no)
                            set_message(spell_message)
                            if spell_point != -1: # 回復系、-1は補助系
                                p.hp += spell_point
                                if p.hp > p.maxhp:
                                    p.hp = p.maxhp
                            draw_battle(screen, fontS, turn_obj, player)
                            pygame.display.update() # 少し時間をとめる
                            pygame.time.delay(delay_speed)

仲間がいない時は
使うことがないので
「pass」にしていました。

1人ずつuse_spellメソッドを
呼び出して、呪文をかけます。
※回復呪文の場合は回復する

 

pygame.display.update() # 少し時間をとめる
pygame.time.delay(delay_speed)

メッセージ表示の為に
少し時間を止めています。

他の箇所でも使っていますが
この方法で時間を止めるのは
何となく辞めたほうが良い気がするので、
変更しようと思っています。
※そのうち・・

 

とりあえず、回復など自身や仲間に使う呪文は
使えるようになりましたが、
複数人が回復呪文を使った場合、
使う呪文は最後のキャラが選択した呪文を
全員使うことになります。


1人目:スカラ
2人目:ホイミ
3人目:ベホイミ
4人目:ベホマラー
を選択した場合、
全員ベホマラーを使ってしまいます。

これは前回の攻撃対象と
似たような原因と思います。

選択した呪文が何かを格納する際に
全員同じ変数を使っている為
上書きされてしまっていると思います。

この辺りは次回修正しようと思います。

といういことで、
呪文に関する修正について
今回は以上にします・・

 

 

その他

バグというわけではないですが
経験値の取得について、少し変更します。

 

変更前

def main(screen, clock, font, fontS, player, area):
(省略)

            if tmr == 11:
                tmp_exp = do_attack(turn_obj.target, dmg, turn_obj)
                if dmg != 0 and tmp_exp == 0 and turn_obj.target.flag_sleep: # 攻撃を受けた かつ 生きている かつ 眠っている
                    if random.randint(0, 99) < 55:
                        turn_obj.target.invalid_sleep()
                        set_message(turn_obj.target.name + " はめをさました!")
                btl_exp += tmp_exp
                check_monster()

変更後

def main(screen, clock, font, fontS, player, area):
(省略)

            if tmr == 11:
                btl_exp += do_attack(turn_obj.target, dmg, turn_obj) # 倒していない時は0が返る
                if dmg != 0 and turn_obj.target.hp != 0 and turn_obj.target.flag_sleep: # 攻撃を受けた かつ 生きている かつ 眠っている
                    if random.randint(0, 99) < 100:
                        turn_obj.target.invalid_sleep()
                        set_message(turn_obj.target.name + " はめをさました!")
                check_monster()

眠っている対象に攻撃をした場合
条件を満たせば、
一定確率で目を覚ますようにしています。

その条件は
攻撃を受けた、生きている、眠っている
の3つです。
※ミス(ダメージ0)は対象外

この条件の中の生きているかどうかを
確認する為に
変更前はdo_attack関数の
戻り値(経験値)を使っていました。
※経験値が0の場合は
 まだ生きている、
 経験値が0でない場合、
 対象を倒した

この条件を単純に攻撃対象のHPが
0かそうでないかに変更しました。

というだけです・・

 

そして、今回は以上です!(`・ω・´)

 

 

最後に

今回は戦闘における呪文について
回復など自身や仲間に使う呪文を
使えるように修正しました。

次回も呪文を修正したいと思います。

まとめサイトへ

 

 

【ご注意】
プログラムやデータなどは著作権法により保護されています。
著作者の許諾を得ずに、プログラムおよびデータそのものまたは改変したものを
配布したり販売したりすることはできません。
また、これらを利用して発生した損害などに関して、著作者は一切責任を負いません。

 

 

-CODE, Python, RPG
-, , , , , , , , ,

Copyright© kerublog , 2022 All Rights Reserved Powered by STINGER.