Inventory Light w końcu wkracza do UI

Witam w kolejnym artykule poświęconym hobbystycznie pisanemu systemowi do tworzenia i zarządzania ekwipunkiem i wszystkim co z nim powiązanym. W końcu udało mi się przenieść dane z bazy danych do Unity UI – czyli niezwykle intuicyjnego systemu do tworzenia interfejsów użytkownika w grach Unity. Nie jest to już tak niewygodne jak było poprzednio, ponieważ wcześniejszy system był o wiele bardziej ograniczony od ówczesnego (jego stosowanie wyglądało identycznie jak pisanie okienka do Edytora, którego niestety nie mogłem tutaj pokazać z powodu zbyt dużej ilości linijek kodu). Mam zamiar za tydzień lub dwa zaimplementować tu Drag and Drop, więc niewykluczone, że będę się wspomagał jakimiś poradnikami lub dokumentacją Unity (a ta jest bardzo rzetelna).

Moje próby zaistnienia jako grafik w moich dotychczas małych i prywatnych projektach na ogół były nieudane i z tego właśnie powodu by z jak najlepszej strony pokazać efekty mojej pracy pozwoliłem sobie na wykorzystanie tego zestawu ze strony opengameart.org.

Unity UI pozwala mi na łatwą zmianę wyglądu już zaprojektowanego interfejsu bez zbędnej ingerencji w kod, ponieważ zazwyczaj jeśli już jest to bardzo mało, można zaprojektować bardzo szybko interfejs użytkownika bez programowania (a przynajmniej mi się udało).

Napisałem w tym czasie jedynie 2 proste klasy: Inventory oraz ItemData

ItemData – Zawiera Item z bazy oraz liczbę całkowitą „Amount” pozwalającą na stackowanie

Inventory – po prostu plecak składujący obiekty klasy ItemData oraz wykonujący na nich operacke

 

Stackowanie w teorii działa, ale jeszcze jest nie do końca dopracowane więc zanim je tutaj pokażę to wolałbym jeszcze się przyjrzeć wszystkim możliwym sytuacjom i zbadać jak ekwipunek na nie zareaguje.

ItemData.cs


using UnityEngine;
using System.Collections;
using Assets.Scripts.Items;

public class ItemData : MonoBehaviour
{
public Item HoldedItem;
public int Amount;

void Start()
{

}
}

Myślę że nie ma co tu wyjaśniać, samo wyjaśnienie klasy ItemDatabase wystarczy.

Klasa Inventory przyjmuje w Inspektorze 4 pola. Są to kolejno:

public ItemDatabase ItemDatabase – obiekt bazy danych tworzonej w poprzednich wpisach

Transform slotPanel – GameObject który jest rodzicem wszystkich slotów

Transform slotPrefab – Prefab slotu, mógłbym oczywiście samemu go generować, ale w ten sposób uniemożliwiłbym modyfikację interfejsu, więc pozostawiam użytkownikowi możliwość dostosowania go do swoich indywidualnych potrzeb

Transform itemPrefab – Może się to wydawać bez sensu, ale itemPrefab zawiera ustawione przeze mnie ułożenie względem rodzica, oraz zawiera GameObject nazwany jako Amount – jest to po prostu licznik wyświetlający wartość „Amount” z ItemData do którego należy.

 

Inventory.cs


using System;
using UnityEngine;
using System.Collections.Generic;
using Assets.Scripts.Items;
using UnityEngine.UI;

