2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

GeekSalonAdvent Calendar 2022

Day 12

【Unity】Fungusを用いたアイテムシステムの構築

Last updated at Posted at 2022-12-11

はじめに

Unityでゲームを作っていてある程度のレベルになると、アイテムの実装という壁に当たることが多いかと思います。アイテムを取得すると何らかの処理を行うというのはできても、取得したアイテムをアイテムボックスに保持して、そこから任意のタイミングで使用するというのは、なかなかハードルが高いかと思います。今回はいくつかのスクリプトで関数を相互参照させて、アイテムボックス機能を実装していきたいと思います。今回はスマートにというよりもわかりやすくという点に重点を置きましたのでところどころ冗長な表現になってることをご了承ください。

環境

  • UnityEditor 2021.3.7f1

目標

目的を細分化させていきます。

  • アイテム取得する
    • 取得したアイテムをステージ上から非表示にする
    • アイテムボックスに取得したアイテムの情報を受け渡す
  • アイテムボックス一覧から取得済みのアイテムを確認する
    • アイテムボックスに取得したアイテムの画像を表示させる
  • アイテムボックス一覧から取得済みのアイテムを使用する
    • 使用できる条件かを判定する
    • アイテムボックス一覧から使用したアイテムを削除する
    • アイテムボックスの状況を更新する

方針

主に3つのスクリプトとFungusのコマンドを組み合わせて実装していきます。
スクリーンショット_20221213_115148.png

前提知識

ソースコード

1.スクリプト

Item.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using UnityEngine.UI;
using Fungus;

public class Item : MonoBehaviour
{
    public static Item instance;
    [SerializeField] Flowchart Log1;
    private Sprite image;
    private int index;
    public enum ItemType
    {
        knife,
        wateringCan,
        SuitKey,
        BreakerKey,
        illustration1,
        illustration2,
        illustration3,
        scissors,
        code,
        memo
    }

    public static Dictionary<ItemType, bool> itemCanUse = new Dictionary<ItemType, bool> ();
    public ItemType item;

    private void Awake()
    {
        if (instance == null)
        {
            instance = this;
        }
    }

    private void Start()
    {
        index = (int)item;
        btn = GetComponent<Button>();
        myTransform = this.transform;
        foreach(ItemType x in System.Enum.GetValues(typeof(ItemType)))
        {
            if(!itemCanUse.ContainsKey(x))
            {
                itemCanUse.Add(x, false);   
            }
        }
    
    }

    public void OnThis()
    {
        gameObject.SetActive(false);
        ItemBox.instance.SetItem(index);
    }

    public void UseItem()
    {
        Debug.Log(itemCanUse.Values.ToArray()[index]);
        if(itemCanUse.Values.ToArray()[index]){
            string indexstr = index.ToString();
            Log1.SendFungusMessage("useItem_" + indexstr);
            ItemBox.instance.UsedItem(index);
        }
        else{
            Log1.SendFungusMessage("canNotUse");
        }
    }

}
ItemBox.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Fungus;


public class ItemBox : MonoBehaviour
{
    public GameObject[] boxs;
    public int[] ItemInBox;
    public static ItemBox instance;
    public GameObject ItemBoxUI;
    public GameObject ItemSelected;
    [SerializeField] Flowchart Log1;

    private int BoxNumber = 0;
    private void Awake()
    {
        if (instance == null)
        {
            instance = this;
        }
    }

    private void Start()
    {
        for(int x=1; x<=7; ++x)
        {
            boxs[x].SetActive(false);
        }
    }

    public void ReloadBox()
    {
        int c = 0;
        bool emptyBox = false; 
        for(int a=0; a<=7; ++a)
        {
            if (emptyBox == true &&  boxs[a].activeSelf == true)
            {
                boxs[a-1].SetActive(true);
                boxs[a-1].gameObject.GetComponent<Image>().sprite = boxs[a].gameObject.GetComponent<Image>().sprite;
                ItemInBox[a-1] = ItemInBox[a];
                boxs[a].SetActive(false);
            }
            emptyBox = true; 
            if (boxs[a].activeSelf == true)
            {
                c = c + 1;
                emptyBox = false; 
            }
            
        }

        BoxNumber = c + 1;
    }

    public void SetItem(int index)
    {
        string indexstr = index.ToString();
        boxs[BoxNumber].gameObject.GetComponent<Image>().sprite = Resources.Load<Sprite>(indexstr);
        boxs[BoxNumber].SetActive(true);
        ItemInBox[BoxNumber] = index;
        ItemBoxUI.SetActive(true);
        SelectItem(index);
        BoxNumber = BoxNumber + 1;
    }

    public void SelectItem(int index)
    {
        string indexstr = index.ToString();
        ItemSelected.gameObject.GetComponent<Image>().sprite = Resources.Load<Sprite>(indexstr);
        Log1.SendFungusMessage("Item_" + indexstr);
    }

