//tips
//動的生成するprefab編集
次は、input fieldのテキスト入力文字を、動的に生成するprefabのtext部分に記載できないか考えていく。
GamePlayerのprefab自動生成でnamelabelをSerializeFieldで扱っていたのでそちらの方法でできないか考える。そちらの方法ではprefabの親オブジェクトにスクリプトをアタッチすることで子要素の引き出しを自在に行っていた。
input fieldとbuttonを含んだprefabを作成していく。
input field ManagerのスクリプトをInput fieldオブジェクトを含む、canvasに移動させたところ下記のエラーが発生。
NullReferenceException: Object reference not set to an instance of an object
InputFieldManager.GetInputName () (at Assets/InputFieldManager.cs:26)
26行目のコードは、string value = inputField.text;であり、スクリプトを写したことで.text部分を拾えなくなっている。
下記のようにコードを修正するも改行が認識されず、on value changedがうまく同期されていない。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class InputFieldManager : MonoBehaviour
{
//InputFieldを格納するための変数
InputField inputField;
[SerializeField]
private Text roomname;
// テキストを格納する変数
[SerializeField]
private Text textbox;
// Start is called before the first frame update
void Start()
{
//InputFieldコンポーネントを取得
inputField = GameObject.Find("InputField").GetComponent<InputField>();
}
//入力された名前情報を読み取ってコンソールに出力する関数
public void GetInputName()
{
string value = roomname.text;
Debug.Log(value);
if (value.IndexOf("\n") != -1)
{
// テキストに入力内容を表示
textbox.GetComponent<Text>().text = roomname.text;
//入力フォームのテキストを空にする
//inputField.text = "";
// 入力できないようにする
inputField.interactable = false;
}
}
}
文字の改行は、IndexOfメソッドで文字列内の文字を検索し、対処していた。
public int IndexOf(
string value
)
引数valueは検索する文字もしくは文字列を指定し、指定した文字、文字列が見つかった場合は、0から始まるインデックス番号を返し、見つからなかった場合は-1を返す。
if (value.IndexOf("\n") != -1)とし、文字列に改行の文字が見つかった場合、処理を行うようにしている。
エラー理由の見当がついていないので一旦保留にして確認中。
//キャラクターのインベントリ実装
今後プレイヤーを操作する上でインベントリの実装は必須なのでそのやり方も理解しておく。
UIの空オブジェクトで画面での表示領域を決めた後に、panelを配置し、先の表示領域と合わせたサイズまで広げる。
このpanelの下にスロットを配置していく。今回はスロットを空オブジェクト として、2つのimageの合成物を一つのスロットとして考えていく。
このスロットをpanelに敷き詰めていくことを考えるのだが、手動ではなく、panelにGrid Layout Groupというコンポーネントをつけることで、パネル傘下にある複数スロットを規則正しく整列させることができる。
この際に、panelの表示領域を一番最初の親空オブジェクトの表示領域と異なる形にしてしまうと、うまく整列させることができなくなってしまうので注意が必要。
次はDropItemをインベントリーに移す作業を行う。
prefab化したDropItemのimageを開き、DropItemスクリプトをアタッチ。Buttonコンポーネントも一緒に追加する。
表示されたonClick()部分にアタッチした下記のスクリプトを反映させる。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DropItem : MonoBehaviour
{
public void Pickup()
{
//アイテム取得
Destroy(gameObject);
}
}
もう少し工夫を加えたいので、monobehaviourではなくscriptableobjectを継承した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;
}
これで作成したアイテムオブジェクトにspriteをアタッチする。そして、Drop itemスクリプトの方にitemを反映させる。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class DropItem : MonoBehaviour
{
public Item item;
private void Start()
{
GetComponent<Image>().sprite = item.icon;
}
public void Pickup()
{
//アイテム取得
Destroy(gameObject);
}
}
ここからインベントリの方にアイテムを移す作業に入っていく。
インベントリスクリプトを下記のように作成し、
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
public static Inventory instance;
//DropItemスクリプトの方でInventoryに指示だしできるようにするため
public List<Item> items = new List<Item>();
void Awake()
{
if (instance == null)
{
instance = this;
}
}
public void Add(Item item)
{
items.Add(item);
}
public void Remove(Item item)
{
items.Remove(item);
}
}
このインベントリの操作をドロップアイテムのクリック作業の際に行わせたいので、DropItemスクリプトも編集する。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class DropItem : MonoBehaviour
{
public Item item;
private void Start()
{
GetComponent<Image>().sprite = item.icon;
}
public void Pickup()
{
//アイテム取得
Inventory.instance.Add(item);
Destroy(gameObject);
}
}
この時新たにInventoryUIを作成し、作成したスクリプトはInventoryスクリプトと同様にinventoryオブジェクトにアタッチする。これはアイテムの取得などをメッセージとして受け取れるようにするもの。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InventoryUI : MonoBehaviour
{
public void UpdateUI()
{
Debug.Log("UpdateUI");
}
}
これに合わせてinventoryスクリプトも下記追加する。
public void Add(Item item)
{
items.Add(item);
InventoryUI.UpdateUI();
}
public void Remove(Item item)
{
items.Remove(item);
InventoryUI.UpdateUI();
}
このインベントリに移したアイテムをインベントリ内で画像表示させるためには、Slotのicon画像を変更させていく必要があるのでそちらのスクリプトも書いていく。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Slot : MonoBehaviour
{
public Image icon;
public GameObject removeButton;
Item item;
public void AddItem(Item newItem)
{
item = newItem;
icon.sprite = newItem.icon;
removeButton.SetActive(true);
}
public void ClearSlot()
{
item = null;
icon.sprite = null;
removeButton.SetActive(false);
}
}
ここまでできたらprefab化されたslotにこのスクリプトを貼り付け、prefabを開き、iconとremove buttonをインスペクターのスクリプト該当箇所にアタッチする。
その上でinventoryUIで全てのslotを取得し、データとして、アイテムが入っているものは表示させる。
slots = slotsParent.GetComponentsInChildren<Slot>();
ここで複数形のsを入れていないでGetComponentInChildren<Slot>とするとエラーとなるので注意。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InventoryUI : MonoBehaviour
{
public Transform slotsParent;
Slot[] slots;
void Start()
{
slots = slotsParent.GetComponentsInChildren<Slot>();
}
public void UpdateUI()
{
for(int i=0; i < slots.Length; i++)
{
if (i<Inventory.instance.items.Count)//UIで表示される前のインベントリの中身Inventory.instance.items
{
slots[i].AddItem(Inventory.instance.items[i]);
}
else
{
slots[i].ClearSlot();
}
}
Debug.Log("UpdateUI");
}
}
これによりインベントリ内の画像にも表示が行われる。