4# Tlačítka a UI

Do teď jsme používali jako jediný input klávesnici.To ale rozhodně není nejvhodnější způsob. Každá hra potřebuje minimálně nějaké menu, tlačítka a případně ovládání myší nebo přes touch. V této lekci nebudeme pracovat na nové hře, ale budeme rozšiřovat/předělávat náš předchozí projekt “NumberWizard”. Začneme vytvořením prázdného 2D projektu s názvem NumberWizardUI a začneme.

Po načtení začneme uložením  nové scény. V našich předchozích projektech jsme neměli žádnou scénu a nebo měli jednu scénu což není úplně realita většiny her. Takže budeme vytvářet úvodní obrazovku (scénu), herní scénu a finální scénu kde se budeme ptát jestli chce hráč hrát znovu. V hierarchii klikněte pravým tlačítkem na “SampleScene” a vybereme “save scene as”

Měli by jsme se objevit přímo ve složce projektu a v něm by měla být složka “Scenes”. Složku si otevřeme a uložíme naší scénu do ni pod jménem “Menu”. Scény mohou mít více slov v názvu (mezery), ale rozhodně nedoporučuji používat háčky a čárky. Z naší hierarchie zmizí původní SampleScene, ale dole v Assets ji stále najdeme. Můžete ji smazat. Stejně jako v předchozí lekci si přidáme Canvas. Klikneme pravým tlačítkem v hierarchii na “Menu” -> GameObject > UI > Canvas. Canvas nám nahrazuje funkci kamery (označení oblasti, kterou hráč vidí), když na nej v hierarchii uděláme dvojklik upraví se nám pohled kamery tak, aby jsme ho měli přes celý náhled scény. Náš předchozí projekt měl drobný problém a to, pokud jste ho exportovali a pokusili se ho zobrazit na monitoru, který neměl rozlišení 1920×1080 pravděpodobně vám část hry chyběla a viděli jste pouze prostředek hry. Pokud nyní kliknete na canvas v inspektoru je položka, kterou můžeme tento problém opravit. V nastavení najdete “Canvas Scaler (Script)”. Původní nastavení jen zobrazuje pixely tak jak jsou a na malé obrazovce nevidíte všechny, pokud ale použijete “Scale with Screen Size” canvas by se nám měl upravovat podle obrazovky, kdy můžeme zvolit i preferované rozlišení, které nám určí poměr stran.

Když máme vytvořený canvas můžeme na něj přidávat jednotlivé prvky (tlačítka a obrázky). Klikneme pravým tlačítkem na canvas s hierarchii a UI > Button. Určitě jste si všimli i možnosti Button – TextMeshPro pro více možností písma. Pro účely tohoto tutoriálu použijeme pouze button.

Tlačítko se nám objeví malé, uprostřed canvasu s miniaturním nápisem. Můžeme ho upravovat úplně stejně jako jsme dělali textová pole v minulé lekci pomocí nástroje “Rect Tool”. Zatím se nebudeme soustředit na samotné tlačítko a jeho text/funkce. Bude nás zajímat pozice tlačítka. Již výše jsem naznačil, že můžeme očekávat různé velikosti obrazovky a musíme podle toho upravit canvas, ale velikost není to jediné co se může měnit. Další problém může nastat u změny poměru stran. Dnes očekáváme, že standardní monitor bude mít poměr stran 16:9, ale může se stát, že někdo má ještě 4:3 případně někdo má grafický monitor, které jsou 16:10 nebo případně ultra-wide monitor třeba 21:9. Naše aplikace nemusí akutně počítat se všemi možnými poměry stran, ale v náročnějších projektech s tím určitě budete muset počítat. Jak na to, aby se nám upravoval layout podle poměru stran? Pokud si kliknete v hierarchii na button měli by jste vidět uprostřed canvasu 4 šipky směřující k sobě.

To jsou takzvané anchor points. 4 body podle, podle kterých se upravuje pozice a velikost tlačítka při změně velikosti/poměru stran. Nyní doporučuji pro účely testování změnit poměr stran v záložce GAME z 1920×1080 na “Free Aspect”. Nyní nám hra bude úplně vyplňovat naši záložku game. A společně s tím můžeme pozorovat změny velikosti a pozice tlačítka. Pokud například roztáhneme anchor points do rohů našeho canvasu, bude velikost tlačítka plně závislá na velikosti plátna.

