10. diel - Unity (C #) Android: Štart, Skóre, PlayerPrefs
V minulej lekcii, Unity (C #) Android: Prestavba, bodáky , sme upravili pohyb hráčov a pozmenili aj spôsob, akým sa nám posúvajú prekážky.
Dnes sa pozrieme na počítač skóre a tiež na počkanie na štarte, kým hráč nekliknete, aby mal čas sa na hru plne pripraviť.
Čakania na štart
Začneme s vyčkaním, kým hráč nezačne hrať. Pre tento účel upravíme
skript pre pohyb hráčov. Najprv ale objektu Player
nastavíme
gravitáciu na 0
, aby nám pri čakaní nepadal. Ideálne si
číslo, ktoré ste mali nastavené predtým, niekam poznačte.
Teraz si otvoríme PlayerMoveScript
.
Do nášho skriptu si pridáme na úplný začiatok novú premennú:
bool started = false;
A do Update()
metódy vložíme nasledujúci kód:
if (!started) { return; }
Keď hru spustíme, hráč nám stojí na mieste a nehýbe sa. To je presne
to, čo sme chceli. Avšak v tento moment chceme čakať, kým hráč nezačne
hrať. Predtým, než budeme reagovať na nejakú tú akciu, si vytvoríme
metódu v tom istom skriptu. Metóda sa bude volať
StartGame()
:
void StartGame() { started = true; rigidbody2D.gravityScale = 1f; // Vaše hodnota, např. 1f Vector3 vel = rigidbody2D.velocity; vel = Flap(vel); rigidbody2D.velocity = vel; }
Metóda nám pri jej zavolanie nastaví started
na
true
. Tiež nastaví gravitáciu na pôvodné číslo, ktoré sme
mali nastavené na hráčovej (to si v kóde upravte).
Keď hráč klikne, začne padať a musel by rýchlo klepnúť
znova. Preto sme zariadili, aby nám postavička zároveň aj "flapla" a tým
hráč dostane chvíľu času na zareagovaní. Používame k tomu metódu
Flap()
, ktorú si hneď tiež pridáme.
Kód metódy Flap()
je nasledovné:
Vector3 Flap(Vector3 v)
{
v.y = flapAmount;
return v;
}
Teraz upravíme časť pod podmienkou !started
do tejto
podoby:
if (!started) { if (Input.GetMouseButtonDown(0) || Input.GetKeyDown(KeyCode.Space)) { StartGame(); } return; }
Keby sa niekomu nepodarilo poskladať metódy do skriptu, nižšie je pre kontrolu jeho finálna podoba:
float flapAmount = 7; float speed = 5; bool started = false; void Start() { } // Update is called once per frame void Update() { if (!started) { if (Input.GetMouseButtonDown(0) || Input.GetKeyDown(KeyCode.Space)) { StartGame(); } return; } Vector3 vel = gameObject.GetComponent<Rigidbody2D>().velocity; if (Input.GetMouseButtonDown(0)) { vel = Flap(vel); } vel.x = speed; gameObject.GetComponent<Rigidbody2D>().velocity = vel; } void StartGame() { started = true; GetComponent<Rigidbody2D>().gravityScale = 1f; Vector3 vel = GetComponent<Rigidbody2D>().velocity; vel = Flap(vel); GetComponent<Rigidbody2D>().velocity = vel; } Vector3 Flap(Vector3 v) { v.y = flapAmount; return v; }
Nie je tu asi nič, čo by sme museli špeciálne vysvetľovať. Všetko v tomto kóde už v tutoriálu zaznelo, tak sa môžeme vrhnúť na ďalšiu časť.
Počítanie skóre
Teraz začneme s počítaním skóre. Na náš Stalag pridáme ďalší
objekt, ktorý bude zisťovať, či hráč preletel. Všetkým prefabům Stalag
pridáme objekt. Vytvoríme si prázdny gameObject, vynulujeme jeho súradnice a
pomenujeme ho napríklad stalagScore
. Tento objekt vložíme ako
podobjektoch Stalag. Pridáme mu Box Collider2D.
Collider si zväčšíme po osi Y dostatočne ďaleko a pokúsime sa Collider narovnať sa spodkom Stalag. Alebo ho tiež môžeme dať viac do stredu, čo sa vám viac páči, na funkcionalitu to vplyv mať nebude. Nebojte sa to vážne roztiahnuť pokojne na desaťnásobok veľkosti Stalag. Mohlo by sa stať, že tento Collider bude moc malinký kvôli našom generovanie Stalag v náhodných veľkostiach a hráč sa ho treba ani nedotkne a nebudú pripisovať sa mu skóre. Tiež musíme tento Collider nastaviť ako trigger:
Ďalej tomuto objektu pridáme ScoreScript
. Tento skript bude,
ako si tušíte, pripísať skóre. Pre tieto účely si pridáme Text na
obrazovku ako GameObject -> UI -> Text.
Vytvorí sa nám samozrejme tiež Canvas, ale s tým už vieme pracovať z
minulých lekcií. Teda si ho nastavíme na kameru, aby bol stále pekne
vidieť. Tento text nám bude vypisovať aktuálne skóre. Text si umiestnime do
pravého horného rohu, zväčšíme si font a text nastavíme napríklad len na
Score: 0
. Tomuto textu pridáme TextScoreScript
.
Základ máme pripravený.
Skripty
Vrhneme sa na ony dva skripty.
TextScoreScript
Najskôr upravíme náš TextScoreScript
:
static int score = 0; void Start () { score = 0; } public static void AddScore() { score++; }
Programátori určite tuší, prečo pred score
máme
static int
. Neprogramátori asi veľa nevie. Keď máme nejakú statickú
premennú alebo metódu, sme schopní k nej pristupovať aj z rôznych metód a
tried, bez toho aby sme ju museli nejako získavať. Takáto metóda však ale
môže pracovať zas len so statickými premennými v triede. Vďaka tomu, že
metódu máme statickú, sme schopní urobiť ďalší skript jednoduchšie.
ScoreScript
Keď cez náš trigger preletí hráč, chceme pripísať skóre. To urobíme
zavolaním metódy na triede ScoreScript
:
void OnTriggerEnter2D(Collider2D col) { if(col.CompareTag("Player")) { print("Adding score"); ScoreScript.AddScore(); } }
Vďaka tomu, že v danej triede máme metódu statickú, sme schopní k nej pristúpiť, bez toho aby sme robili niečo takéto:
GameObject.Find("název objektu").SendMessage...
Alebo ešte horšie takého:
GameObject.Find("název objektu").getComponent...
Horšie preto, že je to zbytočne zložité, ako pre nás, tak pre počítač. Predstavte si scénu, kde máte tisíce objektov a počítač medzi nimi musí nájsť daný objekt, na objekte nájsť skript a až potom sme tam, kde chceme byť.
Teraz, keď hráč preletí úspešne okolo Stalag, vnútorne sa nám skóre pripočíta, ale nikde ho nevidíme.
TextScoreScript
Preto sa vrátime späť do TextScoreScript
, kde zavedieme novú
premennú. Pokiaľ hráč zdolá prekážku, túto premennú si nastavíme na
true
a zmeníme text, ktorý ukazuje aktuálny body:
static int score = 0; static bool changed = false; void Start () { score = 0; } void Update () { if(changed) { changed = false; gameObject.GetComponent<Text>().text = "Score: " + score; } } public static void AddScore() { score++; changed = true; }
Pri aktualizovanie texte sa vždy odkážeme na aktuálny objekt, kde sa nachádza náš text na vypisovanie skóre, a zároveň náš skript.
Pripočítania skóre hotové a my sa môžeme vrhnúť na ukladanie najlepšieho skóre.
Najlepšie skóre
Pridáme si nový text, ktorý si dáme menšiu než ten pôvodný, a
pomenujeme si ho GUIHighScore
. Dáme text pod naše aktuálne
skóre. Tiež mu môžeme pridať text highscore:
:
Tomuto textu pridáme nový skript HighScoreScript
. Najskôr sa
ale vrátime k nášmu ScoreScript
.
ScoreScript
Pridáme si do neho jednu metódu:
void OnDestroy() { int highscore = PlayerPrefs.GetInt("highscore", 0); if (score > highscore) PlayerPrefs.SetInt("highscore", score); }
Táto metóda je v Unity už predpripravená podobne, ako sú metódy
Start()
alebo Update()
. Táto metóda sa volá vždy
pri zničení objektu alebo pri ukončení scény.
PlayerPrefs
Ďalej tu máme PlayerPrefs
. To je trieda s užitočnými
metódami pre ukladanie veľmi jednoduchých dát.
Načítanie
Dáta hráča načítame takto:
PlayerPrefs.GetInt("highscore", 0);
Načítame hodnotu, ktorá je uložená pod kľúčom
"highscore"
. Ak daná hodnota nebude nájdená, uloží sa nám do
premennej 0
. Keby sme ako druhý parameter zadali napríklad
5
, tak budeme mať v highscore
hodnotu 5
,
ak sa žiadne uložené skóre nenájde.
Ukladanie
Metóda SetInt()
robí presný opak:
PlayerPrefs.SetInt("highscore", score);
Ukladáme pod kľúč "highscore"
číslo, ktoré sa nachádza v
premennej score
:
Takže ak hráč dosiahne skóre väčšieho, než je uložené v
PlayerPrefs
, tak sa zapíše do pamäti.
Ak by vás zaujímalo, kam sa napríklad na Windows tieto hodnoty ukladajú, môžete ich nájsť uložené v registroch. Samozrejme je tam nájdete až aspoň po jednom odohraní hry. Pre neskúsených odporúčam sa v registroch počítača moc nehrabú, môžete si nepríjemne poškodiť súbory a funkčnosť aplikácií.
Na účely testovania hry si môžeme pridať na prvý riadku metódy
OnDestroy()
vymazanie skóre:
PlayerPrefs.DeleteKey("highscore");
To zaistí, aby sme zbytočne nenahrali veľké skóre na našom počítači. Až hru budeme mať hotovú, nezabudnime túto riadku samozrejme zmazať.
Ešte jedna možnosť je tá, že si môžeme pridať podmienku:
If (Application.isEditor)
PlayerPrefs.DeleteKey("highscore");
Takže kým nebudeme mať hru vydanú a budeme ju spúšťať iba cez Unity, tak sa zakaždým vymaže skóre.
HighScoreScript
Teraz sa presunieme do HighScoreScript
:
void Start () { int highscore = PlayerPrefs.GetInt("highscore", 0); gameObject.GetComponent<Text>().text = "Highscore: " + highscore; }
Takže zakaždým, keď hru spustíme, sa nám aktualizuje text obsahujúci highscore na najvyššie nahrané skóre.