こんにちは。
「Pythonでつくる ゲーム開発 入門講座」の
Chapter11,12(本格RPGを作ろう!全編・後編)を基にRPGを作っていきます。
前回は戦闘に関する修正で、回復など自身や仲間に使う呪文を使えるようにしました。
今回は攻撃など相手に使う呪文を使えるようにします。
目次
呪文の対象
攻撃など相手に使う呪文を選択した後、
対象(モンスター)を選択します。
その時に選択中の対象を点滅させます。
※今までもそうでしたが
仲間がいる時にも
正常に点滅するようにします。
変更前
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に修正」の
コメントを追記しました。
という感じで、今回は以上です!(`・ω・´)
最後に
仲間を追加することで
必要となった修正は
今回で一段落ですが、
次回も引き続き修正しようと思います。
【ご注意】
プログラムやデータなどは著作権法により保護されています。
著作者の許諾を得ずに、プログラムおよびデータそのものまたは改変したものを
配布したり販売したりすることはできません。
また、これらを利用して発生した損害などに関して、著作者は一切責任を負いません。