CODE Python RPG

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

投稿日:

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

前回は戦闘に関する修正で、回復など自身や仲間に使う呪文を使えるようにしました。

今回は攻撃など相手に使う呪文を使えるようにします。

目次

  1. 呪文の対象
  2. 同じ修正
  3. 「じゅもん」を選択
  4. 使用呪文を格納
  5. btl_playerに修正
  6. 最後に

呪文の対象

攻撃など相手に使う呪文を選択した後、
対象(モンスター)を選択します。

その時に選択中の対象を点滅させます。
※今までもそうでしたが
 仲間がいる時にも
 正常に点滅するようにします。

 

変更前

def draw_battle(bg, fnt, obj, player): # 戦闘画面の描画 obj:戦闘で行動中のオブジェクト
(省略)
                # 呪文対象を決める(idx=25)、呪文対象がモンスター単体の時、呪文対象を表示させない(点滅させる)
                if idx == 25:
                    if chara.get_spell_target(player[0].mas_spell[sel_spell_i]) == 2: # 呪文の対象がモンスター単体
(省略)
                    elif chara.get_spell_target(player[0].mas_spell[sel_spell_i]) == 3: # 呪文の対象がモンスターグループ
(省略)
                    elif chara.get_spell_target(player[0].mas_spell[sel_spell_i]) == 4: # 呪文の対象がモンスター全体
(省略)
                    else: # 回復系
                        bg.blit(mon.img, [mon.x, mon.y])

変更後

def draw_battle(bg, fnt, obj, player): # 戦闘画面の描画 obj:戦闘で行動中のオブジェクト
(省略)
            else:
                # 呪文対象を決める(idx=25)、呪文対象がモンスター単体の時、呪文対象を表示させない(点滅させる)
                if idx == 25:
                    spell_target_no = -1
                    if len(player[btl_player].mas_spell) != 0:
                        spell_target_no = chara.get_spell_target(player[btl_player].mas_spell[sel_spell_i]) # 呪文の対象(0:味方単体,1:味方全員,2:敵単体,3:敵グループ,4:敵全体)
                    if spell_target_no == 2: # 呪文の対象がモンスター単体
(省略)
                    elif spell_target_no == 3: # 呪文の対象がモンスターグループ
(省略)
                    elif spell_target_no == 4: # 呪文の対象がモンスター全体
(省略)
                    else: # 回復系
                        bg.blit(mon.img, [mon.x, mon.y])

また、player[0]をplayer[btl_player]に
修正しています。
※btl_playerはこちらで追加した変数で
 コマンド選択中キャラのインデックスです。 

if len(player[btl_player].mas_spell) != 0:
    spell_target_no = chara.get_spell_target(player[btl_player].mas_spell[sel_spell_i])

今までは使える呪文を
覚えている前提にしていましたが
使える呪文があるのか確認します。
※後述しますが、ここに来る前にも
 同じことを確認するので、
 一応の意味合いが強いです。
 ※というか、無くて良いと思います。。

あと、get_spell_target関数の戻り値を
変数「spell_target_no」に格納しました。

 

 

同じ修正

他の箇所も同じ修正をします。

前回、修正したところも
同じようにしておきます。

変更前

def draw_battle(bg, fnt, obj, player): # 戦闘画面の描画 obj:戦闘で行動中のオブジェクト
(省略)
        # 名前の表示(回復呪文の対象を選択中の時は点滅)
        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)

変更後

def draw_battle(bg, fnt, obj, player): # 戦闘画面の描画 obj:戦闘で行動中のオブジェクト
(省略)
        # 名前の表示(回復呪文の対象を選択中の時は点滅)
        spell_target_no = -1
        if len(p.mas_spell) != 0:
            spell_target_no = chara.get_spell_target(p.mas_spell[sel_spell_i]) # 呪文の対象(0:味方単体,1:味方全員,2:敵単体,3:敵グループ,4:敵全体)
        if idx == 25 and ((spell_target_no == 0 and i == spell_target_i) or spell_target_no == 1): # 呪文の対象の選択中,呪文の対象が味方なら、対象が単体の時は対象のみ、対象が全員の時は全員
            draw_text(bg, "{}".format(p.name), x_i_t[i], y_i_t, fnt, BLINK[tmr%6])
