バーチャル3Dクリエイター神部まゆみです(*^_^*)
この記事はUnityで装備変更や使うメニューを実装したので、それについての記事です。
前回の記事はこちら。
動作確認した最新バージョンは Unity 6000.3.1 です。
やりたいこと:アイテムメニューに装備と使うボタンを作り、装備変更やアイテム消費を実装する
前回まででアイテムを捨てる・拾うまで実装できたので、今度は装備ボタンや使うボタンを実装したい。
ChatGPTパイセンに聞いてみる
とりあえず彼に聞けばなんとかなるだろう…。




じゃあまずアイテムメニュー欄に装備スロットを用意して、デフォルトで銃を装備している設定を実装したほうがいいですかね。まだアイテムを捨てる設定しか作っていないため、装備ボタンすらないのです


うん、その流れがいちばん気持ちいいし、あとあと楽になります。
いまのあなたの進み方を見てると、
「まず装備スロット」→「デフォルト装備」→「装備ボタン」
この順番がベストです。
① まず「装備スロット」を作る
インベントリとは別に、プレイヤー側にこういう枠を持たせます。
public ItemData equippedWeapon;
これが
「いま手に持ってる武器」。
Inventory は「持ち物」、
equippedWeapon は「今使ってるもの」
と役割を分けます。
② デフォルトで銃を装備
Player(または GameManager)に
[SerializeField] private ItemData defaultWeapon;
を用意して、Start で
void Start()
{
Equip(defaultWeapon);
}
これだけで
ゲーム開始時に銃を持っている状態になります。
③ アイテムメニューに「装備」ボタン
今ある「捨てる」の隣に置くのが自然です。
UI的にも
[ 装備 ]
[ 捨てる ]
って並ぶと直感的。
④ 装備ボタンがやること
選択中のアイテムを
- Inventory からは消さない
- equippedWeapon にセット
- 見た目の武器を切り替える
public void EquipSelected()
{
if (selectedItem == null) return;
if (selectedItem.weaponType != WeaponType.Gun &&
selectedItem.weaponType != WeaponType.Melee)
return;
player.Equip(selectedItem);
}
⑤ UI に「装備中」表示が出せる
ここが気持ちいいポイントです。
- 装備中のスロットに
- 枠の色
- 「E」マーク
- アイコン
をつけられる。
これ、あとでクイック切り替えにもそのまま使えます。
なぜこの順番がいいか
いきなりクイック切り替えを作ると👇
- 装備の概念が曖昧
- UI とロジックがズレる
- バグりやすい
でも
メニューで装備 → 攻撃が変わる
ができていれば、
ショートカットは「同じ処理を呼ぶだけ」になります。
ちょっと一気に進める感じだから少し大変そう?
でもこれができれば装備・使うのコアな部分が完成してしまうので、あとはメソッドを呼ぶだけでアイテム関連のほとんどは作れそうです。
実装していってみる
とりあえず実装していってみます。
ItemData.csを書き換える
ItemData.csを書き換え、アイテムタイプを追加します。
using UnityEngine;
[CreateAssetMenu(menuName = "Game/Item")]
public class ItemData : ScriptableObject
{
public string itemName;
public Sprite icon;
[TextArea]
public string description;
[Header("World Drop")]
public GameObject dropPrefab;
public ItemUseType useType;
public EquipSlot equipSlot;
public enum ItemUseType
{
None,
Equip, // 武器・防具
Consume // 回復など
}
}
これでアイテムタイプを指定できるようになったので設定しておきます。
後で装備するところまでやるので武器はEquipにしておく。


装備・使うボタンを配置する
アイテムタイプがEquip(武器・防具)なら装備ボタンを、回復アイテムなど使えるアイテムなら使うボタンを、素材などなら何も表示しないようにします。
そのため装備ボタンと使うボタンは同じ位置に配置しておく。とりあえず動作確認のために少しずらしておくけど。


以前作った詳細説明パネルの子に配置するけど、以前作った捨てるボタンをコピペして作るとラク。


アイテムスロットにE(テキストメッシュプロ)を配置する
現在はとりあえずアイテムスロットを8個設置しているけど、そのすべての子にEって書いたテキストメッシュプロを配置しておきます。
最初はスクリプトで非表示にし、装備されたアイテムにEを表示します。


