//tips
//ScriptableObjectの確認
現在使用しているScriptableObjectを継承しているItemスクリプトの内容を確認する。Monobehaviourではなく、ScriptableObjectを継承することで、オブジェクトにアタッチしなくても、機能として扱うことができるようになる点でコンポーネントとは異なる。
下記がスクリプトの内容で、最初に、Itemスクリプトをインスタンスとして生成する際にCreateAssetMenuを使用することでProjectシーンのcreateを押した時にNew Itemとしてインスタンス作成することができるようにしている。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName ="New Item",menuName ="ScriptableObject/Create Item")]
//Projectシーンのcreateを押した時にScriptableObject/Create Itemが選択できる
public class Item : ScriptableObject
{
new public string name = "New Item";
public Sprite icon = null;
public void Use()
{
Debug.Log(name + "を使用");
}
}
new public string name とされているのは、newで同じフィールド名を使用している場合に、継承元のScriptableObjectで使用されているnameを隠蔽し、同じ名前を用いていることで生じるエラーを起こさせなくしている。
このnewの使い方が簡単に理解できるサンプルを下記に記載する。BaseCでxを入れているにもかかわらず、BaseCを継承しているDerivedCでもxを使用し、異なる値を入れている。その場合、DerivedCではnewをつけることで、BaseCと継承先のDerivedCで異なるxの値を持つことを可能にしている。
public class BaseC
{
public static int x = 55;
public static int y = 22;
}
public class DerivedC : BaseC
{
// Hide field 'x'.
new public static int x = 100;
static void Main()
{
// Display the new value of x:
Console.WriteLine(x);
// Display the hidden value of x:
Console.WriteLine(BaseC.x);
// Display the unhidden member y:
Console.WriteLine(y);
}
}
/*
Output:
100
55
22
*/
話をitemクラスに戻すと、 文字列入力できるnameと画像入れ込みできるiconをセットにしたパッケージが作られており、簡単に、名前とそれに紐付いた画像を扱うことができるようになる。
new public string name = "New Item";
public Sprite icon = null;
シーンではアイテムにpublic Item item;がアタッチされており、その情報をinventorytest.Add(item);でitems.Add(item);からpublic List<Item> items = new List<Item>();に追加し、inventoryUiでリスト情報をUIにupdateさせる際にslotの下記AddItemで表示させている。
public void AddItem(Item newItem)
{
item = newItem;
icon.sprite = newItem.icon;
removeButton.SetActive(true);
}
一旦アイテムを拾うのではなく最初から持っている状態で考えてみる。
これはInventoryTestスクリプトのpublic List<Item> items = new List<Item>();にitemを追加しておけば良い。
以前作成したDIY,Melon,Seaをitemsのelementに追加した。これに対してTimeControllerで操作を加えられないか試していく。
public class TimeController : MonoBehaviour
{
InventoryTest inventorytest;
void Start()
{
Invoke("Item1", 3);
Invoke("Item2", 4);
Invoke("Item3", 5);
}
void Item1()
{
int index = Random.Range(0, inventorytest.items.Count); //int型なので最大値を含まない
Item item1 = inventorytest.items[index];
Debug.Log(inventorytest.items.Count);
Debug.Log("3秒後に実行されたitem1" + item1);
inventorytest.items.RemoveAt(index);
}
void Item2()
{
int index = Random.Range(0, inventorytest.items.Count);
Item item2 = inventorytest.items[index];
Debug.Log("4秒後に実行されたitem2" + item2);
inventorytest.items.RemoveAt(index);
}
void Item3()
{
int index = Random.Range(0, inventorytest.items.Count);
Item item3 = inventorytest.items[index];
Debug.Log("5秒後に実行されたitem3" + item3);
inventorytest.items.RemoveAt(index);
}
TimeControllerスクリプトを上記のように書き換えて、InventoryTestオブジェクトにアタッチしたが下記のエラーが発生した。
NullReferenceException: Object reference not set to an instance of an object
TimeController.Item1 () (at Assets/TimeController.cs:18)
inventorytest = GetComponent<InventoryTest>();をStartメソッドに入れ漏れていたので追加。
これにより、
3秒後に実行されたitem1Sea (Item)
4秒後に実行されたitem2Diy (Item)
5秒後に実行されたitem3Melon (Item)
と表示された。
リストから消されたらUIのボタンも表示をなくしたいので、inventorytest.Removeを追加した。
今度はボタンタッチのbool切り替えで時間ごとに追加される方法を考える。Slotオブジェクト下についているItemButtonオブジェクトのButtonコンポーネントの操作を試す。
Interactableのチェックを外した状態でスタートし、itemが呼ばれたらチャックがつくようにできないか考える。Interactableのチェックを外した状態の初期の色が灰色でバックグラウンドとかぶっていたので少し赤みを追加した。これはDisabled colorで設定できる。
下記よりslotのindexとitemのindexは同じであることがわかるので、そこをうまく利用していく。
for (int i = 0; i < slots.Length; i++)
{
if (i < inventoryTest.items.Count)//UIで表示される前のインベントリの中身Inventory.instance.items
{
slots[i].AddItem(inventoryTest.items[i]);
}
下記をItem1()などに追加したところ
Button button = slots[index].GetComponent<Button>();
button.interactable = true;
エラーが発生。
NullReferenceException: Object reference not set to an instance of an object
TimeController.Item1 () (at Assets/TimeController.cs:33)
button.interactable = true;
Buttonオブジェクトをうまく参照できていない。Debug.Log(slots[index]);で確認すると、Slot(1)オブジェクト がとられており、本来とりたいItemButtonの参照が取れていない。各slotの子までgetcomponentする必要があった。
Button button = slots[index].GetComponentInChildren<Button>();
button.interactable = true;
に変更。
なぜか3つ目のslotが読み込まれないので要因を探っていく。