Samozřejmě toto není nejlepší způsob a je to pouze jako příklad. Pravděpodobnější použití je, že umístíte AP (Anchor points) na jedno případně dvě místa. Když je umístíte například do pravého a levého dolního rohu, zachová nám naše tlačítko poměr stran a bude se držet stále ve stejné vzdálenosti od dolního okraje hry. Samozřejmě většinou chcete aby byla zachována velikost tlačítka v poměru k obrazovce a podle mě je nejlepší způsob, vybrat si očekávané rozlišení 1920×1080 nebo 16:9. Nastavit si velikost a pozici tlačítka a umístit AP do nejbližšího rohu případně středu strany. Aby jste toto nemuseli nastavovat ručně, když kliknete na tlačítko v inspektoru je “Rect Tranform” a hned první možnost Anchors.

Velmi podobně funguje i práce s obrázky, kde samozřejmě je velmi nežádoucí změna poměru stran a tak jen používáme 4 body na jednom místě. Pro vyzkoušení doporučuji stáhnout obrázek ve formátu PNG s transparentním (průhledným) pozadím. Pokud si říkáte jak ho najít stačí v google obrázcích kliknout na nástroje -> barva -> Průhledná

Samozřejmě pokud děláte komerční projekt nemůžete použít libovolný obrázek, který najdete na Google. Pokud budete chtít udělat projekt komerční určitě je lepší použít nějakou stránku kde jsou obrázky pod licencí CC a nebo ještě lépe použijte vlastní art. Když máte obrázek stažený stačí ho přetáhnout do Assets v Unity. Pokud ho ale chceme zobrazit ve hře musíme napřed přidat na canvas UI > Image. Ten by se měl objevit na stejné úrovni jako Button.

Začneme změnou pozice a velikosti našeho obrázku pomocí Rect Tool. Zatím se nemusíme soustředit na tvar, protože náš obrázek je pouze bílá plocha. Aby jsme přidali náš obrázek musíme kliknout na Image v hierarchy a v inspektoru je část Image (Script) kde můžeme vybrat zdroj (source) obrázku kliknutím na malé kolečko napravo od Source Image.

Když obrázek vložíte objeví se vám v inspektoru další nastavení a jedno tlačítko. “Set Native Size” vám nastaví obrázek na výchozí velikost. Samozřejmě změny jsou i poté možné a můžete obrázek deformovat. Pokud chcete zabránit deformacím obrázku doporučuji zaškrtnout “Preserve Aspect”. Můžete se pokusit o layout jako mám já.

Nyní kdyby jsme měnili poměr stran hry mohlo by se nám stát, že by se náš kouzelník vzdálil od dolního okraje. To proto, že máme AP nastavené na střed. Protože je náš kouzelník u levého dolního rohu nastavíme si je na tento roh. Samozřejmě design je na vás a výsledná hra může vypadat jak chcete, jen doporučuji vyzkoušet jiná rozlišení jestli máte dobře nastavené AP.

Nyní můžeme zašít upravovat styl tlačítek. Naše tlačítko v hierarchii má pod sebou schovanou jednu položku a tou je TEXT. Tam můžeme upravit obsah ale i velikost písma případně font. Pokud by jste chtěli více nastavení pro text musíte text smazat a přes pravé tlačítko UI si vložit Text – TextMeshPro. Pro tento tutoriál se budu držet pouze textu.

Na nastavení tlačítka není nic náročného. V inspektoru máte nastavení Button (Script) kde máte nastavení Normal color (Běžná barva tlačítka), Highlighted color (barva po najetí myší), Pressed color (Barva během kliknutí), Selected color (barva tlačítka po kliknutí pokud nás nepošle dál) a Disabled color (pokud není tlačítko zakázané). Pokud chcete měnit barvu písma musíte do nastavení text uvnitř button.