EquipManager.csを作る
武器しか装備させないならここまでは必要ないかもしれないけど、後から防具やアクセサリとかも装備させたくなったら装備を管理するスクリプトがあったほうが良いので作っておきます。
using UnityEngine;
using System.Collections.Generic;
public class EquipManager : MonoBehaviour
{
public static EquipManager Instance;
// どの装備スロットに、インベントリの何番を装備しているか
private Dictionary<EquipSlot, int> equippedIndex = new();
void Awake()
{
if (Instance == null)
Instance = this;
else
Destroy(gameObject);
}
// そのスロットに装備されているインデックス(なければ -1)
public int GetEquippedIndex(EquipSlot slot)
{
return equippedIndex.TryGetValue(slot, out var index) ? index : -1;
}
// 装備する(インベントリの何番目かを渡す)
public void Equip(ItemData item, int inventoryIndex)
{
var slot = item.equipSlot;
equippedIndex[slot] = inventoryIndex;
Debug.Log($"装備: {item.itemName} (slot {slot}, index {inventoryIndex})");
}
// スロットから外す
public void Unequip(EquipSlot slot)
{
if (!equippedIndex.ContainsKey(slot)) return;
equippedIndex.Remove(slot);
Debug.Log($"外した: {slot}");
}
// このインベントリスロットは装備中?
public bool IsEquipped(EquipSlot slot, int inventoryIndex)
{
return equippedIndex.TryGetValue(slot, out var i) && i == inventoryIndex;
}
}
EquipSlot.csを作る
装備用のスクリプトを作っておく。これは作るだけでOK。
public enum EquipSlot
{
Weapon,
Head,
Body,
Arms,
Legs,
Accessory
}
ItemDetailPanel.csを書き換える
以前作ったItemDetailPanel.csを書き換えます。
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class ItemDetailPanel : MonoBehaviour
{
[SerializeField] private Image icon;
[SerializeField] private TMP_Text nameText;
[SerializeField] private TMP_Text descriptionText;
[SerializeField] private Inventory inventory;
[SerializeField] private ItemMenuController menuController;
private ItemData currentItem;
[SerializeField] private DropItemSpawner dropSpawner;
[SerializeField] private Button equipButton;
[SerializeField] private Button useButton;
[SerializeField] private Button dropButton;
private int currentSlotIndex;
public void Show(ItemData item, int slotIndex)
{
currentItem = item;
currentSlotIndex = slotIndex;
icon.sprite = item.icon;
nameText.text = item.itemName;
descriptionText.text = item.description;
bool isEquip = item.useType == ItemData.ItemUseType.Equip;
bool isUse = item.useType == ItemData.ItemUseType.Consume;
equipButton.gameObject.SetActive(isEquip);
useButton.gameObject.SetActive(isUse);
if (isEquip)
{
bool equipped = EquipManager.Instance.IsEquipped(item.equipSlot, slotIndex);
equipButton.GetComponentInChildren<TMP_Text>().text =
equipped ? "外す" : "装備";
}
gameObject.SetActive(true);
}
public void Hide()
{
currentItem = null;
gameObject.SetActive(false);
}
// ★捨てるボタン用
public void OnClickDrop()
{
if (currentItem == null) return;
dropSpawner.Drop(currentItem);
inventory.Remove(currentItem);
menuController.Refresh();
Hide();
}
public void OnClickEquip()
{
if (currentItem == null) return;
var slot = currentItem.equipSlot;
bool isEquipped = EquipManager.Instance.IsEquipped(slot, currentSlotIndex);
if (isEquipped)
{
EquipManager.Instance.Unequip(slot);
}
else
{
EquipManager.Instance.Equip(currentItem, currentSlotIndex);
}
menuController.Refresh();
Show(currentItem, currentSlotIndex);
}
public void OnClickUse()
{
if (currentItem == null) return;
Debug.Log($"{currentItem.itemName} を使用");
inventory.Remove(currentItem);
menuController.Refresh();
Hide();
}
}
ItemSlot.csを書き換える
ItemSlot.csも書き換えます。
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class ItemSlot : MonoBehaviour
{
[SerializeField] private Image icon;
[SerializeField] private GameObject normalFrame;
[SerializeField] private GameObject selectedFrame;
[SerializeField] private TMP_Text equippedText;
private ItemData currentItem;
public void SetSelected(bool selected)
{
normalFrame.SetActive(!selected);
selectedFrame.SetActive(selected);
}
public bool HasItem()
{
return currentItem != null;
}
public void SetItem(ItemData item, bool isEquipped)
{
currentItem = item;
if (item == null)
{
icon.enabled = false;
equippedText.gameObject.SetActive(false);
return;
}
icon.enabled = true;
icon.sprite = item.icon;
equippedText.gameObject.SetActive(isEquipped);
}
public ItemData GetItem()
{
return currentItem;
}
}
ItemMenuController.csを書き換える
ItemMenuController.csも書き換えます。
using UnityEngine;
public class ItemMenuController : MonoBehaviour
{
[SerializeField] private Inventory inventory;
[SerializeField] private ItemSlot[] slots;
private int selectedIndex = -1;
[SerializeField] private ItemDetailPanel detailPanel;
[SerializeField] private EquipManager equipManager;
public void SelectSlot(int index)
{
if (!slots[index].HasItem()) return;
if (selectedIndex >= 0)
slots[selectedIndex].SetSelected(false);
selectedIndex = index;
slots[selectedIndex].SetSelected(true);
var item = slots[index].GetItem();
detailPanel.Show(item, index);
}
void OnEnable()
{
Refresh();
}
public void Refresh()
{
int equippedIndex = equipManager.GetEquippedIndex(EquipSlot.Weapon);
for (int i = 0; i < slots.Length; i++)
{
ItemData item = i < inventory.items.Count ? inventory.items[i] : null;
bool isEquipped = (i == equippedIndex);
slots[i].SetItem(item, isEquipped);
}
}
}
インスペクターで設定する
新しい項目が増えているところがあるのでインスペクターで指定します。


MenuControllerにEquipManagerをアタッチし、ItemMenuControllerのEquipManagerに指定します。


8個のアイテムスロットにEを指定する。上で作ったテキストメッシュプロのやつ。


追加した装備ボタンと使うボタンのクリック時にItemDetailPanelのスクリプトを指定します。
装備はOnClickEquip()、使うはOnClickUse()で。
これで動いた!
これで装備が切り替えられましたね。
と言ってもまだハンドガンしか作っていないので、装備を切り替えてもグラフィックも何も変わらないけど(^_^;)
あと使って消費する処理も実装できました。まだ作りこんでないから消えるだけだけど。
つづく?
長いので少し戸惑ったけど、これで装備とアイテム消費の核となる機能は作れたので、あとはこれをベースに作っていけば行けそうです。
だいたいできたら武器やアイテムを作りこんでいく感じかなぁ。
また続きが書けたら追記します(*^_^*)