public class Inventory : MonoBehaviour {

// Use this for initialization
public ItemDatabase ItemDatabase;

[SerializeField]
private Transform slotPanel;

[SerializeField]
private Transform slotPrefab;

[SerializeField]
private Transform itemPrefab;

[SerializeField]
private int MaxSize;

public List<Transform> SlotList;
public List<ItemData> ItemList;



void Start ()
{
SlotList = new List<Transform>();
ItemList = new List<ItemData>();

FillWithSlots();
}

// Update is called once per frame
void Update () {
if (Input.GetKeyDown(KeyCode.A))
{
AddItem(0);
}
else if(Input.GetKeyDown(KeyCode.S))
{
RemoveItem(0);
}
else if (Input.GetKeyDown(KeyCode.O))
{
AddItem(1);
}
else if (Input.GetKeyDown(KeyCode.P))
{
RemoveItem(1);
}
else if (Input.GetKeyDown(KeyCode.F))
{
foreach (ItemProperty property in ItemDatabase.ItemList[0].ItemProperties)
{
print(property.PropertyName);
}
}

}

private void FillWithSlots()
{
SlotList.Clear();
ItemList.Clear();

for (int i = 0; i < slotPanel.childCount; i++)
{
Destroy(slotPanel.GetChild(i).gameObject);
}

for (int i = 0; i < MaxSize; i++)
{
if (slotPrefab != null && itemPrefab != null)
{
GameObject slotInstance = Instantiate(slotPrefab).gameObject;
slotInstance.name = "Slot";

SlotList.Add(slotInstance.transform);
slotInstance.transform.SetParent(slotPanel.transform);
}
else
{
throw new UnassignedReferenceException("slotPrefab or itemPrefab is not assigned");
}
}

}

public void ReinitializeSlots()
{
ItemList.Clear();
for (int i = 0; i < SlotList.Count; i++)
{
if (SlotList[i].childCount != 0)
{
ItemList.Add(SlotList[i].GetChild(0).GetComponent<ItemData>());
}
}
}

public void RemoveItem(int ID)
{
ReinitializeSlots();
for (int i = 0; i < ItemList.Count; i++)
{
if (ItemList[i].HoldedItem.ID == ID)
{
if (ItemList[i].Amount > 1)
{
ItemList[i].Amount--;
if (ItemList[i].Amount > 1)
{
ItemList[i].transform.GetChild(0).GetComponent<Text>().text = ItemList[i].Amount.ToString();
}
else
{
ItemList[i].transform.GetChild(0).GetComponent<Text>().text = "";
}
break;
}
else
{
Destroy(ItemList[i].gameObject);
ItemList.RemoveAt(i);
break;
}
}
}
}

public void AddItem(int ID)
{
for (int i = 0; i < SlotList.Count; i++)
{
if (SlotList[i].childCount == 0)
{
GameObject itemInstance = Instantiate(itemPrefab).gameObject;
itemInstance.name = "Item";

itemInstance.transform.SetParent(SlotList[i].transform);
itemInstance.GetComponent<RectTransform>().anchoredPosition = Vector2.zero;

ItemData itemData = itemInstance.AddComponent<ItemData>();
ItemList.Add(itemData);
itemData.HoldedItem = ItemDatabase.ItemByID(ID);
itemData.Amount = 1;

itemInstance.GetComponent<Image>().sprite = itemData.HoldedItem.Icon;

break;
}
else
{
if (SlotList[i].GetChild(0).GetComponent<ItemData>().HoldedItem.ID == ID)
{
if (SlotList[i].GetChild(0).GetComponent<ItemData>().Amount <
SlotList[i].GetChild(0).GetComponent<ItemData>().HoldedItem.MaxStackCount)
{
SlotList[i].GetChild(0).GetComponent<ItemData>().Amount++;
if (SlotList[i].GetChild(0).GetComponent<ItemData>().Amount > 1)
{
SlotList[i].GetChild(0).GetChild(0).GetComponent<Text>().text =
SlotList[i].GetChild(0).GetComponent<ItemData>().Amount.ToString();
}
break;
}
}
}
}
}
}

Zapewne zauważyliście, że tylko baza danych nie zawiera tego atrybutu [SerializeField].

Sprawia on że zmienna mimo to że nie jest publiczna zostaje wyświetlona w inspektorze.

Robię to po to, by była możliwość pobierania danych z bazy w innych klasach, ale nie widzę sensu dawania tej możliwości prefabrykatom, więc nie nadużywam nadawania publicznego modyfikatora dostępu.

Stacking również działa, ale pokażę dopiero w następnym wpisie. Oprócz tego postaram się rozwiązać inne błędy, które są już w bazie a mam tu na myśli konkretnie Właściwości oraz Kategorie.

Do zobaczenia w następnym artykule.

 

Reklamy

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Wyloguj / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Wyloguj / Zmień )

Facebook photo

Komentujesz korzystając z konta Facebook. Wyloguj / Zmień )

Google+ photo

Komentujesz korzystając z konta Google+. Wyloguj / Zmień )

Connecting to %s