見出し画像

【Unity】3Dローグライクゲームの作り方〜Step14-6〜

前回の記事はこちら
前回は倉庫の外形を作成しました。

倉庫の中身を表示する

今回は実際に倉庫の中身を表示するところから始めたいと思います。
「WareHouseDisplay」スクリプトを作成して下さい。そこに以下を記述します。

using UnityEngine;
using UnityEngine.UI;


public class WareHouseDisplay : MonoBehaviour
{
   public Inventory inventory;
   public GameObject content;

   private WareHouseSlotView view;
   private int prevViewSelectItemIndex;
   private int selectItemIndex;
   private int leadShowItemIndex = 0;
   private int maxShowItemNum;
   private int inventoryNum;

   // Start is called before the first frame update
   void Start()
   {
       view = GetComponentInChildren<WareHouseSlotView>();
       selectItemIndex = prevViewSelectItemIndex = view.GetSelectItemIndex();
   }

   /**
   * EDirを受け取って、その方向にカーソルを動かす
   */
   public bool MoveSelect(EDir d)
   {
       if (!view.MoveSelect(d)) return false;
       int viewSelectItemIndex = view.GetSelectItemIndex();
       ScrollItem[] contents = content.GetComponentsInChildren<ScrollItem>();
       if (viewSelectItemIndex == prevViewSelectItemIndex + 1)
       {
           if (viewSelectItemIndex > maxShowItemNum - 2 && selectItemIndex < inventoryNum - 2)
           {
               contents[0].transform.SetParent(null);
               contents[0].transform.SetParent(content.transform);
               leadShowItemIndex++;
               viewSelectItemIndex--;
               ShowItemInfo();
           }
       }
       if (prevViewSelectItemIndex == maxShowItemNum - 1 && viewSelectItemIndex == 0)
       {
           leadShowItemIndex = 0;
           ShowItemInfo();
       }
       if (viewSelectItemIndex == prevViewSelectItemIndex - 1)
       {
           if (viewSelectItemIndex < 1 && selectItemIndex > 1)
           {
               for (int i = 0; i < maxShowItemNum - 1; i++)
                   contents[i].transform.SetParent(null);
               for (int i = 0; i < maxShowItemNum - 1; i++)
                   contents[i].transform.SetParent(content.transform);
               leadShowItemIndex--;
               Vector3 moveDistance = contents[viewSelectItemIndex].GetBackDistance(false);
               viewSelectItemIndex++;
               ShowItemInfo();
           }
       }
       if (prevViewSelectItemIndex == 0 && viewSelectItemIndex == maxShowItemNum - 1)
       {
           leadShowItemIndex = inventoryNum - maxShowItemNum;
           ShowItemInfo();
       }
       selectItemIndex = leadShowItemIndex + viewSelectItemIndex;
       prevViewSelectItemIndex = viewSelectItemIndex;
       return true;
   }

   /**
   * インベントリを参照し、アイテムスロットを表示する
   */
   public void Show()
   {
       maxShowItemNum = content.transform.childCount;
       for (int i = inventory.itemNumMax; i < maxShowItemNum; i++)
           content.transform.GetChild(i).gameObject.SetActive(false);
       if (selectItemIndex == inventory.itemNumMax)
       {
           while (!MoveSelect(EDir.Right)) ;
           while (!MoveSelect(EDir.Left)) ;
       }
       inventoryNum = inventory.itemNumMax;
       maxShowItemNum = maxShowItemNum > inventoryNum ? inventoryNum : maxShowItemNum;
       ShowItemInfo();
   }

   /**
   * 現在選択しているアイテムスロットのアイテムを返す
   */
   public Item GetSelectItem() => inventory.Get(selectItemIndex);

