疑似3DダンジョンRPG開発日誌04 ── 装備システムの実装
自作の疑似3DダンジョンRPG「グラヴェンの傷跡」に、武器・防具の装備システムを追加した記録です。
やったこと①:武器・防具データを辞書で追加
まず「どんな装備があるか」をデータとして定義しました。 アイテムと同じように辞書(dict)で管理します。
python
WEAPON_DATA = {
"W01": {"name": "錆びたショートソード", "atk": 2, "price": 0, "desc": "誰かが落とした古い剣。"},
"W02": {"name": "職人のナイフ", "atk": 4, "price": 50, "desc": "ルーカス製。頑丈が売り。"},
# ...
}
ARMOR_DATA = {
"A01": {"name": "旅人の服", "def_": 1, "price": 0, "desc": "辿り着いた時の服。"},
"A02": {"name": "厚手の皮鎧", "def_": 2, "price": 40, "desc": "最低限の防具。"},
# ...
}キーを "W01" "A01" のようなIDにしておくと、誰が何を装備しているかをIDで管理できて便利です。
やったこと②:PlayerクラスにEquipスロットを追加
1人のキャラクターを管理する Player クラスに、装備スロットを追加しました。
python
class Player:
def __init__(self):
# ...
self.equip_weapon = None # 武器スロット("W01" などのID、未装備はNone)
self.equip_armor = None # 防具スロットそして「装備込みの実際の攻撃力・防御力」を返すプロパティも追加しています。
python
@property
def effective_attack(self):
bonus = 0
if self.equip_weapon and self.equip_weapon in WEAPON_DATA:
bonus = WEAPON_DATA[self.equip_weapon]["atk"]
return self.attack + bonus
@property
def effective_defense(self):
bonus = 0
if self.equip_armor and self.equip_armor in ARMOR_DATA:
bonus = ARMOR_DATA[self.equip_armor]["def_"]
return self.defense + bonus@property を使うと player.effective_attack のように普通の変数と同じ書き方で呼び出せます。メソッドっぽく () を付けなくていいのがポイントです。
装備を変更する equip() メソッドも追加しました。付け替えのときに「前の装備を返す」ので、外した装備を袋に戻す処理がシンプルに書けます。
python
def equip(self, slot, item_id):
if slot == "weapon":
old = self.equip_weapon
self.equip_weapon = item_id
return old # 前の装備IDを返す
elif slot == "armor":
old = self.equip_armor
self.equip_armor = item_id
return oldやったこと③:戦闘計算に装備ボーナスを反映
戦闘中のダメージ計算で、素のステータスではなく装備込みの実効値を使うように修正しました。
python
# 修正前
damage = max(1, actor.attack - self.enemy.defense)
# 修正後
damage = max(1, actor.effective_attack - self.enemy.defense)python
# 敵の攻撃を受けるとき
# 修正前
damage = max(1, self.enemy.attack - target.defense)
# 修正後
damage = max(1, self.enemy.attack - target.effective_defense)スキルによる物理攻撃も同様に effective_attack に統一しました。 これだけで「良い武器を装備するほど強くなる」が自動的に機能するようになります。
やったこと④:ショップにタブ切替を追加
もともとアイテムしか売っていなかったショップを、武器・防具も買えるように拡張しました。 左右キーでタブを切り替える UI です。
[ アイテム ] [ 武器 ] [ 防具 ] ← 左右キーで切替タブ番号を変数で管理して、タブに応じてリストを切り替えています。
python
self.shop_tab = 0 # 0=アイテム 1=武器 2=防具
if self.shop_tab == 0:
shop_list = [(k, v["price"], {"name": k, **v}) for k, v in ITEM_DATA.items()]
elif self.shop_tab == 1:
shop_list = [(k, v["price"], v) for k, v in WEAPON_DATA.items()]
else:
shop_list = [(k, v["price"], v) for k, v in ARMOR_DATA.items()]ここで少し注意点がありました。ITEM_DATA はキー自体が商品名なのに対し、WEAPON_DATA はキーがID("W01"など)で name が別にある、という構造の違いです。アイテムの側に {"name": k, **v} で name を追加することで統一しました。
やったこと⑤:装備袋(equipment_bag)システムの導入
「ショップで買ったらすぐ装備される」という簡易実装から、「買ったら袋に入り、あとで誰かに装備させる」 という方式に改良しました。
Party クラスに装備袋リストを追加します。
python
class Party:
def __init__(self):
self.members = [...]
self.equipment_bag = [] # 購入済み装備のIDリストセーブ・ロードにも対応させるため、to_dict と from_dict にも追記しています。
python
def to_dict(self):
return {
"members": [m.to_dict() for m in self.members],
"equipment_bag": self.equipment_bag, # ← 追加
}
def from_dict(self, data):
# ...
self.equipment_bag = data.get("equipment_bag", []) # ← 追加やったこと⑥:ポーズメニューに「そうび」画面を追加
ダンジョン内でも装備を付け替えられるよう、ポーズメニューに「そうび」コマンドを追加しました。
画面の遷移はこのような3ステップです。
① キャラ選択(誰の装備を変える?)
↓
② スロット選択(武器 or 防具?)
↓
③ 装備品選択(袋の中から選ぶ、「はずす」も選べる)装備を選んだときの処理はこのような流れです。
python
# 今の装備を袋に戻す
old = member.equip(slot, chosen)
if old:
self.party.equipment_bag.append(old)
# 選んだ装備を袋から取り出して装備
self.party.equipment_bag.remove(chosen)「はずす」を選んだ場合は装備をNoneにして、外したものを袋に戻します。
途中で出たエラーと解決方法
エラー①:KeyError: 'name'
ショップの描画処理で data["name"] を参照したとき、アイテムタブで発生しました。
原因: ITEM_DATA はキー自体が名前なので "name" というキーが存在しない。
解決: リストを作るときにアイテムだけ {"name": k, **v} で name を補完する。
エラー②:KeyError: 'desc'
選択中の商品説明を表示するとき、アイテムタブで発生しました。
原因: ITEM_DATA には "desc" キーがない。
解決: data["desc"] を data.get("desc", "") に変える。.get() はキーがなければデフォルト値を返してくれるので安全。
まとめ
今回追加した装備システムの全体像はこうなっています。


WEAPON_DATA / ARMOR_DATA ← データ定義
↓
Player.equip_weapon/armor ← 誰が何を装備しているか
Player.effective_attack ← 装備込みの実効値
↓
Battle(戦闘計算) ← effective値を使ってダメージ計算
↓
Party.equipment_bag ← 購入した装備の在庫
↓
ショップ/そうび画面 ← 購入・装備変更のUI装備システムが実装されるとかなりRPGらしくなってきました。現在はグラフィックの用意に試行錯誤していてちょっと政策スピードが落ち気味ですが、納得のいく形にしたいのでじっくりやっていこうと思います。
いいなと思ったら応援しよう!
もし記事が参考になったり、開発を応援してもいいと思ってくれた方がいたら、noteのサポートをいただけると次の記事を書く原動力になります。もちろん読んでくれるだけで十分嬉しいです。