if len(p.mas_spell) != 0:
    spell_target_no = chara.get_spell_target(p.mas_spell[sel_spell_i])

覚えている呪文があるかの確認と
get_spell_target関数の戻り値を
変数「spell_target_no」に格納しました。

 

spell_target_select関数も
同じように修正します。 

変更前

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: # 呪文の対象が味方、味方が複数にした時は味方単体の時に選択できるようにする(party)
(省略)
    elif chara.get_spell_target(player[btl_player].mas_spell[sel_spell_i]) == 1:
(省略)
    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: # 呪文の対象がモンスター全体
(省略)

変更後

def spell_target_select(key, player): # 呪文の対象を選択 player[btl_player]:呪文選択中のプレイヤー
    global idx, spell_target_i
    ent = False
    spell_target_no = -1
    if len(player[btl_player].mas_spell) != 0:
        spell_target_no = chara.get_spell_target(player[btl_player].mas_spell[sel_spell_i]) # 呪文の対象(0:味方単体,1:味方全員,2:敵単体,3:敵グループ,4:敵全体)

    if spell_target_no == 0: # 呪文の対象が味方、味方が複数にした時は味方単体の時に選択できるようにする(party)
(省略)
    elif spell_target_no == 1:
(省略)
    elif spell_target_no == 2: # 呪文の対象がモンスター単体
(省略)
        elif key[K_SPACE] or key[K_RETURN]: # 決定
            player[btl_player].target = monster[spell_target_i] # 攻撃の対象をセット
            ent = True
    elif spell_target_no == 3: # 呪文の対象がモンスターグループ
(省略)
        elif key[K_SPACE] or key[K_RETURN]: # 決定
            player[btl_player].target = spell_target_i # 攻撃の対象(グループなのでインデックス)をセット
            ent = True
    elif spell_target_no == 4: # 呪文の対象がモンスター全体
(省略)

この関数は他にも
少し修正を加えています。

elif key[K_SPACE] or key[K_RETURN]: # 決定
    player[btl_player].target = monster[spell_target_i] # 攻撃の対象をセット
    ent = True

targetは各キャラの対象を
格納する変数です。
こちらで追加した変数です。

elif key[K_SPACE] or key[K_RETURN]: # 決定
    player[btl_player].target = spell_target_i # 攻撃の対象(グループなのでインデックス)をセット
    ent = True

対象がグループの場合は
インデックスを格納します。
※後述の呪文発動参照

  

 

「じゅもん」を選択

コマンドで「じゅもん」を
選択する時に
使える呪文を覚えているか
確認します。

ここで、確認するので
後続での確認は不要と思います。

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

        elif idx == 11: # プレイヤーのターン(入力待ち)
(省略)

                    if COMMAND[btl_cmd_y][btl_cmd_x] == "じゅもん":
                        if len(player[btl_player].mas_spell) != 0:
                            idx = 21 # 呪文の選択
                            tmr = 0
                        else:
                            pass
if len(player[btl_player].mas_spell) != 0:
    idx = 21 # 呪文の選択
    tmr = 0
else:
    pass

使える呪文を覚えていたら
呪文選択(idx21)へ
移ります。

覚えていない場合、
ひとまず「pass」に
しています。

いずれ「呪文を覚えていない」
とか表示するように
できればと思っています。

 

 

使用呪文を格納

前回の最後の方に記載しましたが
複数人が回復呪文を使った場合、
使う呪文は最後のキャラが選択した呪文を
全員使うことになるバグがありましたので
これを修正します。

targetと同様に、chara.pyに
インスタンス変数を追加して、
そこに各キャラが
使う呪文を格納します。

chara.py

class Chara():
    def __init__(self):
        self.act = 0 # 戦闘のコマンド(行動)12:プレイヤー攻撃、13:モンスター攻撃、18:防御
        self.spell = "" # 戦闘コマンドで選択した呪文 ←追加
        self.target = 0 # 攻撃対象(オブジェクト)
self.spell = "" # 戦闘コマンドで選択した呪文 ←追加

を追加しました。

 

battle.py

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

        elif idx == 21: # コマンドで呪文を選択
(省略)
            if spell_select(key, player) == True:
                player[btl_player].spell = player[btl_player].mas_spell[sel_spell_i]
                idx = 25
                tmr = 0