Když se nám povedlo dokončit první obrazovku (scénu) hry můžeme pokračovat dál. Uděláme si další dvě kopie aktuální scény. Jedna zůstane jako úvodní scéna, druhá bude hra a třetí bude konec hry / hrát znovu scéna. Celý “proces” je celkem jednoduchý. V hierarchii klikneme pravým tlačítkem na jméno scény (u nás menu). Pokud za jménem máte ještě hvězdičku dejte napřed save scene případně CTRL + S. Když máte scénu uloženou kliknete na Save scene as. Vybereme složku scenes a uložíme do ni pod názvem game a ještě jednou pod názvem end. V hierarchii vždy vidíte pouze jednu scénu! Pokud chcete otevřít jinou stačí na ní dvakrát kliknout v Assets.

 

V jednotlivých scénách si připravíme popisky tlačítek. V Menu máme správně začít hru, to by nás mělo dostat do game. V game budeme mít tlačítko “Správně”, to by nás mělo dostat na end, kde budeme mít tlačítko “Znovu?”, které nás dostane na začátek do menu. Stačí dvojklik na scénu, kterou chcete upravit, vyberete v hierarchii text uvnitř button a změníte jeho obsah. Během přepínání scén ukládejte CTRL + S nebo po vyskočení okna.

Konečně se dostáváme k psaní kódu. Napřed si vytvoříme prázdný herní objekt ve scéně “Menu” (Pravé tlačítko v hierarchii > create empty). Pro lepší orientaci ho přejmenujeme. Můžeme to udělat tak v hierarchii na něj klikneme pravým tlačítkem a vybereme “Rename” případně v inspektoru úplně první řádek. Dáme mu jméno Scene loader a začneme přidávat component. Po kliknutí na Add component se vám objeví pole do kterého můžete psát. Pokud to co do něj napíšete neodpovídá žádnému komponentu nabídne vám to vytvořit script. My si scipt nazveme SceneLoader. Opět žádné čárky, háčky ani mezery. Je to prakticky stejný způsob, jako když vytvoříte script přes assets jen se vám automaticky připojí k objektu. Script najedeme v assets začneme ho upravovat (dvojklik).

První čím začneme je přidání knihovny. Dáme ji na 4. řádek a tato knihovna se stará o scény (Scene Management).

Tentokrát nebudeme potřebovat Start() ani Update(), protože nečekáme na stisknutí klávesy a nemusí kontrolovat jestli je klávesa stisknuta, ale čekáme na vstup pomocí tlačítek na scéně, které mohou rovnou spouštět dané funkce v naše případě například změnu scény. Můžeme proto funkce void Start a void Update smazat.

Naše funkce bude pro všechny scény stejná a můžeme si to představit jako že se budeme pohybovat po řadě čísel. Máme scénu 0 (v programování vždy číslujeme od nuly) a pokračujeme scénou 1, kdy jen přičteme jedna. Pokud se dostaneme nad počet našich scén vrátíme se na začátek na scénu jedna. Toto se nám může případně hodit, když by jsme přidali scénu, tak nemusíme upravovat kód.

Vytvoříme tedy funkci LoadNextScene(), tato funkce bude veřejná (public), aby jsme ji mohli volat v dalších scriptech a nebude vracet žádnou hodnotu, čili void.

Funkce bude potřebovat několik proměnných. První bude index aktuální scény. Scény jsou číslované 0-X, celá čísla. Proto vytváříme int currentSceneIndex. Do té rovnou uložíme index aktivní scény. Aby jsme získali index aktivní scény použijeme knihovnu SceneManagement, která obsahuje funkci GetAktiveScene(), ze které použijeme pouze hodnotu buildIndex scény.

V dalším kroku musíme získat index další scény a změnit naší scénu. Pro to opět použijeme SceneManager, jeho funkci LoadScene(), kde použijeme index aktuální scény (to co jsme si uložili do proměnné v předchozím řádku) a přičteme jedna.

Aktuálně ještě nemáme dokonalou smyčku a nevrátíme se na začátek. Prostě v případě, že dojdeme k poslední scéně se unity pokusí načíst scénu, které neexistuje. To nám, ale nebrání to celé vyzkoušet. Uložte si script a přesuneme se do unity.

