Diskuze: Konstruktor v Unity
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.


Luboš Běhounek Satik:12.9.2018 13:57
Konstruktor se volá při vytváření objektu, což v Unity tuším už když ho hodíš do scény, zatímco Start se volá až ve chvíli, kdy se inicialuzuje při spuštění hry. Pokud nemáš konkrétní důvod to cpát do konstruktoru, tak bych ty věci nastavoval ve Start().
Miroslav Mazal:12.9.2018 14:11
Mně to sice funguje, ale nejsem si jistý, jestli to správně chápu. A
proto mám v sobě takovou nejistotu a jistý zmatek. Nejde mi jen o funkčnost,
ale abych to fakt pochopil. Co jsem to teda udělal podle toho popisu nahoře?
Start jsem totiž nepoužil. Vytvořil jsem script třídy Kostka, který jsem
připojil k prázdnému GameObject KostkaA.
A takhle jsem ho hodil do GameManagera
public class GameManager : MonoBehaviour {
public Kostka kostkaA;
public Kostka kostkaB;
public Kostka kostkaC;
public Kostka kostkaD;
public Kostka kostkaE;
A až pak je Start. Klidně teď můžu volat metody z KostkaA.
Funkčnost je tady https://www.youtube.com/watch?…
Stisknutím Scape vždy vyberu číslo nebo znak (jako u kostky).
Luboš Běhounek Satik:12.9.2018 14:12
Poradi kodu ma smysl jen uvnitr funkci, pokud prehodis poradi funkce a treba ty kostky, na funkcnost to nema vliv, jestli narazis na tohle.
Martin Petrovaj:12.9.2018 16:16
Keď si píšeš vlastný kód pre Unity a bavíme sa o tomto, potrebujeme rozlišovať dva druhy tried - tie, ktoré sú odvodené od MonoBehaviour a tie, ktoré nie sú.
MonoBehaviour-derived: nepoužívaš konštruktor vôbec, ak potrebuješ niečo nainicializovať, tak do Awake a Start. Konštruktory týchto tried sa správajú nanajvýš zvláštne a nenapadne mi z hlavy situácia, kde by sa to dalo rozumne využiť. Určite to nie je štandardné ani prehľadné.
Ostatné: tu sa už jedná o bežné C# triedy. V Unity Editore sa vo forme komponentov (ako napr. MonoBehaviour skripty, ktoré sa dajú priradiť ku gameobjectom) nevyskytujú, len ich používaš vo svojom ostatnom kóde. Keďže ide o "normálne" triedy, pri vytváraní ich inicializuješ klasicky cez konštruktor.
Aby si lepšie pochopil, čo za čiernu mágiu robí Unity s konštruktormi
pri MonoBehaviours, skús si založiť prázdny projekt a trochu
poexperimentovať - vypisuj do konzoly keď sa zavolá konštruktor, Start,
Awake; skúšaj, čo sa dá a čo nie… Najlepšie je vždy si to vyskúšať a
uvidieť sám
Miroslav Mazal:12.9.2018 16:33
Takže já jsem dělal tu první variantu? Díky přiřazení scriptu ke GameObjectu, kde se odečítá float, mohu příkazem SetActive vypnout GameObject a tím onen script, a ten pak neběží donekonečna a nezatěžuje počítač.
Miroslav Mazal:12.9.2018 16:53
Mohu to tedy takto použít na ten Časovač? Ale jinak raději ne? Já ty prázdné GameObjecty se scriptem(komponentem) mám v Hierarchii, a tím se asi aktivují a tak nemusí být ve Start či Awake. Je to správně?Protože mne to funguje i když ve Start ani Awake nejsou.Mám je v GameManageru nad tím.
Martin Petrovaj:12.9.2018 16:56
Nebude to tým, že samotné kocky nijako špeciálne inicializovať nepotrebuješ (teda Kocka nepotrebuje konštruktor, Start ani Awake) a tým, že v GameManageri si tie kocky potiahol do daných polí v editore?
Pokiaľ si nejaký objekt získaš tým, že ho v editore potiahneš do public premennej napr. GameManagera, tak už ho nepotrebuješ nejako získavať v Awake / Start. Pokiaľ by si ale chcel / potreboval kocky vyhľadať a v GameManageri uložiť z kódu, pravdepodobne by si to robil v Awake / Start v GameManageri.
Takže když to shrnu. Všechny scripty v Unity se píší odvozením z MonoBehaviour. Ale nemám používat metodu vytvoření prázdného GameObjectu a přiřazení Scriptu jako komponentu a nahrazovat tak klasický konstruktor. Je to tak?
Aha ne. Buď budu používat konstruktory v MonoBehaviour a inicializovat je přes Start Awake, anebo bez MonoBehaviour klasickými konstruktory C#. Ale všechny tutoriály pro Unity jsou asi v MonoBehaviour, aspoň, co jsem zatím viděl např. šachy.
Martin Petrovaj:12.9.2018 17:28
Skúsim radšej od začiatku:
- GameObjecty sú objekty, entity v hre (napr. stolička, dvere, hráč, kocka, zbraň).
- Vlastné správanie týmto GameObjectom definujeme tým, že k nim pridáme naše vlastné skripty.
- Aby skripty vedeli jednoducho a prehľadne interagovať s enginom (a rovnako tak opačným smerom), sú odvodené od triedy MonoBehaviour. Tá nám dáva zo skriptov možnosť reagovať na udalosti enginu ako načítanie scény, vykreslenie nového snímku a pod. Ak trieda nededí z MonoBehaviour, tak ju ani nemôžeme priradiť v editore nejakému GameObjectu ako komponent.
- Keďže MonoBehaviour skripty slúžia programátorom ako spôsob, ako interagujeme s enginom počas hry, je tomu prispôsobený ich životný cyklus vrátane inicializácie. Tá sa nevykonáva klasickým konštruktorom, ale jeho funkciu preberajú dve špeciálne metódy - Awake a Start.
To by sme mali skripty-komponenty odvodené od MonoBehaviour. Teraz ku triedam, ktoré z MonoBehaviour nededia:
- Ak trieda nededí z MonoBehaviour, nevie sama od seba reagovať na udalosti v hre / engine, napr. na spustenie hry, vykreslenie nového snímku, nedá sa priradiť ako komponent ku GameObjectu. Nevyužívajú žiadne špeciálne metódy z Unity (napr. Update, Start, OnDestroy atď), engine nijako neovláda ich životný cyklus - je to plne v našich rukách.
- Aby sme sprehľadnili a zjednodušili svoj kód, vedeli ho zdieľať medzi viacerými triedami a pod., často chceme opakujúce sa / univerzálne časti kódu oddeliť nielen do osobitných metód, ale aj osobitných tried. U nich ale nemá veľmi zmysel, aby samy interagovali s enginom, preto nie je žiaden dôvod, aby dedili z MonoBehaviour. Používame ich často len ako "pomocné" triedy, ale aj na ďalšie účely.
- MonoBehaviour skripty potom tieto naše pomocné triedy využívajú tak, ako potrebujú, pričom si ich riadia samy tak, ako najlepšie vedia. Nové inštancie týchto tried vytvárajú klasicky volaním ich konštruktora keď usúdia, že to je vhodné / keď to potrebujú (napr. var generator = new GeneratorNahodnychCisel(); ).
- Výsledkom je prehľadnejší, kratší, efektívnejší a znovupoužiteľný kód.
A poznámka na záver:
- Ak chceme, aby dva MonoBehaviour skripty interagovali medzi sebou, môžeme to tiež jednoducho spraviť tým, že potrebný skript získame ako akýkoľvek iný komponent z GameObjectu, na ktorom sa nachádza a ďalej s ním už pracujeme tak, ako uznáme za vhodné. Potrebný MonoBehaviour skript však takmer vždy nevytvárame, ale získavame. To znamená, že nevoláme žiaden jeho konštruktor ani špeciálne inicializačné metódy, ale predpokladáme, že už sa sám správne nainicializoval, ak to potrebuje (vo svojich metódach Awake / Start).
- Alternatívnym riešením je aj priradenie MonoBehaviour komponentu klasicky cez editor. Hlavným mínusom tohto prístupu je ale zo zjavných dôvodov jeho neflexibilita.
+20 Zkušeností

Super. Moc díky. Večer budu studovat.
Miroslav Mazal:13.9.2018 1:16
Ahoj. První půlku jsem věděl, ale tu druhou studuji. Vytisknul jsem si všechny scripty Šachů z tutoriálu https://www.raywenderlich.com/…e-with-unity a snažím se pochopit, jak jsou propojené. Až když jsi mi to rozepsal, tak jsem si všiml, že opravdu některé scripty nejsou v přímo v MonoBehaviouru. Pochopil jsem to takto:
- Scripty tříd figurek (král, střelec, pěšci atd.) jsou odvozeny od třídy Piece, ale tato třída Piece je pak odvozena z MonoBehaviouru, takže tak jsou vlastně potomci MonoBahaviouru všichni (dítě a vnuci).
- Jejich scripty jsou pak propojeny (Inicializovány) tím, že se v GameManageru vytvoří veřejné proměnné všech figur a v Inspektoru se přetáhnou Prefaby všech figur do příslušných políček. Podle tohoto jsem to udělal s těma kostkama. A opravdu není nutné nikde je inicializovat ve Startu či Awake. Je to tak i dle Manuálu na stránkách Unity, jestli jsem to dobře přeložil. Ve Startu se už jen umístí figurky na příslušná místa ve scéně.
- Je tam taky třída Geometry, která není MonoBehaviour ani nic jiného. Obsahuje jen 3 statické metody. Takže, asi nepotřebuje žádné propojení a je pouze v Projektu (nenašel jsem nikde vytvoření její instance ani veřejnou proměnnou), přesto se dá na tyto metody zavolat.
- Také je tam třída Board, která je jako mé kostky vytvořena umístěním prázdného GameObjectu do scény, ke kterému je připojen script Board. K tomuto prázdnému GameObject Board jsou ještě připojeny dva scripty. TileSelector a MoveSelector. A protože je v GameManageru veřejná proměnná Board, a opět se prázdný GameObject Board přesunul do příslušného políčka GameManageru v Inspectoru, tak se propojily s GameManagerem všechny tři scripty.
- A pak je tu ještě třída Player. Také není v MonoBehaviouru, a ta jediná se asi inicializuje v Startu GameManagera
void Start ()
{
pieces = new GameObject[8, 8];
movedPawns = new List<GameObject>();
white = new Player("white", true);
black = new Player("black", false);
currentPlayer = white;
otherPlayer = black;
InitialSetup();
}
Snad jsem to všechno pochopil. I díky tobě. Asi je to tak, že z pohledu tebe, jako zkušeného programátora v C# je možná někdy lepší jiný postup. Ale ten, který je neflexibilní, je brán jako návod na oficiálních stránkách Unity. To samé mi řekl jeden C# programátor, že Unity opustil, protože dělají věci prý nějak "divně".
Moc díky za takový pracný rozbor. Nikdy bych spoustě věcí nerozuměl, kdyby jsme to tak nerozpitvali.
Zobrazeno 13 zpráv z 13.