見出し画像

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

前回の記事はこちら
前回は拠点セーブを実装しました。

アイテム合成ウィンドウ

宿屋の実装が一応終わったので、次は酒場の仕様を決めたいと思います。
酒場でできることは今の所以下の予定です。

・アイテム合成
・情報収集(予定)

情報収集の方はひとまず置いておきましょう。
アイテムの合成方法は以下を考えています。

・一つの合成につき魔石を一つ使う
・一度に合成できるアイテムは3つまで
・合成レシピが存在する
・材料のアイテムは失う
・合成に成功するとそのアイテムが一つ手に入る
・失敗するとアイテムは手に入らない
・一度合成に成功したアイテムは記録される
・+値は使用するアイテムの+値で大きいものを上限にランダムに付与する

結構複雑そうですが頑張りましょう。
ということで手始めにアイテム合成ウィンドウから作成します。
イメージはこんな感じです。

アイテム合成画面サンプル

これをUnityエディタ上で再現したものがこちらです。

スクリーンショット 2020-11-18 6.54.36

ヒエラルキータブはこのようになっています。

スクリーンショット 2020-11-18 7.43.35

名前はCocktailSlotになっていますが、実態はWareHouseSlotからコピーして持ってきました。
また、CocktailWindowにはItemInventoryスクリプトをアタッチし、所持可能数を5にしておきます。

アイテム合成ウィンドウを開く

外形ができたところで酒場の前でアクションキーを押すとアイテム合成ウィンドウが開くようにします。
「CocktailWindowAction」スクリプトを作成して下さい。そこに、以下のように記述します。

using UnityEngine;
using UnityEngine.UI;

public class CocktailWindowAction : MonoBehaviour
{
   public InventoryActionInTown playerInventoryAction;
   public float inputHoldDelay = 0.3f;

   private EAct action = EAct.KeyInput;
   private bool isOpen = false;
   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 void KeyInput(bool isAction)
   {
       if (!isOpen && isAction)
           OpenWindow();
       else if (isOpen && KeyConfig.GetKeyDown(KeyConfig.EType.COCKTAILCLOSE))
           OpenWindow();
   }

   /**
   * アクションを始める
   */
   private void ActBegin()
   {
       KeyInput(false);
   }

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

   /**
   * アクションが終わった
   */
   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;
   }
}

これをCocktailWindowにあたるオブジェクトにアタッチしておいて下さい。
KeyConfig.ETypeに追記します。

// アイテム合成画面操作
COCKTAILMOVELEFT = KeyCode.LeftArrow,
COCKTAILMOVERIGHT = KeyCode.RightArrow,
COCKTAILMOVEUP = KeyCode.UpArrow,
COCKTAILMOVEDOWN = KeyCode.DownArrow,
COCKTAILACTION = KeyCode.Space,
COCKTAILCANCEL = KeyCode.Escape,
COCKTAILCLOSE = KeyCode.Escape,

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

// パラメーターを追記
public CocktailWindowAction cocktailWindowAction;

// メソッドを変更
private void Update()
{
   /*   省略   */
   // 以下6行を追記
   act = cocktailWindowAction.GetAction();
   if (act != EAct.KeyInput)
   {
       cocktailWindowAction.Proc();
       return;
   }
   if (KeyConfig.GetKeyDown(KeyConfig.EType.FACILITYACTION))
   {
       switch (playerMovement.facility)
       {
           case "Shop":
               shopAction.Proc(true);
               return;
           case "Inn":
               innAction.Proc(true);
               return;
           // 以下3行を追記
           case "Bar":
               cocktailWindowAction.Proc(true);
               return;
       }
   }
   inventoryAction.Proc();
   act = inventoryAction.GetAction();
   if (act != EAct.KeyInput) return;
   playerMovement.Move();
}

実行する前に、酒場にあたる場所に平面を配置し、Player Movement In Townコンポーネントに設定しておくことを忘れないようにして下さい。
実行してみます。

スクリーンショット 2020-11-18 9.05.13

酒場前でアクションキーを押すとアイテム合成画面が表示されました。
画面を閉じることもできるか確認しておきましょう。

アイテム合成場所でカーソルを動かす

アイテム合成をするところでカーソルを動かせるようにします。
CocktailWindowオブジェクト階層下のMainにあたるオブジェクトにWareHouseSlotViewスクリプトをアタッチします。そしてコンテンツにはMainを指定して下さい。
スクリプトを書きます。CocktailWindowActionクラスを変更して下さい。

// パラメーターを追加
public WareHouseSlotView mainView;
private bool isCursorMoving = false;
private Item selectItem = null;

// メソッドを追加
private bool MoveSelectItem()
{
   if (Input.anyKeyDown) inputTime = 0;
   if (KeyConfig.GetKeyDown(KeyConfig.EType.COCKTAILMOVELEFT))
       return mainView.MoveSelect(EDir.Left);
   if (KeyConfig.GetKeyDown(KeyConfig.EType.COCKTAILMOVERIGHT))
       return mainView.MoveSelect(EDir.Right);
   inputTime += Time.deltaTime;
   if (inputTime < inputHoldDelay) return true;
   if (!Input.anyKey) return true;
   inputTime = 0;
   if (KeyConfig.GetKey(KeyConfig.EType.COCKTAILMOVELEFT))
       return mainView.MoveSelect(EDir.Left);
   if (KeyConfig.GetKey(KeyConfig.EType.COCKTAILMOVERIGHT))
       return mainView.MoveSelect(EDir.Right);
   return true;
}