player[btl_player].spell = player[btl_player].mas_spell[sel_spell_i]

呪文を選択したら
spellに格納します。

 

あとはこれを使って
呪文発動です。

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

        elif idx == 26: # 呪文発動
(省略)

            if tmr == 1:
                spell_blink = chara.get_spell_blink(turn_obj.spell) # 呪文演出(いろ) # spellを使う
                spell_blink = spell_blink.split(",")
                set_message(turn_obj.name + " は " + turn_obj.spell + " となえた!") # spellを使う
(省略)

            if tmr == 8:
                if turn_obj.check_mp(turn_obj.spell): # mpが足りていたら
                    spell_target_no = -1
                    if len(p.mas_spell) != 0: # 一応追加
                        spell_target_no = chara.get_spell_target(turn_obj.spell) # 呪文の対象(0:味方単体,1:味方全員,2:敵単体,3:敵グループ,4:敵全体)
                    if spell_target_no == 0: # 呪文の対象が味方単体
                        spell_point, spell_message = turn_obj.use_spell(turn_obj.spell, turn_obj.target, spell_target_no) # spellを使う
(省略)

                    elif spell_target_no == 1: # 呪文の対象が味方全体
                        for i, p in enumerate(player):
                            spell_point, spell_message = turn_obj.use_spell(turn_obj.spell, p, spell_target_no) # spellを使う
(省略)

spellに修正した行は
コメントに「spellを使う」を
追記しました。

 

以下は対象がモンスターの呪文です。

                    elif spell_target_no == 2: # 呪文の対象がモンスター単体
                        spell_point, spell_message = turn_obj.use_spell(turn_obj.spell, turn_obj.target, spell_target_no)
                        set_message(spell_message)
                        if spell_point != -1: # 攻撃系、-1は補助系
                            btl_exp += do_attack(turn_obj.target, spell_point, turn_obj)
                        check_monster()

                    elif spell_target_no == 3: # 呪文の対象がモンスターグループ
                        list_typ = mon_overlap() # 例{9:1、1:1}、→ [9, 1]を取得
                        for i, mon in enumerate(monster):
                            if mon.num == list_typ[turn_obj.target]: # グループの時だけturn_obj.targetにはインデックスが入っている
                                spell_point, spell_message = turn_obj.use_spell(turn_obj.spell, mon, spell_target_no)
                                set_message(spell_message)
                                if spell_point != -1: # 攻撃系、-1は補助系
                                    btl_exp += do_attack(mon, spell_point, turn_obj)
                                draw_battle(screen, fontS, turn_obj, player)
                                pygame.display.update()
                                pygame.time.delay(delay_speed)
                        check_monster()

                    elif spell_target_no == 4: # 呪文の対象がモンスター全体
                        for i, mon in enumerate(monster):
                            spell_point, spell_message = turn_obj.use_spell(turn_obj.spell, mon, spell_target_no)
                            set_message(spell_message)
                            if spell_point != -1: # 攻撃系、-1は補助系
                                btl_exp += do_attack(mon, spell_point, turn_obj)
                            draw_battle(screen, fontS, turn_obj, player)
                            pygame.display.update()
                            pygame.time.delay(delay_speed)
                        check_monster()

elif spell_target_no == 2: # 呪文の対象がモンスター単体
    spell_point, spell_message = turn_obj.use_spell(turn_obj.spell, turn_obj.target, spell_target_no)

use_spellの引数を
turn_obj.spell, turn_obj.target
に修正しています。

btl_exp += do_attack(turn_obj.target, spell_point, turn_obj)

また、do_attack関数の引数も
インデックスからオブジェクトに
変わっている為、修正しています。
詳細はこちら

 

elif spell_target_no == 3: # 呪文の対象がモンスターグループ
    list_typ = mon_overlap() # 例{9:1、1:1}、→ [9, 1]を取得
    for i, mon in enumerate(monster):
        if mon.num == list_typ[turn_obj.target]: # グループの時だけturn_obj.targetにはインデックスが入っている
            spell_point, spell_message = turn_obj.use_spell(turn_obj.spell, mon, spell_target_no)

対象がグループの場合
turn_obj.targetにはインデックスが
入っています。