V unity klikneme v levé horním rohu na FILE -> Build Settings. Zde musíme určit pořadí v jakém scény budeme exportovat a pokud by jsme toto neudělali naše scény nedostanou index v takovém pořadí jaké chceme. Ze začátku máme “Scenes in build” prázdné a je potřeba je naplnit. Stačí je přetáhnout z Assets > Scenes. Můžete postupně v pořadí v jakém je chcete nebo najednou a pak změnit pořadí v Build Settings. Nemusíte nic ukládat stačí okno zavřít.

Aktuálně máme téměř vše připravené. Jediné co nám chybí je způsob jak script zapínat. V Hierarchii si otevřete tlačítko a v inspektoru úplně dole najdete On Click () – List is Empty.

Zde klikneme na malé plus.

První musíme přidat objekt, který obsahuje funkci, kterou má tlačítko spouštět. Klikneme na malé kolečko vedle None (Object). Otevře se nám nabídka kde jsou nahoře dvě záložky, první je Assets a druhá je Scene. S ohledem na to, že hledáme náš prázdný herní object “Scene loader”, hledáme v záložce scene. Poté přidáme tlačítku funkci. Tato možnost se otevře až po přidání objektu. Zde vybereme jméno objektu a pak jméno funkce. Takže Scene loader -> LoadNextScene ().

Aktuálně toho nemáme moc, ale již by mělo fungovat první tlačítko,  které by nás mělo přesunout z první stránky na druhou.

Výborně, teď musíme to samé udělat pro další scény. Otevřeme si scénu game, přidáme v hierarchii prázdný objekt, dáme mu jméno Scene loader. V inspektoru přidáme component, to bude náš script Scene Loader. Přepneme se na tlačítko, klikneme na + u On Click (), vybereme game object SceneLoader a vybereme funkci LoadNextScene.

Pro scénu End začneme stejně, ale po scéně END již není další scéna a tak je potřeba přidat funkci co nás bude vracet na začátek. Otevřeme si Scene Loader script a vytvoříme novou veřejnou funkci. Bude se jmenovat LoadStartScene a bude velmi podobná naší LoadNextScene (můžete udělat jen kopii a promazat). Nebudeme potřebovat na jakém indexu scény jsme teď, stačí nám pouze druhý řádek s načítáním scény, kde napíšeme do závorky nulu.

Uložíme. Přepneme se do unity a jediný rozdíl proti předchozí scéně bude, že místo funkce LoadNextScene vybereme v On Click funkci LoadStartScene.

Je už na čase udělat funkční část hry. Budeme pracovat na scéně GAME a budeme potřebovat 2 další tlačítka a 2 textová pole. Tlačítko již jedno máme a tak stačí udělat dvě kopie (Pravé tlačítko v hierarchii a duplikovat) a posunout je nad sebe. Také doporučuji přejmenovat pro lepší orientaci.

Pro přidání textu klikneme pravým na Canvas, UI-> TEXT pokud chcete více nastavení textu vybereme TextMeshPro. Já opět zůstanu u TEXT. Zde předepíšeme nějaký obyčejný text například “Myslím si, že tvé číslo je…”. Druhý text mohou být jen otazníky, protože je později upravíme scriptem. Rozložení, velikost písma a další je jen na vás.

Nyní budeme potřebovat script naší původní verze, která pracovala pouze s konzolí. Pokud se vám ji nechce hledat v souborech najdete ji i zde. V unity si vytvoříme nový C# script NumberWizard a do něj zkopírujeme obsah txt souboru nebo původního scriptu. Script opět musíme připnout k nějakému hernímu objektu a tak si vytvoříme nový prázdný objekt GAME a k němu přidáme herní komponent NumberWizard script.

Nyní musíme přepracovat samotný script. Hodně nám toho zůstane určitě musíme upravit input a můžeme upravit způsob záznamu proměnných na serializovaná pole. Serializovaná pole nám umožní úpravu hodnot skrz unity. Vím, že u této “hry” to není zas tak důležité, ale u dalších her se vám určitě bude hodit možnost rychle upravit životy, útok nebo cokoliv dalšího, aniž by jste to museli hledat v kódu. Proto je třeba se naučit serializovaná pole používat a trénovat to co nejvíce.

Začínáme oblastí maxNumber a minNumber.

Úprava na serializované pole je v tomto případě primitivní. Stačí před int dopsat [SerializedField]. V další části můžeme smazat všechny řádky, kde je Debug.Log a vytvoříme si dvě funkce. OnPressHigh a OnPressLow. Obě budou veřejné a nebudou vracet hodnotu (void).

