こんにちは。
「Pythonでつくる ゲーム開発 入門講座」の
Chapter11,12(本格RPGを作ろう!全編・後編)を基にRPGを作っていきます。
前回は一つのみですが、回復呪文を使えるように変更しました。
今回は攻撃呪文を使えるように変更します。
前回、作成したメソッドは1つの呪文しか使えませんが、
色々な呪文が使える汎用的なメソッドにします。
目次
呪文シートを作成
スプレッドシートの内容を変更します。
今まではキャラのシートに呪文の項目を入れていましたが
新しく呪文のシートを作成します。
変更前(キャラシート)

変更後(キャラシート)

M列はそのレベルになったら覚える呪文です。
新規(呪文シート)

呪文シートに新しく「上限」「下限」の項目を
追加しました。
呪文を使った時の回復するダメージ、与えるダメージを
下限〜上限の間でランダムな値にします。
前回も使ったrandintを使います。
randintの詳細はこちら。
random.randint(下限, 上限)
スプレッドシートの変更は以上です。
呪文シートを読み込む
先ほど作成した呪文シートの値を読み込む為に
chara.pyを変更します。
ws_chara = wb.worksheet("キャラ")
ws_mon = wb.worksheet("モンスター") ws_mon = wb.worksheet("モンスター")
ws_spell = wb.worksheet("呪文") # 追加
(省略)
# chara1_usemp = ws_chara.col_values(14) # 削除(消費MP)
# chara1_spell_target = ws_chara.col_values(15) # 削除(呪文のターゲット)
# chara1_spell_explain = ws_chara.col_values(16) # 削除(呪文の説明)
(省略)
(以下追加)
spell_name = ws_spell.col_values(1) # A列
spell_usemp = ws_spell.col_values(2) # B列 消費MP
spell_lo = ws_spell.col_values(3) # C列 上限
spell_up = ws_spell.col_values(4) # D列 下限
spell_explain = ws_spell.col_values(5) # E列 呪文の説明
spell_target = ws_spell.col_values(6) # F列 ターゲット
spell_usemp_dict = {}
spell_lo_dict = {}
spell_up_dict = {}
spell_explain_dict = {}
spell_target_dict = {}
for i, tmp in enumerate(spell_name[1:], 1):
spell_usemp_dict.setdefault(tmp, int(spell_usemp[i]))
spell_lo_dict.setdefault(tmp, int(spell_lo[i]))
spell_up_dict.setdefault(tmp, int(spell_up[i]))
spell_explain_dict.setdefault(tmp, spell_explain[i])
spell_target_dict.setdefault(tmp, int(spell_target[i]))
class Chara():
(省略)
def get_spell_usemp(self, str_spell): # 消費MPを返す
return spell_usemp_dict[str_spell]
def get_spell_explain(self, str_spell): # 呪文の説明を返す
return spell_explain_dict[str_spell]
def get_spell_target(self, str_spell): # ターゲットを返す
return spell_target_dict[str_spell]
「以下追加」のところから変数を追加して
呪文のシートの値を取得しています。
次に辞書型の変数を用意しました。
辞書型の詳細はこちら。
spell_usemp_dict = {}
spell_lo_dict = {}
spell_up_dict = {}
spell_explain_dict = {}
spell_target_dict = {}
spell_usemp_dict["ホイミ"] = 3
のようになるので、
使う呪文の消費MPを知りたい時などに使います。
辞書型の変数には
setdefaultを使って要素を追加します。
使い方は以下のような感じです。
spell_usemp_dict = {}
spell_usemp_dict.setdefault("ホイミ", 3)
print(spell_usemp_dict)
# 結果
# {'ホイミ': 3}
このsetdefaultを使ってfor文で
各変数に要素を追加しています。
for i, tmp in enumerate(spell_name[1:], 1):
spell_usemp_dict.setdefault(tmp, int(spell_usemp[i]))
spell_lo_dict.setdefault(tmp, int(spell_lo[i]))
spell_up_dict.setdefault(tmp, int(spell_up[i]))
spell_explain_dict.setdefault(tmp, spell_explain[i])
spell_target_dict.setdefault(tmp, int(spell_target[i]))
1行目はシートの項目名の為、2行目から開始する為に
enumerate(spell_name[1:], 1)
としています。
enumerateの2つ目の引数を「1」にすると
「i」は1から始まります。
指定しない場合は0から始まります。
enumerateの詳細はこちら。
あとは各変数を取得する為に
get_spell_usemp
get_spell_explain
get_spell_target
のメソッドを追加しました。
引数のstr_spellは使う呪文です。
ホイミの時は
spell_usemp_dict["ホイミ"] → 3
となり、消費MPの3を返します。
消費MP、ターゲット、呪文の説明は
今までレベルアップした時に取得していましたが
上記のメソッドで取得する為、
以下のように削除します。
class Brave(Chara):
(省略)
def master_spell(self):
if chara1_spell[self.lv] != "": # レベルアップして覚える呪文があるなら
self.mas_spell.append(chara1_spell[self.lv])
self.usemp.append(chara1_usemp[self.lv]) # 削除
self.spell_explain.append(chara1_spell_explain[self.lv]) # 削除
self.spell_target.append(chara1_spell_target[self.lv]) # 削除
return chara1_spell[self.lv]
return ""
spellメソッド
前回、呪文ホイミのメソッドであるhoimiを
作成しましたが、新しく追加した変数を使って
汎用的なメソッドに変更します。
変更前
class Chara():
(省略)
def hoimi(self):
if self.mp < 3:
return -1 # MPが足りない
else:
self.mp -= 3 # 消費MP
return random.randint(30, 40) # 30-40回復
変更後
class Chara():
(省略)
def spell(self, str_spell):
if self.mp < spell_usemp_dict[str_spell]:
return -1 # MPが足りない
else:
self.mp -= spell_usemp_dict[str_spell] # 消費MP
return random.randint(spell_lo_dict[str_spell], spell_up_dict[str_spell])
def get_spell_usemp(self, str_spell):
return spell_usemp_dict[str_spell]
def get_spell_explain(self, str_spell):
return spell_explain_dict[str_spell]
def get_spell_target(self, str_spell):
return spell_target_dict[str_spell]
hoimiメソッドでは定数を使った為
ホイミのみにしか使えなかったですが
新しく追加した変数に置き換えることで
他の呪文でも使えるように変更しました。
消費MP(spell_usemp_dict)
下限(spell_lo_dict)
上限(spell_up_dict)
引数のstr_spellは使う呪文です。
ホイミの時は
spell_usemp_dict["ホイミ"] → 3
spell_lo_dict["ホイミ"] → 30
spell_up_dict["ホイミ"] → 40
となります。
randintを使って、
呪文を使った時の回復するダメージ、与えるダメージを
下限〜上限の間でランダムな値にします。
random.randint(spell_lo_dict[str_spell], spell_up_dict[str_spell])
戻り値はターゲットが味方の時は回復する値、
ターゲットがモンスターの時は与えるダメージの値
となります。
※get_spell_targetメソッドの戻り値で判定します。
戻り値が0 → ターゲットが味方
戻り値が1 → ターゲットがモンスター
chara.pyの変更は以上です。
追加したメソッドに置き換え
battle.pyを変更します。
まず、新しく追加したメソッドに置き換えます。
def draw_battle(bg, fnt, obj, player):
(省略)
else:
# 呪文対象が敵の時、呪文対象を表示させない(点滅)
if idx == 25 and i == spell_target_i and player.get_spell_target(player.mas_spell[sel_spell_i]) == 1 and tmr%5 == 0:
pass
else:
bg.blit(mon.img, [monster[i].x, monster[i].y])
(省略)
# 名前の表示(回復呪文の対象を選択中の時は点滅)
if idx == 25 and player.get_spell_target(player.mas_spell[sel_spell_i]) == 0: # 呪文の対象の選択中,呪文の対象が味方なら
draw_text(bg, "{}".format(player.name), x_i_t, y_i+6, fnt, BLINK[tmr%6])
(省略)
# 呪文の説明
tmp_explain = player.get_spell_explain(player.mas_spell[tmp_sel_spell_i]).split("\n")
(省略)
# 呪文の消費MP/残りMP
draw_text(bg, "{}/{}".format(player.get_spell_usemp(player.mas_spell[tmp_sel_spell_i]), player.maxmp), x_i_t, bg.get_height()*0.9+20, fnt, col)
(省略)
def spell_target_select(bg, key, player): # 呪文の対象を選択
global idx, spell_target_i
ent = False
if player.get_spell_target(player.mas_spell[sel_spell_i]) == 0: # 呪文の対象が味方
ターゲット
変更前:player.spell_target[sel_spell_i]
変更後:player.get_spell_target(player.mas_spell[sel_spell_i])
呪文の説明
変更前:spell_explain[tmp_sel_spell_i]
変更後:get_spell_explain(player.mas_spell[tmp_sel_spell_i])
消費MP
変更前:player.usemp[tmp_sel_spell_i]
変更後:player.get_spell_usemp(player.mas_spell[tmp_sel_spell_i])
としています。
player.mas_spell[sel_spell_i]
は使う呪文です。
※mas_spell:覚えた呪文
sel_spell_i:選択した呪文(添字)
新しく追加したメソッドの置き換えは以上です。
呪文発動
前回はホイミのみでしたが、
汎用的なメソッドに変更したspellメソッドを使って、
色々な呪文を発動します。
変更前
def main(screen, clock, font, fontS, player):
(省略)
elif idx == 26: # 呪文発動
draw_battle(screen, fontS, turn_obj, player)
if turn_obj.mas_spell[sel_spell_i] == "ホイミ":
if tmr == 1:
set_message(turn_obj.name + " は ホイミを となえた!")
re_dmg = turn_obj.hoimi()
if 2 <= tmr and tmr <= 4:
pygame.draw.rect(screen, BLINK[tmr%6], [0, 0, screen.get_width(), screen.get_height()])
if tmr == 5:
if re_dmg != -1:
player.hp += re_dmg
if player.hp > player.maxhp:
player.hp = player.maxhp
set_message(player.name + " の キズが かいふくした!")
else:
set_message("しかし MPがたりない!")
if tmr == 8:
init_message()
idx = 24 # ターンの確認
tmr = 0
変更後
def main(screen, clock, font, fontS, player):
(省略)
elif idx == 26: # 呪文発動
draw_battle(screen, fontS, turn_obj, player)
if tmr == 1:
set_message(turn_obj.name + " は " + turn_obj.mas_spell[sel_spell_i] + " となえた!")
dmg = turn_obj.spell(turn_obj.mas_spell[sel_spell_i])
if 2 <= tmr and tmr <= 4:
pygame.draw.rect(screen, BLINK[tmr%6], [0, 0, screen.get_width(), screen.get_height()])
if turn_obj.get_spell_target(turn_obj.mas_spell[sel_spell_i]) == 0:
if tmr == 5:
if dmg != -1:
player.hp += dmg
if player.hp > player.maxhp:
player.hp = player.maxhp
set_message(player.name + " の キズが かいふくした!")
else:
set_message("しかし MPがたりない!")
if turn_obj.get_spell_target(turn_obj.mas_spell[sel_spell_i]) == 1:
if tmr == 5:
if dmg != -1:
monster[spell_target_i].hp -= dmg
set_message(monster[btl_enemy].name + "に " + str(dmg)+"ポイントのダメージを与えた!")
if monster[spell_target_i].hp <= 0:
monster[spell_target_i].hp = 0
set_message(turn_obj.name + " は " + monster[spell_target_i].name + " をやっつけた!")
btl_exp += monster[spell_target_i].exp
del_battle_turn(monster[spell_target_i]) # ターンオブジェクトから消す(倒したモンスターは攻撃しない)
dead_monster.append(monster[spell_target_i]) # 先に加える
monster.pop(spell_target_i)
else:
set_message("しかし MPがたりない!")
if not monster:
idx = 16 # 勝利
tmr = 0
if tmr == 8:
init_message()
idx = 24 # ターンの確認
tmr = 0
汎用的なメソッドにしたので
if turn_obj.mas_spell[sel_spell_i] == "ホイミ":
が不要になります。
※やはりここに全ての呪文のパターンは
書けないですね(^_^;)
変更前
set_message(turn_obj.name + " は ホイミを となえた!")
re_dmg = turn_obj.hoimi()
変更後
set_message(turn_obj.name + " は " + turn_obj.mas_spell[sel_spell_i] + " となえた!")
dmg = turn_obj.spell(turn_obj.mas_spell[sel_spell_i])
上記のようにspellメソッドを使います。
戻り値は
ターゲットが味方:回復する値、
ターゲットがモンスター:与えるダメージの値
turn_obj.mas_spell[sel_spell_i]
は使う呪文です。
前回、追加したre_dmgは使わずに
回復も攻撃も値はdmgに入れます。
呪文のターゲットが味方の場合は
前回のホイミと同じです。
if turn_obj.get_spell_target(turn_obj.mas_spell[sel_spell_i]) == 0:
(回復する)
呪文のターゲットがモンスターの場合
モンスターにダメージを与えます。
dmgが-1の時はMPが足りない時です。
if turn_obj.get_spell_target(turn_obj.mas_spell[sel_spell_i]) == 1:
(モンスターにダメージを与える)
ダメージを与える動作は通常攻撃の時に似ています。
なので、同じ関数とかに出来るかもしれないですね(^_^)
elif idx == 12: # プレイヤーの攻撃
draw_battle(screen, fontS, turn_obj, player)
if tmr == 1:
set_message(turn_obj.name + " の攻撃!")
dmg = player.attack(monster[btl_enemy])
if 2 <= tmr and tmr <= 4:
screen.blit(imgEffect[0], [monster[btl_enemy].x+monster[btl_enemy].img.get_width()-tmr*80, tmr*80])
if tmr == 5:
emy_blink = 5
if dmg > 0:
set_message(monster[btl_enemy].name + "に " + str(dmg)+"ポイントのダメージを与えた!")
else:
set_message("ミス!" + monster[btl_enemy].name + "にダメージを与えられない!")
if tmr == 11:
monster[btl_enemy].hp = monster[btl_enemy].hp - dmg
if monster[btl_enemy].hp <= 0:
monster[btl_enemy].hp = 0
set_message(turn_obj.name + " は " + monster[btl_enemy].name + " をやっつけた!")
btl_exp += monster[btl_enemy].exp
del_battle_turn(monster[btl_enemy]) # ターンオブジェクトから消す(倒したモンスターは攻撃しない)
dead_monster.append(monster[btl_enemy]) # 先に加える
monster.pop(btl_enemy)
if not monster:
idx = 16 # 勝利
tmr = 0
if tmr == 16:
init_message()
idx = 24 # ターンの確認
tmr = 0
ご参考までに呪文を使っている様子を
動画にしました。
動画はこちらです。
という感じで、今回は以上です!(`・ω・´)
最後に
今回はメソッドを汎用的にして
攻撃呪文を使えるように変更しました。
次回も引き続き呪文を変更していこうと思います。
【ご注意】
プログラムやデータなどは著作権法により保護されています。
著作者の許諾を得ずに、プログラムおよびデータそのものまたは改変したものを
配布したり販売したりすることはできません。
また、これらを利用して発生した損害などに関して、著作者は一切責任を負いません。