   /**
   * アイテムスロットに情報を付け足す
   */
   private void ShowItemInfo()
   {
       for (int i = 0; i < maxShowItemNum; i++)
       {
           Transform slot = content.transform.GetChild(i);
           slot.gameObject.SetActive(true);
           int idx = i + leadShowItemIndex;
           Item it = inventory.Get(idx);
           if (it == null)
           {
               slot.GetChild(0).GetComponentInChildren<Text>().text = "";
               slot.GetChild(0).gameObject.SetActive(false);
           }
           else
           {
               slot.GetChild(0).GetComponentInChildren<Text>().text = it.name;
               slot.GetChild(0).gameObject.SetActive(true);
               slot.GetChild(0).GetComponent<Image>().sprite = Resources.Load<Sprite>("Sprites/" + it.sprite);
           }
       }
   }
}

とりあえずItemSlotDisplayクラスをほぼそのまま持ってくることにしました。これをWareHouseWindowにアタッチします。
また、WareHouseActionクラスも変更して下さい。

// WareHouseSlotViewを以下に書き換え
public WareHouseDisplay display;

テストする前に、宿屋もしくはそれに因んだオブジェクトにItemInventoryスクリプトをアタッチし、それをコンポーネントに設定しておきましょう。
実行してみます。

倉庫1

上記は所持可能数を20にし、事前にアイテムを入れられるだけ入れた状態になります。
少し表示がおかしいですね。これは横一列のスクロール機能をほぼそのまま再利用したのが原因です。一応このままでも使えないことはないですが、見栄えが悪いので修正します。
WareHouseDisplayクラスを変更して下さい。

using UnityEngine;
using UnityEngine.UI;


public class WareHouseDisplay : MonoBehaviour
{
   public Inventory inventory;
   public GameObject content;

   private WareHouseSlotView view;
   private int selectItemIndex;
   private int leadShowItemIndex = 0;
   private int maxShowItemNum;

   // Start is called before the first frame update
   void Start()
   {
       view = GetComponentInChildren<WareHouseSlotView>();
       selectItemIndex = view.GetSelectItemIndex();
   }

   /**
   * EDirを受け取って、その方向にカーソルを動かす
   */
   public bool MoveSelect(EDir d)
   {
       int viewSelectItemIndex = view.GetSelectItemIndex();
       content.GetComponentsInChildren<ScrollItem>()[viewSelectItemIndex].SetSelected(false, true);
       bool isMove = true;
       switch (d)
       {
           case EDir.Left:
               if (viewSelectItemIndex + leadShowItemIndex == 0)
               {
                   if (inventory.itemNumMax % maxShowItemNum == 0)
                       leadShowItemIndex = inventory.itemNumMax - maxShowItemNum;
                   else
                       leadShowItemIndex = inventory.itemNumMax - inventory.itemNumMax % maxShowItemNum;
               }
               else if (viewSelectItemIndex == 0)
                   leadShowItemIndex -= maxShowItemNum;
               break;
           case EDir.Right:
               if (viewSelectItemIndex + leadShowItemIndex == inventory.itemNumMax - 1)
               {
                   leadShowItemIndex = 0;
                   while (view.GetSelectItemIndex() > 0) view.MoveSelect(d);
                   isMove = false;
               }
               else if (viewSelectItemIndex == maxShowItemNum - 1)
               {
                   leadShowItemIndex += maxShowItemNum;
                   while (view.GetSelectItemIndex() > 0) view.MoveSelect(d);
                   isMove = false;
               }
               break;
           case EDir.Up:
               if (viewSelectItemIndex + leadShowItemIndex < view.column)
               {
                   if (inventory.itemNumMax % maxShowItemNum == 0)
                       leadShowItemIndex = inventory.itemNumMax - maxShowItemNum;
                   else
                       leadShowItemIndex = inventory.itemNumMax - inventory.itemNumMax % maxShowItemNum;
                   Show();
               }
               else if (viewSelectItemIndex < view.column)
                   leadShowItemIndex -= maxShowItemNum;
               break;
           case EDir.Down:
               if ((GetPageNum() == GetPageNumMax() - 1) &&
                   (viewSelectItemIndex >= ((inventory.itemNumMax - leadShowItemIndex) / view.column - 1) * view.column))
               {
                   leadShowItemIndex = 0;
                   Show();
                   viewSelectItemIndex %= view.column;
                   while (view.GetSelectItemIndex() != viewSelectItemIndex)
                       view.MoveSelect(EDir.Left);
                   content.GetComponentsInChildren<ScrollItem>()[viewSelectItemIndex].SetSelected(true);
                   isMove = false;
               }
               else if (viewSelectItemIndex > maxShowItemNum - view.column - 1)
               {
                   leadShowItemIndex = maxShowItemNum * ((GetPageNum() + 1) % GetPageNumMax());
               }
               break;
       }
       Show();
       if (isMove) view.MoveSelect(d);
       Show();
       selectItemIndex = leadShowItemIndex + view.GetSelectItemIndex();
       return true;
   }