OnPressHigh bude dělat to samé jako předtím dělal UpArrow a OnPressLow bude dělat to samé jako DownArrow. Proto můžeme jejich obsah kopírovat.

Nyní můžeme smazat vše v void Update. Také můžeme odstranit vše z void StartTheGame. Zde budeme potřebovat jen jednu věc a to výpočet midNumber. Rozsah čísel určujeme mimo kód a tak již nejde nechat výchozí hodnotu 500. S ohledem na to, že TheQuestion() dělá už jen výpočet midNumber můžeme ji pouze zavolat.

Celý kód se nám výrazně zmenšuje, ale budeme muset ještě něco málo přidat. Minimálně výpis midNumber hráči. Funkci, kterou budeme potřebovat se jmenuje ToString(). ToString dokáže vzít proměnou a přeměnit ji na string, který jde vypsat do textového. To budeme potřebovat, ale nějak připojit. K tomu si vytvoříme nové serializované pole podle toho kam chceme text vypisovat. Tady je drobný rozdíl mezi TextMeshPro a obyčejným text.

TextMeshPro

Musíte připojit TMPro a serializované pole bude typu TextMeshProUGUI. Řádek 4 a 10.

Obyčejný TEXT

Musíme připojit UnityEngine.UI a serializované pole bude typu Text. Řádek 4 a 10.

Uložíme a přepneme se do Unity. Zde si otevřeme náš GAME object a v inspektoru by jsme měli vidět 3 pole. Max number, Min number a Guess Text. Do Guess Text připojíme textové pole NumberGuess (kliknutí na malé kolečko vedle pole). Také můžete předvyplnit hodnoty 1000 a 1 do Max a Min.

Nyní sice máme pole připojené, ale nijak toto připojení nevyužíváme. Poprvé budeme pole upravovat hned na začátku hry, kdy přepíšeme “???” na 500. To uděláme v StartTheGame. Budeme vypisovat rovnou do textového pole GuessText proměnnou midNumber ve formě string (řetězce znaků).

Pokud chcete udělat první test, stačí uložit, přepnout do unity a zapnout. ??? by se měli změnit na 500.

Samozřejmě to není ještě hotové, tlačítka větší/menší zatím dělají to samé jako Správně. Mimochodem až teď jsem si všiml, že celou dobu mám ve slově “Správně” překlep. Paráda… Otevřeme si tlačítko v inspektoru, a v části On Click() změníme object z SceneLoader na GAME. A jako funkci zvolíme NumberWizard -> OnPressHigh/Low podle toho, které tlačítko upravujeme.

Tato změna však zatím nestačí. Proměnná se nám sice mění, ale hráči ji neukazujeme. Musíme proto zpět do scriptu a budeme kopírovat řádek GuessText.text = midNumber.ToString(). Ten přidáme jako poslední řádek do OnPressHigh a OnPressLow a tím by jsme měli mít hotovo, pokud chcete 

Pokud chcete udělat webovou verzi. V případě, že chcete udělat verzi pro Windows ještě by stálo za to přidat tlačítko konec/quit/X, prostě nějaký způsob jak program zavřít. Ve scéně menu si uděláme další tlačítko. Můžeme začít opět kopií tlačítka, které už máme. Uděláme ho menší a já ho dám do pravého horního rohu jen jako X.

Toto bude skutečně úprava pouze pro PC/MAC/Linux. Pro Android a iOS je třeba zavírat aplikace jinak a dostaneme se k tomu později. Budeme potřebovat script. Nemusíme vytvářet nový C# script můžeme jen dopsat jednu funkci do SceneLoader. Bude se jedna a novou veřejnou funkci, která nevrací hodnotu. Pojmenujeme si ji QuitGame(). Bude obsahovat jediný řádek a to Application.Quit(). Nezapomeňte uložit.

Díky tomu, že script SceneLoader již využíváme stačí otevřít tlačítko v inspektoru a změnit funkci LoadNextScene na QuitGame. HOTOVO! Zde je verze pro windows a pro prohlížeč.

 

 

 

 

 

 

 

 

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Share This