見出し画像

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

前回の記事はこちら
前回はアイテムを買えるようにしました。

倉庫ウィンドウ

ショップの実装が一通り終わったので、次は倉庫を実装したいと思います。
今回の仕様は以下の通り。

・入れられるのは魔石以外のアイテムとコイン
・ダンジョン内で倒れても倉庫内のアイテムは残る
・アイテムは最大20〜50個程度入れられる(ゲーム進行度具合で変動)
・コインはほぼ無制限
・ソート機能

ただ、倉庫を実装するのには一つ問題があります。
それは2番目の項目からわかります。そう、倉庫はダンジョン内で倒れても何らかの形で生き返るからこそ活きるのです。ということは現在の「ダンジョン内で倒れたらそのままゲームオーバー」という仕様を変える必要が出てきます。
つまり筆者が言いたいのは、ゲームの仕様を倒れたら「生き返る」のか「ゲームオーバー」にするのか、どちらかを選ぶ必要が出てくる、ということです。
一長一短あるのでどちらを選ぶかは自由ですが、筆者は説明の為に前者を採用します。後者を選んだ方は倉庫の実装の段は飛ばして頂いて構いません。こんな風に実装するんだな、ぐらいに流して下さい。
さて、前置きが長くなってしまいましたが、とりあえずウィンドウの外形から作成していくことにします。イメージはこちら。

倉庫サンプル

これをUnityエディター上で再現します。筆者はこうなりました。

スクリーンショット 2020-11-08 16.18.34

スクリーンショット 2020-11-08 16.17.00

MainSceneのステータス画面の装備品表示箇所をプレハブ化することにしました。それがItemImageです。更にそれを含んだWareHouseSlotもプレハブを作成しました。これにはScrollItemをアタッチしておいて下さい。
ちなみにContentsにあたるオブジェクトにGrid Layoutコンポーネントをアタッチすると配置が楽です。

倉庫ウィンドウを表示する

それでは倉庫ウィンドウを表示したいと思います。
「WareHouseAction」スクリプトを作成して下さい。以下のように記述します。

using UnityEngine;

public class WareHouseAction : MonoBehaviour
{
   public ItemInventory itemInventory;
   public float inputHoldDelay = 0.3f;

   private EAct action = EAct.KeyInput;
   private bool isOpen = false;
   private Item selectItem = null;
   private float inputTime = 0;

   // 独自の更新メソッド
   public void Proc(bool isAction = false)
   {
       switch (action)
       {
           case EAct.KeyInput: KeyInput(isAction); break;
           case EAct.ActBegin: ActBegin(); break;
           case EAct.Act: Act(); break;
           case EAct.ActEnd: ActEnd(); break;
           case EAct.MoveBegin: MoveBegin(); break;
           case EAct.Move: Move(); break;
           case EAct.MoveEnd: MoveEnd(); break;
           case EAct.TurnEnd: TurnEnd(); break;
       }
   }

   /**
   * 現在の行動状態を返す
   */
   public EAct GetAction() => action;

   /**
   * 倉庫画面を開く
   */
   public void OpenWindow()
   {
       action = EAct.MoveBegin;
   }

   /**
   * 選択するアイテムスロットを変更する
   */
   private bool MoveSelectItem()
   {
       return true;
   }

   /**
   * アイテムを選択
   */
   private void SelectItem()
   {
       if (KeyConfig.GetKeyDown(KeyConfig.EType.WAREHOUSEACTION))
       {
           
       }
   }

   /**
   * アイテムの選択を解除
   */
   private void UnSelectItem()
   {
       if (KeyConfig.GetKeyDown(KeyConfig.EType.WAREHOUSECANCEL))
       {
           selectItem = null;
       }
   }


   /**
   * 待機中
   */
   private void KeyInput(bool isAction)
   {
       if (!isOpen && isAction)
           OpenWindow();
       else if (isOpen && KeyConfig.GetKeyDown(KeyConfig.EType.WAREHOUSECLOSE))
           OpenWindow();
   }

   /**
   * アクションを始める
   */
   private void ActBegin()
   {
       if (selectItem == null)
       {
           bool isCursorMoving = !MoveSelectItem();
           if (isCursorMoving) return;
           KeyInput(false);
           SelectItem();
       }
       else
       {
           UnSelectItem();
       }
   }

   /**
   * アクション中
   */
   private void Act()
   {
       action = EAct.MoveBegin;
   }

   /**
   * アクションが終わった
   */
   private void ActEnd()
   {
       action = EAct.TurnEnd;
   }

   /**
   * 移動を始める
   */
   private void MoveBegin()
   {
       isOpen = !isOpen;
       if (isOpen)
       {
           gameObject.SetActive(true);
       }
       action = EAct.Move;
   }

   /**
   * 移動中
   */
   private void Move()
   {
       action = EAct.MoveEnd;
   }

   /**
   * 移動が終わった
   */
   private void MoveEnd()
   {
       if (isOpen) action = EAct.ActBegin;
       else
       {
           gameObject.SetActive(false);
           action = EAct.TurnEnd;
       }
   }

   /**
   * ターンが終わった
   */
   private void TurnEnd()
   {
       action = EAct.KeyInput;
   }
}

これをWareHouseWindowにアタッチしておいて下さい。
KeyConfigクラスに追記します。

// 倉庫画面操作
WAREHOUSEMOVELEFT = KeyCode.LeftArrow,
WAREHOUSEMOVERIGHT = KeyCode.RightArrow,
WAREHOUSEMOVEUP = KeyCode.UpArrow,
WAREHOUSEMOVEDOWN = KeyCode.DownArrow,
WAREHOUSEACTION = KeyCode.Space,
WAREHOUSECANCEL = KeyCode.Escape,
WAREHOUSECLOSE = KeyCode.Escape