    public void DeleteItem(int ItemNumber)
    {
        for(int d=0; d<=7; ++d)
        {
            if (ItemInBox[d] == ItemNumber)
            {
                boxs[d].SetActive(false);
            }
        }
    }

    public void OnItem(int itemButtonNumber) { SelectItem(ItemInBox[itemButtonNumber]);  }

    public void UsedItem(int itemNumber) {
    int deletePositonNum = 0;
    for(int a=0; a<=7; ++a)
        {
            if(ItemInBox[a] == itemNumber)
            {
                deletePositonNum = a;
            }
        }
    DeleteItem(deletePositonNum); 
    ItemSelected.SetActive(false);
    }
}
    
UIManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIManager : MonoBehaviour
{
    public GameObject ItemBoxUI;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    public void OpenCloseItemBox()
    {
        if(ItemBoxUI.activeSelf == true)
        {
            ItemBoxUI.SetActive(false);
        }
        else
        {
            ItemBoxUI.SetActive(true);
            ItemBox.instance.ReloadBox();
        }
    }

}

2.Fungusの設定

Fungusの導入や基本設定は終わっている前提で進めていきます。
Scene内にFlowchartとSayDialog、MenuDialogを設置しておいてください。
FlowchartWindowでブロックとコマンドの設定をしていきます。
image.png
今回はとりあえず二つだけアイテムを実装していきます。

各アイテムのブロック

image.png
image.png
Itemスクリプトのenumのindexに対応する形でItem_0、Item_1、、、、とMessaageReceivedのMessaageを設定し、ItemBoxスクリプトのSelectItem()から発火できるように設定します。
Sayコマンドを設定し、アイテム選択時に流れるメッセージを設定します。
また、選択したアイテムをItemSelectedに表示できるようにSetActiveを設定します。

Backのブロック

image.png
上でtrueにしたItemSelectedのActive状態をfalseにします。

useのブロック

image.png
InvokeMethotコマンドで対応するアイテムのobjectを相手取り、ItemスクリプトのUseItem()を呼び出します。

can_not_useのブロック

image.png
Item使用不可のメッセージとItemSelectedのActive状態をfalseにするコマンドを設定します。

各use_itemのブロック

image.png
ItemスクリプトのUseItem()からメッセージ”use_item_「各index」”を受けっとたら発火するように設定します。
コマンドには実際にアイテムを使用した時の処理を設定してください。今回はSayだけしか設定していませんが、スクリプトの関数を呼び出すと幅広い処理ができると思います。

3.エディタ上での設定

アイテムの設置

今回はUIのボタンをアイテムにしているので、ステージ上にCanvasを設置し、そのCanvas上にアイテムを設置しています。ItemScriptをアタッチし、Buttonには自身のOnThis()を設定します。必要に応じてImageコンポーネントもアタッチしてください。また、enumのItemtypeを宣言しているので、そのアイテムが何であるかをエディタから設定するのを忘れないでください。
image.png

アイテムボックスの設置

アイテムボックスのUI(つまりアイテムボックスを開いた時の枠)を設置し、その子要素としてItemSelected、Itemsそしてその子要素にItem0~Item7を設置します。
image.png
ItemsはItem0~Item7をまとめるためのフォルダのようなものなので、何もアタッチする必要はありません。
ItemSelectedはアイテムボックスからアイテムが選択された時のピックアップ表示を担うものです。ItemBoxとItemSelectedはImage、Item0~Item7にはImageとButtonがついていれば大丈夫です。

ItemManagerの設置

CreateEmptyでからのObjectを作り、ItemBoxスクリプトをアタッチしてください。publicで宣言したあれこれも設定していきます。
image.png

Item0~Item7の設定

Item0~Item7のbuttonに関数をセットしていきます。
image.png
ItemManagerをセットし、ItemBoxのOnItemを呼び出します。OnItemには引数を設けているので、Item0であれば0を、Item1であれば1を、といった具合に入力していってください。

3.その他の設定

アイテムボタンの設定

CreateEmptyでUiManagerオブジェクトを用意し、UiManagerスクリプトをアタッチします。
image.png
ItemBoxUIをセットしておきます。
Canvas上にアイテムボタンを作り、UiManagerのOpenCloseItemBoxをbuttonにセットすればアイテムボタンの用意は完了です。
image.png

アイテムの使用可否の設定
ItemManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ItemManager : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKey (KeyCode.DownArrow)) {
            Item.itemCanUse[Item.ItemType.knife] = true;
            Debug.Log("sssssss");
        }
    }
}

ItemスクリプトのDictionary型変数itemCanUseのkey「knife」を使ってvalueになっているboolを書き換えることで、同一シーン内であればどこからでもアイテムの使用可否を設定することができます。
Item.itemCanUse[Item.ItemType.knife] = true;

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?