use_spellの引数は
turn_obj.targetではなく
モンスターオブジェクト(mon)に
しています。
※使う呪文もspellに修正しています。

btl_exp += do_attack(mon, spell_point, turn_obj)

do_attack関数は先程と同じように
引数をオブジェクト(mon)に修正しています。

 

elif spell_target_no == 4: # 呪文の対象がモンスター全体
    for i, mon in enumerate(monster):
        spell_point, spell_message = turn_obj.use_spell(turn_obj.spell, mon, spell_target_no)
        set_message(spell_message)
        if spell_point != -1: # 攻撃系、-1は補助系
            btl_exp += do_attack(mon, spell_point, turn_obj)

対象が全体も同様です。

 

 

btl_playerに修正

最後にplayer[0]をplayer[btl_player]に
修正します。

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

    elif idx == 21 or idx == 25:
(省略)

        if (sel_spell_p+1)*SPELL_SHOW_NUM > len(player[btl_player].mas_spell): # btl_playerに修正
            end_i = len(player[btl_player].mas_spell) # btl_playerに修正
        else:
            end_i = (sel_spell_p+1)*SPELL_SHOW_NUM
        for i, spell in enumerate(player[btl_player].mas_spell[sel_spell_p*SPELL_SHOW_NUM:end_i]): # btl_playerに修正
(省略)

        # 呪文の説明
        if len(player[btl_player].mas_spell) != 0:
            tmp_explain = chara.get_spell_explain(player[btl_player].mas_spell[tmp_sel_spell_i]).split("\n") # btl_playerに修正
            for i, tmp in enumerate(tmp_explain):
                draw_text(bg, "{}".format(tmp), x_i_t, y_i_t+y_h*i, fnt, col)
            # 呪文の消費MP/残りMP
            draw_text(bg, "{}/{}".format(chara.get_spell_usemp(player[btl_player].mas_spell[tmp_sel_spell_i]), player[btl_player].maxmp), x_i_t, bg.get_height()*0.9+20, fnt, col) # btl_playerに修正
(省略)

def spell_select(key, player): # 呪文を選択
(省略)

    max_p = len(player[btl_player].mas_spell)//SPELL_SHOW_NUM # btl_playerに修正
(省略)

    elif key[K_DOWN] and sel_spell_y < 3 and tmp_sel_spell_i+2 < len(player[btl_player].mas_spell): # btl_playerに修正
        sel_spell_y += 1
(省略)

        tmp_sel_spell_i = sel_spell_x+sel_spell_y*2+sel_spell_p*SPELL_SHOW_NUM
        if tmp_sel_spell_i >= len(player[btl_player].mas_spell): # btl_playerに修正
            if len(player[btl_player].mas_spell)%2 != 0: # btl_playerに修正
                sel_spell_x = 0
        # 行の確認・修正
        while True:
            tmp_sel_spell_i = sel_spell_x+sel_spell_y*2+sel_spell_p*SPELL_SHOW_NUM
            if tmp_sel_spell_i > len(player[btl_player].mas_spell): # btl_playerに修正
                sel_spell_y -= 1
            else:
                break
    elif key[K_RIGHT] and sel_spell_x < 1 and tmp_sel_spell_i+1 < len(player[btl_player].mas_spell): # btl_playerに修正
        sel_spell_x += 1
    elif key[K_RIGHT] and sel_spell_x == 1 and sel_spell_p < max_p: # →キー ページが最大でなければページを変える
        sel_spell_x = 0
        sel_spell_p += 1
        # ページ遷移後に覚えた呪文のmax数を超えたか、超えていれば行を少なくする
        while True:
            tmp_sel_spell_i = sel_spell_x+sel_spell_y*2+sel_spell_p*SPELL_SHOW_NUM
            if tmp_sel_spell_i >= len(player[btl_player].mas_spell): # btl_playerに修正
                sel_spell_y -= 1
            else:
                break
(省略)

 

修正した行は
「# btl_playerに修正」の
コメントを追記しました。

という感じで、今回は以上です!(`・ω・´)

 

 

最後に

仲間を追加することで
必要となった修正は
今回で一段落ですが、
次回も引き続き修正しようと思います。

まとめサイトへ

 

 

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

 

 

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

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