// メソッドを変更
private void ActBegin()
{
   if (isCursorMoving)
   {
       isCursorMoving = !MoveSelectItem();
       return;
   }
   if (selectItem == null)
   {
       isCursorMoving = !MoveSelectItem();
       if (isCursorMoving) return;
       KeyInput(false);
   }
}

実行してみます。下記のように左右キーでカーソルが移動できればOKです。

スクリーンショット 2020-11-18 16.28.33

アイテム合成場所にアイテムを入れる

最後にアイテム合成場所にアイテムを入れられるようにします。
まずCocktailWindowにWareHouseDisplayスクリプトをアタッチしておきます。
CocktailWindowActionクラスを変更して下さい。

// パラメーターを削除
public WareHouseSlotView mainView;

// パラメーターを追加
public ItemInventory itemInventory;
public WareHouseDisplay mainDisplayDisplay;

// メソッドを追加
/**
* アイテムスロットにアイテムを挿入する
* もし既に入っていたらそのアイテムを返す
*/
public Item ItemSlotInsertItem(Item it)
{
   int selectItemIndex = mainDisplay.GetSelectItemIndex();
   itemInventory.Insert(selectItemIndex, it);
   mainDisplay.Show();
   Item item = selectItem;
   return item;
}

/**
* アイテムを選択
*/
private void SelectItem()
{
   if (KeyConfig.GetKeyDown(KeyConfig.EType.COCKTAILACTION))
   {
       selectItem = mainDisplay.GetSelectItem();
       playerInventoryAction.OpenInventory(false, cocktailWindow:this);
       action = EAct.Act;
   }
}

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

// メソッドを変更
private bool MoveSelectItem()
{
   if (Input.anyKeyDown) inputTime = 0;
   if (KeyConfig.GetKeyDown(KeyConfig.EType.COCKTAILMOVELEFT))
       return mainDisplay.MoveSelect(EDir.Left);
   if (KeyConfig.GetKeyDown(KeyConfig.EType.COCKTAILMOVERIGHT))
       return mainDisplay.MoveSelect(EDir.Right);
   inputTime += Time.deltaTime;
   if (inputTime < inputHoldDelay) return true;
   if (!Input.anyKey) return true;
   inputTime = 0;
   if (KeyConfig.GetKey(KeyConfig.EType.COCKTAILMOVELEFT))
       return mainDisplay.MoveSelect(EDir.Left);
   if (KeyConfig.GetKey(KeyConfig.EType.COCKTAILMOVERIGHT))
       return mainDisplay.MoveSelect(EDir.Right);
   return true;
}

private void ActBegin()
{
   if (selectItem == null)
   {
       bool isCursorMoving = !MoveSelectItem();
       if (isCursorMoving) return;
       KeyInput(false);
       SelectItem();
   }
   else
   {
       UnSelectItem();
   }
}

private void Act()
{
   selectItem = null;
   action = EAct.ActBegin;
}

InventoryActionInTownクラスを変更します。

// パラメーターを追加private CocktailWindowAction cocktailWindow;

// メソッドを変更public void OpenInventory(bool isStone, WareHouseAction wareHouse = null, CocktailWindowAction cocktailWindow = null)
{
   if (isStone)
   {
       display.inventory = stoneInventory;
       action = EAct.MoveBegin;
   }
   else
   {
       display.inventory = itemInventory;
       action = EAct.MoveBegin;
   }
   this.wareHouse = wareHouse;
   this.cocktailWindow = cocktailWindow;
}

​private void SelectItem()
{
   if (KeyConfig.GetKeyDown(KeyConfig.EType.INVENTORYACTION))
   {
       if (wareHouse != null)
       {
           selectItem = display.GetSelectItem();
           if (selectItem == null || !selectItem.isEquip)
           {
               Item item = wareHouse.InventoryInsertItem(selectItem);
               display.inventory.Remove(selectItem);
               if (item != null) display.inventory.Add(item);
           }
           action = EAct.MoveBegin;
           wareHouse = null;
           selectItem = null;
       }
       else if (cocktailWindow != null)
       {
           selectItem = display.GetSelectItem();
           if (selectItem == null || !selectItem.isEquip)
           {
               Item item = cocktailWindow.ItemSlotInsertItem(selectItem);
               display.inventory.Remove(selectItem);
               if (item != null) display.inventory.Add(item);
           }
           action = EAct.MoveBegin;
           cocktailWindow = null;
           selectItem = null;
       }
       else
       {
           string choiceOrder = "";
           selectItem = display.GetSelectItem();
           if (selectItem != null)
           {
               if (selectItem.isEquip) choiceOrder = "Remove";
               else
               {
                   choiceOrder = "Sell";
                   if ((int)selectItem.id < 1001) choiceOrder += ",Equip";
               }
               subMenu.SetChoices(choiceOrder);
               subMenu.Show();
           }
       }
   }
}

ビルドして実行してみましょう。
以下のようにスロットにアイテムを入れられたらOKです。

スクリーンショット 2020-11-18 23.51.36

特に今は判定とかはしていないので魔石を入れる箇所にも他のアイテムを入れられます。また、合成結果のアイテムのスロットには何も入れられない方がいいでしょう。

ということで次回はその判定の実装から行っていきたいと思います。

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