11. Program s opakovaním
Veľmi často pri programovaní potrebujeme, aby počítač vykonal viackrát ten istý príkaz alebo tú istú sekvenciu príkazov. V minulej lekcii sme si vyrobili náhodný generátor kociek, ktorý ale fungoval na klikanie. Čo by sme robili, keby sme chceli, aby vygeneroval 5 kociek sám od seba už na začiatku?
Prvý krok by bol, že by sme presunuli generovanie z Update
do Start
:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Generator : MonoBehaviour { public GameObject objekt; // Start is called before the first frame update void Start() { GameObject novy = Instantiate(objekt); novy.GetComponent<Ovladanie>().enabled = false; novy.GetComponent<Rotator>().speedY = 1; } // Update is called once per frame void Update() { } }
To nám vygeneruje 1 kocku pri štarte. Ale my ich chceme 5. Jedna možnosť je 5x zopakovať túto trojriadkovú sekvenciu:
void Start() { GameObject novy = Instantiate(objekt); novy.GetComponent<Ovladanie>().enabled = false; novy.GetComponent<Rotator>().speedY = 1; GameObject novy2 = Instantiate(objekt); novy2.GetComponent<Ovladanie>().enabled = false; novy2.GetComponent<Rotator>().speedY = 1; GameObject novy3 = Instantiate(objekt); novy3.GetComponent<Ovladanie>().enabled = false; novy3.GetComponent<Rotator>().speedY = 1; GameObject novy4 = Instantiate(objekt); novy4.GetComponent<Ovladanie>().enabled = false; novy4.GetComponent<Rotator>().speedY = 1; GameObject novy5 = Instantiate(objekt); novy5.GetComponent<Ovladanie>().enabled = false; novy5.GetComponent<Rotator>().speedY = 1; }
Toto nám musí nevyhnutne prísť ako dosť primitívne riešenie, že? Síce funkčné, ale primitívne.
Navyše, keby sme teraz chceli zmeniť, aby počiatočná rýchlosť rotácie nebola nastavená na 1
ale 0.5f
, tak musíme na piatich miestach upravovať náš kód.
A čo by sme robili, keby sme nevedeli vopred koľko kociek má byť? Čo ak ten počet závisí od niečoho, čo vopred ešte nevieme. Napríklad voliteľná obtiažnosť hry alebo úplná náhoda?
Riešením je takzvaný cyklus alebo program s opakovaním.
Môj prvý cyklus
V jazyku C# sa opakovanie robí pomocou konštruktu for
. Už sme videli konštrukt if
, ktorý robil podmienku. Tak tu máme konštrukt for
, ktorý robí opakovanie:
void Start() { for (int i = 0; i < 5; i++) { GameObject novy = Instantiate(objekt); novy.GetComponent<Ovladanie>().enabled = false; novy.GetComponent<Rotator>().speedY = 1; } }
Je to už od pohľadu trochu zložitejšie ako pri if
, ale poradíme si s tým. Vysvetlíme si to ľudskou rečou. Takýto for
má predpis a telo:

Vyzerá to komplikovane, ale všetko vyzerá ťažko len do chvíle, než sa to naučíme. Tak začnime nejakými pokusmi, aby sme si osvojili cyklus for
.
- Vytvorte nový skript s názvom Cyklus a priraďte ho na game objekt Main Camera.
- Povypínajte ostatné naše experimentálne skripty (Vypisovanie, Premenne, Nahoda…), ktoré sme si navešali na Main Camera, nech nám nestrašia v konzole.
Vyskúšame zatiaľ namiesto generovania kociek len jednoduché výpisy do konzoly. Budeme opäť písať do metódy Start
, tento raz v skripte Cyklus. Začnime s jednoduchou verziou cyklu, ktorý sme použili pri kockách, len namiesto generovania kociek budeme mať jednoduchý výpis do konzoly:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Cyklus : MonoBehaviour { // Start is called before the first frame update void Start() { for (int i = 0; i < 5; i++) { Debug.Log("Ja sa opakujem!"); } } // Update is called once per frame void Update() { } }
Po spustení sa naozaj vypíše do konzoly viackrát ten istý výpis:

Vyskúšajte ako sa bude meniť počet výpisov, keď zmeníte predpis cyklu na nasledovné varianty:
for (int i = 0; i < 3; i++)
for (int i = 1; i < 5; i++)
for (int i = 0; i <= 5; i++)
for (int i = 0; i < 1; i++)
for (int i = 1; i < 1; i++)
Vedeli by ste sformulovať ako závisí počet opakovaní cyklu v závislosti od toho aké čísla dáme do predpisu?
Ako funguje cyklus for
?
Prvá časť predpisu v cykle (napr. int i = 0
) je v skutočnosti príkaz, ktorý sa zavolá na samom začiatku cyklu. Čo by robil tento príkaz, keby nebol v predpise cyklu, ale stál by sám o sebe v programe?
int i = 0;
Takýto riadok v programe vytvorí novú premennú typu int
s názvom i
a vloží do nej hodnotu 0
. A to isté sa stane aj tu. Cyklus si vytvorí premennú i
a vloží do nej počiatočnú hodnotu 0
.
Druhá časť predpisu má tvar otázky, predpokladu. Ako sa používa pri podmienke if
, napríklad:
if (i < 5) { ... }
Takáto podmienka if
sa vykoná len ak je splnený predpoklad i < 5
. A to isté robí aj v cykle. Ak je predpoklad splnený, telo cyklu sa vykoná a cyklus pokračuje. Ak nie je splnený, telo cyklu sa nevykoná a cyklus končí.
Tretia časť predpisu má opäť tvar príkazu. Keby bol samostatne v kóde vyzeral by rovnako:
i++;
Je to aritmetický príkaz a znamená zvýšenie hodnoty i o 1. Toto sa vykonáva po každom jednom zbehnutí cyklu.
Keď teda počítač vidí takto naformulovaný cyklus urobí nasledovné:
- Vyrobí si premennú
i
a vloží do nej hodnotu0
- Otestuje, či je splnený predpoklad
i <5
- Ak predpoklad platí:
- Vykoná telo cyklu
- Vykoná príkaz
i++
- Znova kontroluje či je splnená podmienka a tak dokola
- Ak predpoklad neplatí, tak cyklus končí.
V skratke teda cyklus for funguje tak, že začne na nejakej hodnote pomocnej premennej, postupne ju zvyšuje a kým táto hodnota nedosiahne limit, tak sa vykonáva dokola telo cyklu.
Preto sa napríklad cyklus for (int i = 1; i < 1; i++)
nevykonal ani raz. Začíname na hodnote 1. Predpoklad sa pýta, či je táto hodnota menšia ako 1. To nie je. Preto cyklus okamžite končí a nevykoná sa ani raz.
Upravte náš testovací cyklus v metóde Start
tak, aby sa vykonal práve 10x
Upravte náš testovací cyklus v metóde Start
tak, aby začínal od hodnoty 5 a vykonal sa práve 4x.
Bez použitia počítača si rozmyslite, koľkokrát sa vykoná takto zadefinovaný cyklus: for (int a = 1; a < 10; a++)
. Pokojne aj počítajte na prstoch. Nikto vás nevidí. Potom si overte svoju úvahu v skripte.
BONUS:
Bez použitia počítača si rozmyslite, koľkokrát sa vykoná takto zadefinovaný cyklus: for (int x = 1; x > 0; x++)
.
NEOVERUJTE si tento cyklus v skripte. Naozaj. Môže vám z toho zamrznúť Unity alebo celý počítač. Ak ste prišli úvahou k správnemu výsledku, koľkokrát sa takýto cyklus vykoná, tak asi tušíte prečo.
Použime cyklus v praxi
Teraz, keď už vieme, ako funguje cyklus for
. Pozrime sa naspäť na naše generovanie kociek v skripte Generator:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Generator : MonoBehaviour { public GameObject objekt; // Start is called before the first frame update void Start() { for (int i = 0; i < 5; i++) { GameObject novy = Instantiate(objekt); novy.GetComponent<Ovladanie>().enabled = false; novy.GetComponent<Rotator>().speedY = 1; } } // Update is called once per frame void Update() { } }
Teraz už vieme, že cyklus zadefinovaný ako for (int i = 0; i < 5; i++)
sa vykoná 5x. A asi by sme aj vedeli, čo treba zmeniť, aby sa vykonal 7x alebo 10x alebo 100x.
Vedeli by sme, čo zmeniť, aby sa vykonal n-krát?
- Vytvorte v skripte Generator verejnú vlastnosť s názvom
pocet
. - Priraďte do nej v inšpektore nejakú hodnotu. Napríklad 30. (Generator máme ako komponent na game objekte Kocky, keby ste ho nevedeli nájsť)
- Upravte v metóde
Start
predpis cyklu tak, aby sa cyklus zopakovalpocet
-krát
A vyskúšajte cez inšpektor zmeniť hodnotu napríklad na 300 a vygenerujte si 300 náhodných červených kociek:
Gratulujem práve ste vyrobili skript na generovanie ľubovoľného počtu objektov na náhodné pozície. V úvodných lekciách sme také niečo nevedeli a potrebovali sme si stiahnuť už hotový skript, ktorý to robí za nás. Teraz si taký skript už vieme napísať aj sami.
Zhrnutie
Pomocou cyklu for
vieme nejaký blok príkazov (tzv. telo cyklu) vykonať opakovane viackrát.
Počet opakovaní cyklu nastavíme v predpise cyklu pomocou počiatočnej hodnoty (napr. int i = 0
) a pomocou podmienky (napríklad i < pocet
)
Pozor, keď nesprávne nastavíme podmienku, môže sa stať, že sa cyklus nevykoná ani raz, alebo že sa bude vykonávať donekonečna a aplikácia zamrzne.
Hotový projekt po tejto lekcii: Programovanie_11.zip