   /**
   * インベントリを参照し、アイテムスロットを表示する
   */
   public void Show()
   {
       maxShowItemNum = content.transform.childCount;
       for (int i = 0; i < maxShowItemNum; i++)
           content.transform.GetChild(i).gameObject.SetActive(true);
       for (int i = inventory.itemNumMax - leadShowItemIndex; i < maxShowItemNum; i++)
           content.transform.GetChild(i).gameObject.SetActive(false);
       int inventoryNum = inventory.itemNumMax;
       maxShowItemNum = maxShowItemNum > inventoryNum ? inventoryNum : maxShowItemNum;
       ShowItemInfo();
   }

   /**
   * 現在選択しているアイテムスロットのアイテムを返す
   */
   public Item GetSelectItem() => inventory.Get(selectItemIndex);

   /**
   * 現在のページ数を返す
   */
   public int GetPageNum() => leadShowItemIndex / maxShowItemNum;

   /**
   * 最大のページ数を返す
   */
   public int GetPageNumMax() => Mathf.CeilToInt((float)inventory.itemNumMax / (float)maxShowItemNum);

   /**
   * アイテムスロットに情報を付け足す
   */
   private void ShowItemInfo()
   {
       for (int i = 0; i < maxShowItemNum; i++)
       {
           Transform slot = content.transform.GetChild(i);
           int idx = i + leadShowItemIndex;
           Item it = inventory.Get(idx);
           if (it == null)
           {
               slot.GetChild(0).GetComponentInChildren<Text>().text = "";
               slot.GetChild(0).gameObject.SetActive(false);
           }
           else
           {
               slot.GetChild(0).GetComponentInChildren<Text>().text = it.name;
               slot.GetChild(0).gameObject.SetActive(true);
               slot.GetChild(0).GetComponent<Image>().sprite = Resources.Load<Sprite>("Sprites/" + it.sprite);
           }
       }
   }
}

更にWareHouseSlotViewクラスも変更します。

public bool MoveSelect(EDir d)
{
   ScrollItem[] contents = content.GetComponentsInChildren<ScrollItem>();
   if (contents.Length < 1) return true;
   if (d == EDir.Right)
       selectItemIndex = (selectItemIndex + 1) % contents.Length;
   if (d == EDir.Left)
       selectItemIndex = (selectItemIndex + contents.Length - 1) % contents.Length;
   if (d == EDir.Down)
   {
       selectItemIndex =
           (selectItemIndex + column) % (Mathf.CeilToInt((float)contents.Length / (float)column) * column);

       if (selectItemIndex > contents.Length - 1) selectItemIndex = contents.Length - 1;
   }
   if (d == EDir.Up)
   {
       selectItemIndex = (selectItemIndex + (Mathf.CeilToInt((float)contents.Length / (float)column) * column) - column) %
           (Mathf.CeilToInt((float)contents.Length / (float)column) * column);
       if (selectItemIndex > contents.Length - 1) selectItemIndex = contents.Length - 1;
   }
   contents[selectItemIndex].SetSelected(true);
   return true;
}

実行してみます。

倉庫2

上記は倉庫のインベントリの所持可能数を50にした場合です。
これはもっといい実装方法がありそうですね......。まあ動くのでよしとしましょう。

というところで今回はここまでです。次回は倉庫からアイテムを入れたり出したりする予定です。

この記事が気に入ったらサポートをしてみませんか?