更にSequenceManagerInTownクラスを変更します。

using UnityEngine;

public class SequenceManagerInTown : MonoBehaviour
{
   public PlayerMovementInTown playerMovement;
   public InventoryActionInTown inventoryAction;
   public ShopAction shopAction;
   public WareHouseAction wareHouseAction;

   private void Update()
   {
       EAct act = inventoryAction.GetAction();
       if (act != EAct.KeyInput)
       {
           inventoryAction.Proc();
           return;
       }
       act = shopAction.GetAction();
       if (act != EAct.KeyInput)
       {
           shopAction.Proc();
           return;
       }
       act = wareHouseAction.GetAction();
       if (act != EAct.KeyInput)
       {
           wareHouseAction.Proc();
           return;
       }
       if (KeyConfig.GetKeyDown(KeyConfig.EType.FACILITYACTION))
       {
           switch (playerMovement.facility)
           {
               case "Shop":
                   shopAction.Proc(true);
                   return;
               case "Inn":
                   wareHouseAction.Proc(true);
                   return;
           }
       }
       inventoryAction.Proc();
       act = inventoryAction.GetAction();
       if (act != EAct.KeyInput) return;
       playerMovement.Move();
   }
}

実行する前に宿屋の範囲を指定する平面を用意し、Player Movement In Townコンポーネントに設定しておくことを忘れないようにして下さい。
(Ware House ActionコンポーネントのItem Inventoryの項目には今のところは何も設定しなくてもいいです)
それではテストプレイしてみます。

スクリーンショット 2020-11-08 17.21.03

指定した範囲内でスペースキーを押すと倉庫画面が表示されます。閉じることもできるか確認しておいて下さい。

倉庫画面でカーソルを動かす

最後に倉庫画面でカーソルを動かしてみたいと思います。ItemSlotDisplayなどがそのまま使えれば良かったのですが、これらは縦移動には対応していません。なので新しくスクリプトを作成し、そこに改めてカーソルを動かす処理を書いていきたいと思います。
名前は「WareHouseSlotView」です。

using UnityEngine;

public class WareHouseSlotView : MonoBehaviour
{
   public GameObject content;
   public int column = 6;

   private int selectItemIndex = 0;

   // Start is called before the first frame update
   void Start()
   {
       ScrollItem[] contents = content.GetComponentsInChildren<ScrollItem>();
       if (contents.Length > 0)
           contents[selectItemIndex].SetSelected(true);
   }

   /**
   * EDirを受け取って、その方向にカーソルを動かす
   */
   public bool MoveSelect(EDir d)
   {
       ScrollItem[] contents = content.GetComponentsInChildren<ScrollItem>();
       if (contents.Length < 1) return true;
       selectItemIndex = GetSelectItemIndexFor(contents);
       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) % contents.Length;
       }
       if (d == EDir.Up)
       {
           selectItemIndex = (selectItemIndex + contents.Length - column) % contents.Length;
       }
       contents[selectItemIndex].SetSelected(true);
       return true;
   }

   /**
   * 選択されているアイテムのインデックスを返す
   */
   public int GetSelectItemIndex() => selectItemIndex;

   /**
   * 配列から選択されているアイテムのインデックスを返す
   */
   private int GetSelectItemIndexFor(ScrollItem[] contents)
   {
       for (int i = 0; i < contents.Length; i++)
       {
           if (contents[i].GetSelected()) return i;
       }
       return 0;
   }
}

ビルドしたら、WareHouseWindow階層下のWindowにアタッチしましょう。
更にWareHouseActionクラスも変更します。

// パラメーターを追加
public WareHouseSlotView display;

// メソッドに追記
private bool MoveSelectItem()
{
   if (Input.anyKeyDown) inputTime = 0;
   if (KeyConfig.GetKeyDown(KeyConfig.EType.WAREHOUSEMOVELEFT))
       return display.MoveSelect(EDir.Left);
   if (KeyConfig.GetKeyDown(KeyConfig.EType.WAREHOUSEMOVERIGHT))
       return display.MoveSelect(EDir.Right);
   if (KeyConfig.GetKeyDown(KeyConfig.EType.WAREHOUSEMOVEUP))
       return display.MoveSelect(EDir.Up);
   if (KeyConfig.GetKeyDown(KeyConfig.EType.WAREHOUSEMOVEDOWN))
       return display.MoveSelect(EDir.Down);
   inputTime += Time.deltaTime;
   if (inputTime < inputHoldDelay) return true;
   if (!Input.anyKey) return true;
   inputTime = 0;
   if (KeyConfig.GetKey(KeyConfig.EType.WAREHOUSEMOVELEFT))
       return display.MoveSelect(EDir.Left);
   if (KeyConfig.GetKey(KeyConfig.EType.WAREHOUSEMOVERIGHT))
       return display.MoveSelect(EDir.Right);
   if (KeyConfig.GetKey(KeyConfig.EType.WAREHOUSEMOVEUP))
       return display.MoveSelect(EDir.Up);
   if (KeyConfig.GetKey(KeyConfig.EType.WAREHOUSEMOVEDOWN))
       return display.MoveSelect(EDir.Down);
   return true;
}

実行してみます。以下のようにカーソルを移動できればOKです。

スクリーンショット 2020-11-08 18.13.21

今回はここまでです。
次回は実際に倉庫内のアイテムを表示できるようにしたいと思います。

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