見出し画像

疑似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() はキーがなければデフォルト値を返してくれるので安全。

まとめ

今回追加した装備システムの全体像はこうなっています。

今のところ武器防具一種類ずつですが、アクセサリー枠も欲しいかなと思ってます
UIも少し整えました
WEAPON_DATA / ARMOR_DATA   ← データ定義
        ↓
Player.equip_weapon/armor  ← 誰が何を装備しているか
Player.effective_attack    ← 装備込みの実効値
        ↓
Battle(戦闘計算)          ← effective値を使ってダメージ計算
        ↓
Party.equipment_bag        ← 購入した装備の在庫
        ↓
ショップ/そうび画面        ← 購入・装備変更のUI

装備システムが実装されるとかなりRPGらしくなってきました。現在はグラフィックの用意に試行錯誤していてちょっと政策スピードが落ち気味ですが、納得のいく形にしたいのでじっくりやっていこうと思います。

いいなと思ったら応援しよう!

しん もし記事が参考になったり、開発を応援してもいいと思ってくれた方がいたら、noteのサポートをいただけると次の記事を書く原動力になります。もちろん読んでくれるだけで十分嬉しいです。