This is an old revision of the document!
TBU
Inregistrare pe teams
Pentru a crea un sistem de inventar avem nevoie in primul rand de date atasate fiecarui obiect, cum ar fi nume, icon, atribute etc. Putem realiza acest lucru usor prin obiecte scriptabile (Scriptable Objects). Obiectele Scriptable sunt containere de date ce nu trebuie sa fie atasate la un GameObject intr-o scena. Ele pot fi salvate ca asset-uri in bibliteca proiectului ca mai apoi sa poata fi utilizate.
Obiectele scriptabile se definesc prin crearea unui script ce mosteneste clasa ScriptableObject.
Pentru a instantia un obiect scriptabil avem doua variante:
[CreateAssetMenu(fileName = "New Item", menuName = "Inventory/Item", order = 1)] public class Item : ScriptableObject { new public string name = "New MyScriptableObject"; //suprascrie atributul name public string objectName = "New MyScriptableObject"; public bool colorIsRandom = false; public Color thisColor = Color.white; public Sprite icon; public Vector3[] spawnPoints; }
Intrucat exista atribute implicite pentru un obiect scriptabil (e.g. name), putem folosi variabile diferite (e.g. objectName) sau putem suprascrie definirea acestui atribut prin folosirea metodei new
(new public string name).
Mai departe, pentru un inventar vom avea nevoie de o lista de obiecte gestionabile. Pentru acest lucru vom face un script de gestiune pentru inventar (e.g InventoryManager) care gestioneaza adaugarea, eliminarea si interogarea inventarului. Pentru o accesare mai usoara si mai facila, ideal ar fi ca acest inventorymanager sa fie un Singleton. Pentru a avea un singleton trebuie sa ne asiguram ca avem o singura instanta creata pentru acest script atunci cand e accesat.
public class InventoryManager : MonoBehaviour { // singleton public static InventoryManager instance; void Awake() { instance = this; } //lista de obiecte public List<Item> items = new List<Item>(); //metode pentru gestionare public void Add(Item item) { items.Add(item); } public void Remove(Item item) { items.Remove(item); } }
Fiind definit ca un singleton, putem accesa acum foarte usor gestionarea inventarului:
Inventory.instance.Add(item); Inventory.instance.Remove(item);
Inca un element util in gestionarea inventarului este definirea unei metode de a notifica atunci cand s-a produs o modificare in inventar. Pentru acest lucru putem folosi Delegates
. Un Delegate este un pointer la o metode. Aceasta ne permite sa tratam metoda ca o variabila și sa o folosim pentru un callback. Cand este apelata, acesta notifica toate metodele care fac referire la delegate. Astfel putem definit o variabila pentru evenimentul de schimbare.
public delegate void OnInventoryChanged(); public OnInventoryChanged onInventoryChangedCallback; //metode pentru gestionare public void Add(Item item) { ... onInventoryChangedCallback.Invoke(); //notifica despre modificare } public void Remove(Item item) { ... onInventoryChangedCallback.Invoke(); //notifica despre modificare }
Urmatorul pas este crearea unei interfete grafice si legarea interfetei de functionalitatea InventoryManger-ului. Pentru interfata grafica, putem folosi, ca si pana acum, canvas-ul oferit de Unity, structurat astfel incat sa avem un panou general pentru inventar, si mai multe slot-uri pentru obiectele din acesta. Pe fiecare slot putem defini urmatoarele aspecte:
Pentru sloturile de inventar este indicat sa folositi un prefab sau un template.
Interfata grafica a inventarului are nevoie si de un script de gestionare. Astfel vom aveam un script care asculta (subscribe) evenimentul definit (delegate
) la actualizarea inventarului, si actualizeaza fiecare slot din interfata grafica:
void Start() { inventory = Inventory.instance; inventory.onInventoryChangedCallback += UpdateUI; //definesc o metoda ca se apeleaza la aparitia unui eveniment delegat slots = GetComponentsInChildren<InventorySlot>(); //fiecare slot din inventar } void UpdateUI() { //actualizare fiecare slot for(i=0; i < slots.Length; i++) { if(i<iventory.items.Count) slots[i].AddItem(..) else slots[i].RemoveItem(..) } }
Bineinteles, in inventar se pot pune diferse restrictii si interactiuni (cum ar fi dimensiunea maxima a inventarului)
bool AddItem() { if(items.Count >= space) //no more room return false else return true; } if(Inventory.instance.Add(item)) Destroy(gameObject);
Similar se poate face si gestiunea altor interfet: de quest pentru player, de echipament / arma, skilltree etc.
Pentru crearea unui sistem de dialog, se folosesc elemente de UI Canvas: Panel, Button, Image etc.
Mai departe, putem face un DialogManager, tot sub format singleton, pentru a putea referentia elementele de UI mai usor, o singura data. In acest manager putem configura diverse linii de dialog, numele NPC-ului care sa apara in caseta de dialog etc. De asemenea, va trebui sa tinem minte si in ce moment, sau la care linie de dialog ne aflam.
public class DialogManager : MonoBehaviour { public static DialogManager instance; public GameObject panel; public string NPCName; public List<string> sentences = new List<string>(); Button continueButton; Text dialogeTextContainer, NPCNameContainer; int lineIndex; void Awake() { //get child components dialogeTextContainer = ... NPCNameContainer = ... continueButton = ... continueButton.onClick.AddListener(delegate { ContinueDialog(); }); instance = this; } public void AddNewDialogue(string[] lines, string NPCName) { //initializeaza dialogul curent din NPC lineIndex=0; ... } public void showDialog() { dialogeTextContainer.text = sentences[lineIndex]; //afiseaza linia de dialog curenta NPCNameContainer.text= NPCName; panel.SetActive(true); } public void ContinueDialog() { lineIndex++; showDialog(); } }
Apoi, in clasa NPC-ului, putem instantia un dialog personalizat pentru NPC-ul respectiv:
public class NPC : InteractionObject { public string[] sentences; //se pot configura liniile de dialog in editor public string name; public override void Interaction() { base.Interaction(); // se apeleaza metoda parinte DialogManager.Instance.AddNewDialog(sentences, name); }