This shows you the differences between two versions of the page.
pjv:laboratoare:2020:01 [2020/10/14 15:40] alexandru.gradinaru |
pjv:laboratoare:2020:01 [2021/10/13 16:13] (current) alexandru.gradinaru |
||
---|---|---|---|
Line 1: | Line 1: | ||
===== Introducere in Unity ===== | ===== Introducere in Unity ===== | ||
- | ==== Unity Editor ===== | + | ==== Documentatie video ===== |
+ | |||
+ | [[https://youtu.be/3FYJD6sXT74|1. Introducere in Editorul Unity]] | ||
+ | |||
+ | [[https://youtu.be/IjfsxhF7mH4|2. Introducere in scriptingul Unity]] | ||
+ | |||
+ | ==== Documentatie extinsa text ===== | ||
+ | |||
+ | [[https://ctipub-my.sharepoint.com/:b:/g/personal/alexandru_gradinaru_upb_ro/EX9JzUQOGiJDljh770eC9ioBESCT7N3_TR4CdKBhidDgOg?e=6GMORk|1. Introducere in Editorul Unity]] | ||
+ | |||
+ | [[https://ctipub-my.sharepoint.com/:b:/g/personal/alexandru_gradinaru_upb_ro/EXdRYNImL8VGryfKsurcUqQBx5af0KLN2pMN-AaicOM6VA?e=eMLA0T|2. Introducere in scriptingul Unity]] | ||
+ | |||
+ | <note important>Aveti documentatie video si text extinsa, dar si un sumar cu elementele principale necesare in rezolvarea laboratorului, pentru cei care au mai lucrat deja cu Unity si sunt familiarizati cu anumite concepte. </note> | ||
+ | |||
+ | |||
+ | ==== Sumar documentatie ===== | ||
+ | |||
+ | > **Hotkeys** | ||
+ | |||
+ | {{ https://koenig-media.raywenderlich.com/uploads/2017/12/UnitHotkeys_CheatSheet.png?800 |}} | ||
- | VIDEO here - soon | ||
> **Folders inside unity** | > **Folders inside unity** | ||
Line 163: | Line 181: | ||
=== C# Basics === | === C# Basics === | ||
- | |||
- | > **Classes and Structures** | ||
- | |||
- | One of the basic design decisions every framework designer faces is whether to design a type as a **class (a reference type)** or as a **struct (a value type)**. | ||
- | |||
- | **Similarities:** | ||
- | |||
- | * Both are _container_ types, meaning that they contain other types as members. | ||
- | * Both have members, which can include constructors, methods, properties, fields, constants, enumerations, events, and event handlers. | ||
- | * Members of both can have individualized access levels. For example, one member can be declared `Public` and another `Private`. | ||
- | * Both can implement interfaces. | ||
- | * Both can have shared constructors, with or without parameters. | ||
- | * Both can expose a _default property_, provided that property takes at least one parameter. | ||
- | * Both can declare and raise events, and both can declare delegates. | ||
- | |||
- | **Differences:** | ||
- | |||
- | The Main difference between reference types **(Class)** and value types **(Struct)** we will consider is that reference types are allocated on the heap and garbage-collected, whereas value types are allocated either on the stack or inline in containing types and deallocated when the stack unwinds or when their containing type gets deallocated. | ||
- | |||
- | * Structures are **_value types_**; classes are **_reference types_**. A variable of a structure type contains the structure's data, rather than containing a reference to the data as a class type does. | ||
- | * Structures use stack allocation; classes use heap allocation. | ||
- | * All structure elements are `Public` by default; class variables and constants are by `Private` default, while other class members are by `Public` default. | ||
- | * A structure must have at least one nonshared variable or nonshared, noncustom event element; a class can be completely empty. | ||
- | * Structure elements cannot be declared as `Protected`; class members can. | ||
- | * Structures are not inheritable; classes are. | ||
- | * A structure does not require a constructor; a class does. | ||
> **Static Classes and Singleton** | > **Static Classes and Singleton** | ||
Line 266: | Line 258: | ||
=== Unity C# References === | === Unity C# References === | ||
+ | |||
+ | |||
+ | > **Variables and Parameters** | ||
+ | |||
+ | Variables can be controlled from the Unity Editor as parameters, as long as they are defined public or serializable. | ||
+ | We can use both simple variable or arrays. | ||
+ | |||
+ | <code> | ||
+ | public float speed; | ||
+ | public Sprite[] images; | ||
+ | private float internalBleed; //cannot be controller from Unity Editor interface | ||
+ | |||
+ | [SerializeField] | ||
+ | private Text scoreText; | ||
+ | | ||
+ | [SerializeField] | ||
+ | private GameObject[] enemyTypes; | ||
+ | </code> | ||
+ | |||
> **MonoBehaviour Event Execution Order** | > **MonoBehaviour Event Execution Order** | ||
Line 305: | Line 316: | ||
Instantiate(bullet, Vector3.zero, Quaternion.identity); | Instantiate(bullet, Vector3.zero, Quaternion.identity); | ||
Instantiate(bullet, new Vector3(0, 0, 10), bullet.transform.rotation); | Instantiate(bullet, new Vector3(0, 0, 10), bullet.transform.rotation); | ||
+ | |||
+ | newobj = Instantiate(objTemplate) as ObjType; | ||
+ | |||
+ | //from pregab - prefab must be in Resources folder | ||
+ | newobj1 = Instantiate(Resources.Load("enemy")); | ||
+ | |||
+ | // Instantiate the projectile at the position and rotation of this transform | ||
+ | Rigidbody projectile; | ||
+ | Rigidbody clone; | ||
+ | clone = Instantiate(projectile, transform.position, transform.rotation); | ||
+ | |||
+ | enemyOrc = Instantiate(Orc) as Enemy; | ||
/* Destroy a GameObject */ | /* Destroy a GameObject */ | ||
Line 312: | Line 335: | ||
GameObject myObj = GameObject.Find("NAME IN HIERARCHY"); | GameObject myObj = GameObject.Find("NAME IN HIERARCHY"); | ||
GameObject myObj = GameObject.FindWithTag("TAG"); | GameObject myObj = GameObject.FindWithTag("TAG"); | ||
+ | childObject=parentObject.GetChild("child_name"); | ||
+ | parentObject.GetChild("child_name").GetComponent<SpriteRenderer>().sprite = image; | ||
/* Accessing Components */ | /* Accessing Components */ | ||
Line 317: | Line 342: | ||
AudioSource audioSource = GetComponent<AudioSource>(); | AudioSource audioSource = GetComponent<AudioSource>(); | ||
Rigidbody rgbd = GetComponent<Rigidbody>(); | Rigidbody rgbd = GetComponent<Rigidbody>(); | ||
+ | GetComponent<SpriteRenderer>().sprite = image; //set image in child component | ||
+ | GetComponent<Text>().text = '123' //set text | ||
+ | |||
+ | /* Transforms - can be accessed using the `transform` attribute */ | ||
+ | Vector3 objectPosition = gameObject.transform.position; | ||
+ | gameObject.transform.position = new Vector3(posX, posY, posZ); | ||
+ | transform.Translate(Vector3.up * Time.deltaTime, Space.World); | ||
+ | transform.Rotate(Vector3.up * Time.deltaTime, Space.World); | ||
+ | |||
+ | /* Activate - can hide or how an element from the scene*/ | ||
+ | myObject.SetActive(false); // hide | ||
+ | myObject.SetActive(true); // show | ||
+ | |||
+ | GetComponent<BoxCollider>().SetActive(false); // hide component | ||
</code> | </code> | ||
Line 357: | Line 396: | ||
float physicsInterval = Time.fixedDeltaTime; | float physicsInterval = Time.fixedDeltaTime; | ||
+ | </code> | ||
+ | |||
+ | > **Random values** | ||
+ | |||
+ | <code c#> | ||
+ | Random.Range(-10.0f, 10.0f) | ||
+ | Random.Range(0, 8); | ||
</code> | </code> | ||
Line 438: | Line 484: | ||
if (Input.GetButton("ButtonName")) { Debug.Log("Button is being held down"); } | if (Input.GetButton("ButtonName")) { Debug.Log("Button is being held down"); } | ||
- | </code> | + | float translation = Input.GetAxis("Vertical") * speed; |
+ | float rotation = Input.GetAxis("Horizontal") * rotationSpeed; | ||
- | > **Hotkeys** | + | // Make it move 10 meters per second instead of 10 meters per frame... |
+ | translation *= Time.deltaTime; | ||
+ | rotation *= Time.deltaTime; | ||
- | {{ https://koenig-media.raywenderlich.com/uploads/2017/12/UnitHotkeys_CheatSheet.png?400 |}} | + | // Move translation along the object's z-axis |
+ | transform.Translate(0, 0, translation); | ||
+ | // Rotate around our y-axis | ||
+ | transform.Rotate(0, rotation, 0); | ||
- | <hidden> | + | /* special input events */ |
- | + | // OnMouseDown is called when the user has pressed the mouse button while over the Collider. | |
- | === Parametri / Variabile === | + | // This event is sent to all scripts of the GameObject with Collider or GUI Element. Scripts of the parent or child objects do not receive this event. |
- | + | // This function is not called on objects that belong to Ignore Raycast layer. | |
- | Parametri se pot controla in editor atat timp cat sunt definiti ca variabile publice sau serializabile. | + | // This function is called on Colliders marked as Trigger if and only if Physics.queriesHitTriggers is true. |
- | + | void OnMouseDown() | |
- | Se pot defini atat variabile simple cat si liste (array) | + | |
- | + | ||
- | <code> | + | |
- | public float speed; | + | |
- | + | ||
- | public Sprite[] images; | + | |
- | + | ||
- | + | ||
- | [SerializeField] | + | |
- | private Text scoreText; | + | |
- | + | ||
- | [SerializeField] | + | |
- | private GameObject[] enemyTypes; | + | |
- | </code> | + | |
- | + | ||
- | + | ||
- | === Instantierea obiectelor === | + | |
- | + | ||
- | Obiectele se pot instantia folosind functia | + | |
- | <code> | + | |
- | newobj = Instantiate(objTemplate) as ObjType; | + | |
- | + | ||
- | //from pregab - prefab must be in Resources folder | + | |
- | newobj1 = Instantiate(Resources.Load("enemy")); | + | |
- | + | ||
- | // Instantiate the projectile at the position and rotation of this transform | + | |
- | Rigidbody projectile; | + | |
- | Rigidbody clone; | + | |
- | clone = Instantiate(projectile, transform.position, transform.rotation); | + | |
- | + | ||
- | enemyOrc = Instantiate(Orc) as Enemy; | + | |
- | </code> | + | |
- | + | ||
- | === Transformari === | + | |
- | + | ||
- | Transformarile unui obiect se pot accesa prin atributul `transform` (https://docs.unity3d.com/ScriptReference/Transform.html) | + | |
- | + | ||
- | <code> | + | |
- | Vector3 objectPosition = GameObject.transform.position; | + | |
- | + | ||
- | GameObject.transform.position = new Vector3(posX, posY, posZ); | + | |
- | + | ||
- | transform.Translate(Vector3.up * Time.deltaTime, Space.World); | + | |
- | + | ||
- | transform.Rotate(Vector3.up * Time.deltaTime, Space.World); | + | |
- | </code> | + | |
- | + | ||
- | === Random === | + | |
- | + | ||
- | Pentru a genera valori random puteti folosi clasa Random | + | |
- | + | ||
- | <code> | + | |
- | + | ||
- | Random.Range(-10.0f, 10.0f) | + | |
- | Random.Range(0, 8); | + | |
- | + | ||
- | </code> | + | |
- | + | ||
- | === Controlul unor obiecte sau componente === | + | |
- | + | ||
- | Afisarea sau ascunderea unui obiect din scena se poate face prin functia de activare | + | |
- | + | ||
- | <code> | + | |
- | myObject.SetActive(false); // ascunde | + | |
- | myObject.SetActive(true); // arata | + | |
- | </code> | + | |
- | + | ||
- | Similar, se pot controla componentele unui obiect | + | |
- | + | ||
- | <code> | + | |
- | + | ||
- | this.GetComponent<BoxCollider>().SetActive(false); // dezactivare | + | |
- | this.GetComponent<SpriteRenderer>().sprite = image; //setarea unei imagini | + | |
- | + | ||
- | myObject.GetComponent<Text>().text = '123' //setarea unui text | + | |
- | + | ||
- | </code> | + | |
- | + | ||
- | De asemenea se pot accesa elemente copil sau parinte | + | |
- | <code> | + | |
- | childObject=parentObject.GetChild("child_name"); | + | |
- | + | ||
- | //setarea unei componente a elementului copil | + | |
- | parentObject.GetChild("child_name").GetComponent<SpriteRenderer>().sprite = image; | + | |
- | </code> | + | |
- | + | ||
- | === Asteptari/Wait === | + | |
- | + | ||
- | Daca vreti veti sa introduceti asteptari in rularea unui script/functii puteti folosi corutine. | + | |
- | Corutinele sunt folosite pentru a porni functii asincrone, care se pot intinde pe mai multe frame-uri, si in care se poate pune pauza (wait). | + | |
- | + | ||
- | <code> | + | |
- | void Start() | + | |
{ | { | ||
- | StartCoroutine(Example()); | + | // Destroy the gameObject after clicking on it |
- | } | + | Destroy(gameObject); |
+ | } | ||
- | IEnumerator Example() | ||
- | { | ||
- | print(Time.time); | ||
- | yield return new WaitForSeconds(5); | ||
- | print(Time.time); | ||
- | } | ||
</code> | </code> | ||
- | === Evenimente de Input === | ||
- | Pentru a putea detecta daca un element a fost apasat, se poate folosi functia OnMouseDown | + | > **Debug** |
- | <code> | + | |
- | void OnMouseDown() | + | <code c#> |
- | { | + | Debug.Log(transform.position); |
- | gameObject.SetActive(false); | + | Debug.Log("text"); |
- | } | + | |
- | | + | |
</code> | </code> | ||
- | <note important>Atentie! Aceasta functie este activa doar in cazul in care utilizatorul apasa cu mouseul peste un elemente de UI sau un Collider</note> | ||
=== Cerinte === | === Cerinte === | ||
Line 575: | Line 524: | ||
- | - Configurati scene pentru rulare 2D | + | - Configurati scena pentru rulare 2D |
- | - Adaugati in scena o imagine care reprezinta o tabla de joc (masa) | + | - Adaugati in scena o imagine care reprezinta o tabla/fundalul de joc (masa) |
- | - Adaugati doua imagini in scena: | + | - Adaugati doua imagini suprapuse in scena*: |
- unul care sa reprezinte elementul ascuns | - unul care sa reprezinte elementul ascuns | ||
- unul care sa reprezinte elementul afisat | - unul care sa reprezinte elementul afisat | ||
- | - Scriptati elementul afisat astfel incat la click sa se ascunda si sa se afiseze cel ascuns | + | - Scriptati/programati elementul afisat astfel incat la click pe acesta sa se ascunda si sa se afiseze cel ascuns timp de cateva secunde (2-3 secunde de exemplu, apoi revine la elementul ascuns) |
- | - Colectati inca 3 imagini pentru elementele afisate | + | - Colectati alte imagini si realizati un grid de 4x4 sau 4x2 elemente generat aleator la fiecare rulare controlat de un script (game controller) care sa asigure: |
- | - Realizati un game controller in care sa scriptati urmatoarele | + | - instantierea dinamica a gridului si formarea de perechi (in scena trebuie sa fie perechi de elemente astfel incat utilizatorul trebuie sa selecteze 2 elemente care coincid pentru a castiga punctaj) |
- | - instantierea dinamica a unui grid de 4x4 elemente (primul este deja instantiat) | + | - amestecarea elementelor la fiecare rulare (elementele afisat trebuie sa fie pozitionat/afisat intr-un slot diferit la fiecare rulare noua) |
- | - pozitionarea random a tipurilor de elemente (in scena trebuie sa fie perechi de elemente - deci vor fi 8 perechi pozitionate random la fiecare rulare) | + | |
- | - schimbarea dinamica a imaginii in functie de tip pentru fiecare element din scena | + | |
- mentinerea elementelor selectate curent (se selecteaza o data maxim 1 pereche) | - mentinerea elementelor selectate curent (se selecteaza o data maxim 1 pereche) | ||
- rularea asincrona a verificarii daca perechea a fost selectata sau nu corect | - rularea asincrona a verificarii daca perechea a fost selectata sau nu corect | ||
- mentinerea si afisarea unui scor. Scorul creste atunci cand descoperiti doua elemente identice. | - mentinerea si afisarea unui scor. Scorul creste atunci cand descoperiti doua elemente identice. | ||
- | - Adaugati un buton de restart game | + | - Adaugati un buton de restart game (acest lucru va regenera gridul cu elemente amestecate) |
+ | |||
+ | {{ :pjv:laboratoare:2020:lab1_example.gif?600 |}} | ||
- | </hidden> | + | <note tip>* exista mai multe variante de abordare a rezolvarii: de exemplu folosind elemente de canvas sau folosind elemente de scena pe care se ataseaza collidere (aveti grija la conditiile de activare a evenimentelor de mouse)</note> |