← Přehled všech hodin

Třídy a objekty

Cíl hodiny: Přestaneš popisovat hrdinu pěti samostatnými proměnnými a začneš ho popisovat jednou věcí, která má vlastní údaje i vlastní schopnosti.
Jak stránku používat: vpravo nahoře je tlačítko Prezentace — schová všechno kromě jednoho bloku a přepíná se šipkami. U ukázek a cvičení je kód vlevo editovatelný: uprav ho a klikni na Spustit (nebo Ctrl+Enter). Program se přeloží a spustí přímo v prohlížeči a vpravo se objeví to, co vypsal do konzole. Nic se neinstaluje.
Kam to dnes směřuje:

1. Vysvětlení a souvislosti

Poznámky pro učiteleJak celou hodinu vést1. Vysvětlení a souvislosti

Tenhle blok je jen pro vás — dětem ho nepromítejte.

Fáze Co se děje Čas
Rozjezd Formička a perníky, tři hrdinové na tabuli bez tříd 10 min
První třída Bloky 2–3, class + new + tečka 20 min
Konstruktor Blok 4 + ukázka 2 15 min
Metody objektu Bloky 5–6 + ukázky 3–4 20 min
static Blok 7 + ukázka 5 10 min
Cvičení Děti pracují samy, vy obcházíte 55 min
Závěr Kdo chce, ukáže svou družinu 10 min
Hlavní pedagogický cíl

Dnešek je největší myšlenkový skok celého kurzu. Do dneška byl program seznam příkazů nad hromadou proměnných. Ode dneška je program parta věcí, které si pamatují svůj stav a něco umí.

Nejde o zapamatování syntaxe. Jde o to, aby dítě dokázalo říct větu: „Postava je plán. Hrdina je konkrétní kus podle toho plánu." Kdo tohle řekne vlastními slovy, tomu je dědičnost příště jasná za deset minut.

Nezačínejte kódem. Začněte formičkou na perníčky. Formička je třída, perníčky jsou objekty. Každý perníček má stejný tvar, ale jinou polevu. Formička sama se nedá sníst.

Tři věci, které dnes NEVYSVĚTLUJTE
  1. Dědičnost. Dnes žádné : za názvem třídy. Přijde příští hodinu a děti by to teď jen zamlžilo.
  2. Referenční typy a haldu. Stačí věta „proměnná drží odkaz na objekt". Detail je v učitelském bloku Technické pozadí.
  3. Rozdíl mezi polem třídy a vlastností do hloubky. Používejte vlastnosti ({ get; set; }) jako výchozí volbu, pole jen tam, kde je opravdu privátní.

Jak pracovat se smíšenou úrovní. Cvičení 1 a 2 zvládne každý — je to opisování s malou obměnou. Cvičení 3 je první, kde se musí přemýšlet (metoda mění stav objektu). Cvičení 4 spojuje třídy se List<T> a je nejlepší na procvičení. Cvičení 5 je celé kolo hry — slabším nechte jen dvě postavy místo tří.

Nejčastější zádrhel hodiny: děti napíšou třídu nad příkazy a překladač zaječí CS8803. V C# s top-level příkazy musí být všechny třídy až úplně dole, pod posledním příkazem. Napište to velkým písmem na tabuli hned na začátku.

Blok 1Tři hrdinové bez tříd = katastrofa1. Vysvětlení a souvislosti

Devět proměnných pro tři hrdiny. A to jsme jim zatím nedali ani zlato, ani úroveň, ani zbraň.

Zkus si představit, co se stane, když:

  • přidáš čtvrtého hrdinu → další tři proměnné,
  • přidáš každému inventář → další čtyři proměnné,
  • chceš seřadit hrdiny podle životů → nejde to, jsou to samostatné krabice, které o sobě nevědí.

Číslovaná jména proměnných jsou vždycky znamení, že se něco dělá špatně. Potřebujeme způsob, jak říct: „tohle všechno patří k sobě a je to jeden hrdina".

Klikni vlevo na Spustit a objeví se tu výstup programu.
Blok 2Třída je formička, objekt je perník1. Vysvětlení a souvislosti

class Postava je plán. Říká: každá postava na světě má jméno a životy. Sama o sobě nic nedělá a nedá se z ní hrát — stejně jako se nedá sníst formička.

new Postava() vyrobí konkrétní kus podle toho plánu. Tomu kusu se říká objekt nebo instance. Můžeš jich vyrobit kolik chceš a každý má svoje vlastní hodnoty.

Tečka je „jeho". hrdina.Jmeno čti jako „hrdinovo jméno".

public znamená „zvenku vidět". Kdyby tam nebylo, C# by údaj schoval a řádek hrdina.Jmeno = "Ela"; by se nepřeložil.

Nejdůležitější pravidlo dneška

V programu s top-level příkazy (tak píšeme celý kurz) musí být deklarace tříd až pod posledním příkazem. Když třídu napíšeš nahoru, dostaneš chybu CS8803: Top-level statements must precede namespace and type declarations.

Klikni vlevo na Spustit a objeví se tu výstup programu.
Blok 3Vlastnosti — údaj, který si hlídá sám sebe1. Vysvětlení a souvislosti

public string Jmeno { get; set; } je vlastnost (property). Zvenku se používá úplně stejně jako pole — hrdina.Jmeno = "Ela"; — ale uvnitř je to dvojice malých metod: get (dej hodnotu) a set (ulož hodnotu).

Tahle podoba se jmenuje automatická vlastnost. C# si sám vyrobí schovanou krabici na hodnotu a ty se o nic nestaráš.

Když potřebuješ hlídat hodnotu, rozepíšeš set ručně, jako u Zivoty. Uvnitř set je vždycky k dispozici proměnná value — to je to, co se přiřazuje. Math.Max(0, value) zajistí, že životy nikdy neklesnou pod nulu.

Proto se v C# skoro vždycky píšou vlastnosti, ne holá pole: až se za měsíc rozhodneš hlídat hodnotu, nemusíš přepisovat zbytek programu.

private znamená opak public — dovnitř vidí jen třída sama.

Klikni vlevo na Spustit a objeví se tu výstup programu.
Blok 4Konstruktor — objekt se narodí rovnou hotový1. Vysvětlení a souvislosti

Konstruktor je metoda, která se spustí při new. Poznáš ho podle dvou věcí: jmenuje se přesně jako třída a nemá návratový typ (není tam void ani int).

Díky němu už nejde vyrobit postavu bez jména. Tenhle řádek se nepřeloží:

Postava nekdo = new Postava();   // CS7036 — chybí argumenty

A to je dobře! Konstruktor je smlouva: „chceš postavu? Řekni mi jméno, životy a sílu, jinak ti ji nedám."

Všimni si dvojího psaní: Jmeno s velkým je vlastnost objektu, jmeno s malým je parametr konstruktoru. Řádek Jmeno = jmeno; znamená „ulož mi, co jsi mi předal".

Když chceš obojí

Konstruktorů může být víc — liší se počtem parametrů. Ten kratší může zavolat delší pomocí : this(...):

Postava novy = new Postava("Míra");
Console.WriteLine($"{novy.Jmeno}: {novy.Zivoty} HP, síla {novy.Sila}");

class Postava
{
    public string Jmeno { get; set; }
    public int Zivoty { get; set; }
    public int Sila { get; set; }

    public Postava(string jmeno, int zivoty, int sila)
    {
        Jmeno = jmeno;
        Zivoty = zivoty;
        Sila = sila;
    }

    public Postava(string jmeno) : this(jmeno, 100, 10) { }
}
Klikni vlevo na Spustit a objeví se tu výstup programu.
Blok 5Metody — objekt umí něco sám se sebou1. Vysvětlení a souvislosti

Metoda uvnitř třídy vidí na svoje vlastnosti bez tečky. V Utoc je Sila automaticky síla toho objektu, na kterém se metoda zavolala.

Když napíšeš hrdina.Utoc(sok), tak uvnitř metody:

  • Jmeno a Sila znamenají Elu,
  • cil znamená Skřeta.

Když napíšeš sok.Utoc(hrdina), role se prohodí. Stejný kód, jiný objekt. Tomuhle se říká, že metoda pracuje nad instancí.

Kdybys chtěl zdůraznit „moje", můžeš psát this.Sila. Znamená to totéž a používá se hlavně tam, kde by se jinak parametr pletl s vlastností.

Všimni si, že JeNazivu() nic nevypisuje — jen vrátí true nebo false. Rozhodování necháváme na tom, kdo metodu volá.

Klikni vlevo na Spustit a objeví se tu výstup programu.
Blok 6ToString — jak se objekt umí představit1. Vysvětlení a souvislosti

Bez ToString() by se vypsalo Postava — jen název typu. Nic užitečného.

Každý objekt v C# metodu ToString() už má (zdědil ji, o tom příště). Slovo override znamená „tuhle hotovou metodu přepíšu po svém".

Odteď se objekt umí představit sám. Funguje to všude, kde se čeká text:

  • Console.WriteLine(hrdina),
  • $"...{hrdina}..." v interpolaci,
  • string.Join(", ", druzina) u celého seznamu.

Je to jedna z nejlevnějších věcí, kterou můžeš třídě přidat, a nejvíc zpřehlední výpisy. Piš ji do každé třídy, kterou vyrobíš.

Klikni vlevo na Spustit a objeví se tu výstup programu.
Blok 7static — co patří celé třídě, ne jednomu objektu1. Vysvětlení a souvislosti

Obyčejná vlastnost patří objektu. Každá postava má svoje jméno.

static patří třídě jako celku. PocetPostav existuje jednou pro všechny postavy dohromady — proto se čte Postava.PocetPostav, ne a.PocetPostav.

Typické použití static:

  • počitadlo vyrobených objektů,
  • konstanta platná pro všechny (MaxZivotu),
  • pomocná metoda, která nepotřebuje žádný objekt.

const je static napevno — hodnota se nikdy nesmí změnit.

Častá chyba

Console.WriteLine(a.PocetPostav); se nepřeloží (CS0176). Statický údaj se čte přes jméno třídy, ne přes objekt.

Klikni vlevo na Spustit a objeví se tu výstup programu.
Poznámky pro učiteleTechnické pozadí — jen pro vás1. Vysvětlení a souvislosti

Třídy jsou referenční typy. Proměnná Postava hrdina nedrží objekt, ale odkaz na něj. Proto se po Postava b = a; mění obě proměnné zároveň — ukazují na tentýž objekt. Dětem to dnes neříkejte teorií, ale mějte to v záloze, až někdo objeví, že „se mu to mění na dvou místech". Krátká demonstrace stačí:

Postava a = new Postava("Ela");
Postava b = a;
b.Jmeno = "Míra";
Console.WriteLine(a.Jmeno);   // Míra!

class Postava
{
    public string Jmeno { get; set; }

    public Postava(string jmeno)
    {
        Jmeno = jmeno;
    }
}

struct vs. class. struct je hodnotový typ a kopíruje se. Do 15 let to nemá smysl otevírat; pokud se někdo zeptá, řekněte „to je stejná myšlenka, ale kopíruje se to místo sdílení".

Automatické vlastnosti nejsou magie — překladač si vyrobí skryté pole (<Jmeno>k__BackingField). Proto je výkonnostně jedno, jestli píšete pole nebo auto-property, a proto se doporučuje vždycky property.

null a NullReferenceException. Neinicializovaná vlastnost typu string je null a hrdina.Jmeno.Length na ní spadne. Řešení pro děti je jednoduché: konstruktor s parametry, který nikdy nenechá nic prázdné. Proto se ke konstruktoru dostáváme hned ve třetím bloku, ne na konci hodiny.

record. Moderní C# má record Postava(string Jmeno, int Zivoty); — jeden řádek místo dvaceti. Vypadá to lákavě, ale děti by pak nepochopily, co se stalo. Ukažte to nejrychlejším jako bonus na konci hodiny, ne dřív.

Pořadí v souboru. Top-level příkazy musí předcházet deklaracím typů (CS8803). V reálném projektu ve VS Code se tenhle problém nestane, protože každá třída má vlastní soubor — a to je přesně to, k čemu se dostaneme v hodině o modulech.

Pojmenování. V C# se vlastnosti a metody píšou PascalCase (Jmeno, Utoc), parametry a lokální proměnné camelCase (jmeno, pocetKol). Trvejte na tom od první minuty, ať si nezvyknou na python_style.

2. Ukázky pro projekci

Blok 8Ukázka 1 — První třída a dva hrdinové2. Ukázky pro projekci
Studenti zkuste změnit
  • Změň jména a čísla u obou postav.
  • Přidej do třídy další vlastnost Zlato a vypiš ji.
  • Vyrob třetí postavu a vypiš ji taky.
  • Zkus přesunout class Postava nahoru nad příkazy a přečti si chybu.
demo/demo1_prvni_trida.cs
Tady se objeví výstupKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.

Co si z toho odnést: jedna třída, dva objekty. Každý new vyrobí nový kus s vlastní pamětí — a class je vždycky až úplně dole.

Blok 9Ukázka 2 — Konstruktor a hlídané vlastnosti2. Ukázky pro projekci
Studenti zkuste změnit
  • Dej hrdinovi záporné životy a sleduj, co udělá set.
  • Přidej do konstruktoru čtvrtý parametr zlato.
  • Zkus vyrobit postavu bez argumentů a přečti si chybu CS7036.
  • Změň MaxZivotu na 200 a zkus nastavit životy na 180.
demo/demo2_konstruktor.cs
Tady se objeví výstupKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.

Co si z toho odnést: set je poslední obrana objektu. Ať mu zvenku pošleš cokoliv, Math.Clamp to srovná do povoleného rozsahu a objekt zůstane platný.

Blok 10Ukázka 3 — Metody objektu: souboj na kola2. Ukázky pro projekci
Studenti zkuste změnit
  • Změň sílu obou soupeřů a sleduj, kdo vyhraje.
  • Přidej metodu Uzdrav(int kolik) a použij ji uprostřed souboje.
  • Zvyš počet kol na 10 a podívej se, co se stane po smrti.
  • Vypiš po každém kole proužek životů z .
demo/demo3_souboj.cs
Tady se objeví výstupKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.

Co si z toho odnést: hrdina.Utoc(skret) a skret.Utoc(hrdina) je jedna metoda ve dvou rolích. Objekt uvnitř metody vždycky pracuje sám se sebou.

Blok 11Ukázka 4 — Celá družina v jednom seznamu2. Ukázky pro projekci
Studenti zkuste změnit
  • Přidej do družiny čtvrtého hrdinu.
  • Seřaď výpis podle životů (OrderByDescending).
  • Spočítej průměrnou sílu družiny.
  • Najdi nejzraněnějšího člena a vypiš jen jeho.
demo/demo4_druzina.cs
Tady se objeví výstupKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.

Co si z toho odnést: List<Postava> funguje úplně stejně jako List<int> — jen místo čísel drží celé objekty. A foreach mění objekty uvnitř seznamu doopravdy, protože seznam drží odkazy.

Blok 12Ukázka 5 — CsQuest: hrdina proti bestiáři2. Ukázky pro projekci
Studenti zkuste změnit
  • Přidej do pole příšer čtvrtou nestvůru.
  • Dej hrdinovi po každém vítězství +2 k síle.
  • Změň semínko v new Random(7) a uvidíš jiný průběh.
  • Přidej příšeře metodu Odmena(), která vrátí zlato podle síly.
demo/demo5_csquest.cs
Tady se objeví výstupKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.

Co si z toho odnést: tohle je celý dnešek pohromadě — dvě třídy, konstruktory, metody, List<T>, náhoda a smyčka. A hlavně: hlavní program je krátký a čitelný, protože všechna práce je schovaná v metodách objektů.

Blok 13Když se něco pokazí2. Ukázky pro projekci
error CS8803: Top-level statements must precede
  namespace and type declarations.

Chyba číslo jedna dnešní hodiny. Třída je napsaná nad příkazy. V programu s top-level příkazy musí být pořadí vždycky takhle:

  1. nejdřív všechny příkazy (Console.WriteLine, cykly, new, …),
  2. teprve pak všechny class.

Řešení je prosté: označ celý blok class ... { ... } a přesuň ho na úplný konec souboru. Nic jiného měnit nemusíš — C# si třídu najde, i když je pod příkazy, které ji používají.

Druhý kandidát na chybu dne je NullReferenceException. Znamená, že proměnná typu objekt nikdy nedostala hodnotu z new, nebo že string vlastnost zůstala prázdná. Lék je vždycky stejný — konstruktor, který všechno vyplní.

Hláška / projev Co to znamená Jak to opravit
CS8803 třída je nad příkazy přesuň všechny class na konec souboru
CS7036 konstruktor chce argumenty, nedostal je new Postava("Ela", 100, 12)
CS1061 ... does not contain a definition for ... překlep v názvu vlastnosti nebo metody zkontroluj velká písmena: Jmeno, ne jmeno
CS0122 ... is inaccessible due to its protection level chybí public dej public před vlastnost nebo metodu
CS0176 statický údaj se čte přes objekt Postava.PocetPostav, ne hrdina.PocetPostav
CS0120 nestatický údaj se čte bez objektu vyrob objekt: new Postava(...) a čti přes něj
NullReferenceException proměnná je prázdná (null) chybí new, nebo vlastnost nikdy nedostala hodnotu
vypíše se jen Postava třída nemá ToString() přidej public override string ToString()
změna u jednoho hrdiny se projeví i u druhého obě proměnné ukazují na stejný objekt vyrob druhý objekt vlastním new
CS0029 Cannot implicitly convert type metoda má void, ale používáš návrat dej metodě návratový typ (int, bool, string)

3. Cvičení

Jak dnes pracovat: každé cvičení staví na předchozím — třída Postava se postupně rozrůstá. Piš do jednoho souboru a nech si ho otevřený, budeš ho potřebovat i příští hodinu.
Blok 14Cvičení 1 — Plán hrdiny (15 min)3. Cvičení

Zadání:

Vyrob první vlastní třídu a postav podle ní dva hrdiny.

  1. Napiš na konec souboru třídu Postava se čtyřmi vlastnostmi
    💡 Poradit
    Třída patří pod všechny příkazy:
    class Postava
    {
    public string Jmeno { get; set; }
    public string Povolani { get; set; }
    public int Zivoty { get; set; }
    public int Sila { get; set; }
    }
    Bez public na ně zvenku neuvidíš.
  2. Vyrob hrdinu pomocí new a vyplň mu všechny čtyři údaje
    💡 Poradit
    Postava hrdina = new Postava();
    hrdina.Jmeno = "Ela";
    Tečka znamená „jeho". Pozor na velká písmena — Jmeno, ne jmeno.
  3. Vypiš hrdinovu vizitku do rámečku
    💡 Poradit
    Rámeček vyrobíš z opakovaného znaku:
    Console.WriteLine(new string('─', 34));
    Údaje zarovnáš v interpolaci:
    Console.WriteLine($" Jméno: {hrdina.Jmeno}");
  4. Přidej druhou postavu a vypiš vizitky obou stejnou pomocnou metodou
    💡 Poradit
    Metodu si napiš mezi příkazy (ne do třídy):
    void Vizitka(Postava p)
    {
    Console.WriteLine($" {p.Jmeno} — {p.Povolani}");
    }
    Pak stačí Vizitka(hrdina); a Vizitka(parta);
  5. Přidej vlastnost Zlato a do vizitky dopiš bojovou hodnotu
    💡 Poradit
    Do třídy přidej public int Zlato { get; set; }
    Bojovou hodnotu spočítej přímo ve výpisu:
    $"Bojová hodnota: {p.Sila * 2 + p.Zivoty / 10}"
Úroveň Co má zvládnout
Minimum Body 1–3, jedna postava a její vizitka
Rozšíření Body 4–5, dvě postavy a společná pomocná metoda
Výzva Přidat třetí postavu a vypsat, kdo má nejvyšší bojovou hodnotu
cviceni/cviceni1_plan_hrdiny.cs
Tady se objeví výstupKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Pro učitele — na co si dát pozor

Očekávaný výsledek: dvě vizitky v rámečcích, každá s jinými údaji a s vlastní bojovou hodnotou.

Kde se zaseknou:

  1. Třída nahořeCS8803. Čekejte to u poloviny třídy. Reagujte pořád stejnou větou: „Kam patří třídy?" — a nechte je odpovědět „dolů".
  2. Malé písmeno v hrdina.jmenoCS1061. Dobrá příležitost ukázat, že VS Code jméno napovídá po napsání tečky (Ctrl+mezerník).
  3. Zapomenuté newPostava hrdina; a pak NullReferenceException. Vysvětlete: „deklarace je jen cedulka, new teprve vyrobí věc."
  4. Metoda Vizitka uvnitř třídy. Někdo ji tam přirozeně napíše — a je to vlastně lepší návrh! Pochvalte a řekněte, že přesně to uděláme ve cvičení 3.

Rychlíkům zadejte třetí postavu a porovnání bojových hodnot pomocí if.

Řešení 1 — jedna z možných variant

Toto je jedna z možných variant. Tvoje řešení se může lišit a to je v pořádku.

reseni/reseni1_plan_hrdiny.cs
Tady se objeví výstupKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Blok 15Cvičení 2 — Konstruktor, který nepustí zmetky (20 min)3. Cvičení

Zadání:

Zařiď, aby se žádná postava nenarodila prázdná ani se zápornými životy.

  1. Přidej do třídy konstruktor se čtyřmi parametry
    💡 Poradit
    Konstruktor se jmenuje jako třída a nemá návratový typ:
    public Postava(string jmeno, string povolani, int zivoty, int sila)
    {
    Jmeno = jmeno;
    ...
    }
  2. Vyrob obě postavy jedním řádkem přes konstruktor
    💡 Poradit
    Postava hrdina = new Postava("Ela", "Strážkyně", 100, 12);
    Pořadí argumentů musí sedět s pořadím parametrů. Řádky hrdina.Jmeno = ... už nepotřebuješ a smaž je.
  3. Přidej metodu ToString() a vypiš postavy rovnou
    💡 Poradit
    Do třídy:
    public override string ToString()
    {
    return $"{Jmeno,-8} {Povolani,-12} {Zivoty,4} HP";
    }
    Pak stačí Console.WriteLine(hrdina);
  4. Změň Zivoty na hlídanou vlastnost v rozsahu 0 až MaxZivotu
    💡 Poradit
    Potřebuješ soukromé pole a ruční get/set:
    private int zivotyUvnitr;
    public int Zivoty
    {
    get { return zivotyUvnitr; }
    set { zivotyUvnitr = Math.Clamp(value, 0, MaxZivotu); }
    }
    A nahoru do třídy public const int MaxZivotu = 150;
  5. Přidej druhý konstruktor pro nováčka, který doplní výchozí hodnoty
    💡 Poradit
    Kratší konstruktor zavolá ten delší:
    public Postava(string jmeno) : this(jmeno, "Nováček", 80, 6) { }
    Pak funguje i new Postava("Míra").
Úroveň Co má zvládnout
Minimum Body 1–2, postavy vznikají jedním řádkem
Rozšíření Body 3–4, ToString() a hlídané životy
Výzva Bod 5 a k tomu ošetřit prázdné jméno (string.IsNullOrWhiteSpace)
cviceni/cviceni2_konstruktor.cs
Tady se objeví výstupKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Pro učitele — na co si dát pozor

Očekávaný výsledek: tři postavy vypsané jedním Console.WriteLine(objekt), životy nikdy mimo rozsah 0–150.

Kde se zaseknou:

  1. Konstruktor s návratovým typem (public void Postava(...)) → C# to bere jako obyčejnou metodu a new Postava("Ela", ...) pak hlásí CS1729. Ukažte rozdíl vedle sebe na tabuli.
  2. Nekonečná rekurze ve vlastnosti: kdo napíše set { Zivoty = value; }, vyrobí StackOverflowException. Musí tam být soukromé pole, ne vlastnost sama.
  3. Zapomenutý override u ToString() → varování a vypíše se název typu.
  4. : this(...) se plete s dědičností. Dnes říkejte jen „tenhle konstruktor si zavolá ten druhý". Dvojtečka za názvem třídy přijde příští hodinu.

Dobrá otázka do třídy: „Proč je lepší mít konstruktor než pět řádků s tečkou?" Odpověď, ke které je chcete dovést: nejde zapomenout na údaj.

Řešení 2 — jedna z možných variant

Toto je jedna z možných variant. Tvoje řešení se může lišit a to je v pořádku.

reseni/reseni2_konstruktor.cs
Tady se objeví výstupKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Blok 16Cvičení 3 — Postava, která umí bojovat (20 min)3. Cvičení

Zadání:

Přesuň chování dovnitř objektu. Postava už nebude jen údaj — bude to někdo, kdo něco umí.

  1. Přidej do třídy metodu JeNazivu(), která vrátí true nebo false
    💡 Poradit
    Metoda uvnitř třídy vidí na vlastnosti bez tečky:
    public bool JeNazivu()
    {
    return Zivoty > 0;
    }
    Nic nevypisuje — jen vrací odpověď.
  2. Přidej metodu Utoc(Postava cil), která sebere cíli životy
    💡 Poradit
    public void Utoc(Postava cil)
    {
    cil.Zivoty = Math.Max(0, cil.Zivoty - Sila);
    }
    Sila je moje síla, cil.Zivoty jsou jeho životy. Math.Max zabrání zápornému stavu.
  3. Přidej metodu ProuzekZivotu(), která vrátí proužek z a
    💡 Poradit
    Nejdřív spočítej délku plné části:
    int delka = Zivoty * 20 / MaxZivotu;
    Pak slož text:
    return $"{Jmeno,-8} │{new string('█', delka).PadRight(20, '░')}│ {Zivoty,4} HP";
  4. Nech oba soupeře bojovat ve smyčce, dokud jeden nepadne
    💡 Poradit
    while (hrdina.JeNazivu() && skret.JeNazivu())
    Uvnitř: hrdina.Utoc(skret); a pak jen když ještě žije if (skret.JeNazivu()) skret.Utoc(hrdina);
    Přidej si pojistku kolo <= 20, ať smyčka nikdy neběží donekonečna.
  5. Přidej lektvary a metodu Uzdrav(), kterou hrdina použije při málo životech
    💡 Poradit
    Do třídy přidej public int Lektvary { get; set; } a metodu:
    public bool Uzdrav(int kolik)
    {
    if (Lektvary <= 0) return false;
    Lektvary--;
    Zivoty = Math.Min(MaxZivotu, Zivoty + kolik);
    return true;
    }
    V souboji: if (hrdina.Zivoty < 30) hrdina.Uzdrav(25);
Úroveň Co má zvládnout
Minimum Body 1–2, útok objektu na objekt funguje
Rozšíření Body 3–4, proužky životů a souboj do konce
Výzva Bod 5 a k tomu hlášku, když hrdinovi dojdou lektvary
cviceni/cviceni3_souboj.cs
Tady se objeví výstupKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Pro učitele — na co si dát pozor

Očekávaný výsledek: souboj proběhne za několik kol, proužky se krátí a hrdina vypije lektvar přesně v okamžiku, kdy klesne pod 30 HP.

Kde se zaseknou:

  1. Sila versus cil.Sila. Nejčastější logická chyba hodiny: dítě napíše cil.Zivoty -= cil.Sila; a soupeř si ubere sám podle své vlastní síly. Nechte je to spustit a ptejte se, proč jsou čísla divná — chyba se najde sama.
  2. Nekonečná smyčka. Když někdo zapomene ubírat životy, prohlížeč se zasekne. Proto je v zadání pojistka kolo <= 20. Trvejte na ní.
  3. Dělení nulou v ProuzekZivotu. Kdo nenastaví MaxZivotu v konstruktoru, dostane DivideByZeroException. Ukažte, že konstruktor je jediné místo, kde se to má nastavit.
  4. Metoda vypisuje i vrací. Diskutujte, proč JeNazivu() nic nevypisuje. Odpověď: „rozhodování patří tomu, kdo se ptá."

Rychlíkům zadejte kritický zásah: každé páté kolo dvojnásobné poškození.

Řešení 3 — jedna z možných variant

Toto je jedna z možných variant. Tvoje řešení se může lišit a to je v pořádku.

reseni/reseni3_souboj.cs
Tady se objeví výstupKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Blok 17Cvičení 4 — Celá družina v jednom seznamu (20 min)3. Cvičení

Zadání:

Tři hrdinové už nebudou tři proměnné. Budou to tři objekty v jednom seznamu.

  1. Vyrob List<Postava> a přidej do něj tři členy družiny
    💡 Poradit
    List<Postava> druzina = new List<Postava>();
    druzina.Add(new Postava("Ela", 100, 12));
    Objekt se dá vyrobit rovnou uvnitř Add — nemusí mít vlastní proměnnou.
  2. Vypiš celou družinu cyklem foreach a spočítej její životy
    💡 Poradit
    foreach (Postava clen in druzina)
    {
    Console.WriteLine(clen);
    }
    Součet: druzina.Sum(p => p.Zivoty), počet: druzina.Count.
  3. Přidej do třídy statické počitadlo vyrobených postav
    💡 Poradit
    Do třídy: public static int PocetPostav = 0;
    Do konstruktoru: PocetPostav++;
    Čte se přes jméno třídy: Console.WriteLine(Postava.PocetPostav);
  4. Spusť past — každému seber 25 životů a zjisti, kdo přežil
    💡 Poradit
    Nejdřív zraň všechny:
    foreach (Postava clen in druzina) clen.Zivoty = Math.Max(0, clen.Zivoty - 25);
    Pak vyfiltruj živé:
    List<Postava> zivi = druzina.Where(p => p.JeNazivu()).ToList();
  5. Vypiš statistiku družiny: nejsilnější, nejzraněnější a průměrná síla
    💡 Poradit
    druzina.OrderByDescending(p => p.Sila).First()
    druzina.OrderBy(p => p.Zivoty).First()
    druzina.Average(p => p.Sila) — výsledek zaokrouhli zápisem {prumer:F1}
Úroveň Co má zvládnout
Minimum Body 1–2, družina v seznamu a její výpis
Rozšíření Body 3–4, statické počitadlo a past
Výzva Bod 5 a k tomu seřadit výpis družiny podle životů
cviceni/cviceni4_druzina.cs
Tady se objeví výstupKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Pro učitele — na co si dát pozor

Očekávaný výsledek: družina tří postav, past vyřadí Míru (má jen 20 HP), statistika sedí a Postava.PocetPostav odpovídá počtu volání new.

Kde se zaseknou:

  1. druzina.PocetPostavCS0176. Skvělá příležitost zopakovat rozdíl mezi „patří objektu" a „patří třídě".
  2. Změna uvnitř foreach. U objektů funguje — protože seznam drží odkazy. Kdo to zkoušel se seznamem čísel, pamatuje si opak. Tohle je nejlepší moment celé hodiny na vysvětlení rozdílu a děti ho pochopí z příkladu, ne z teorie.
  3. Where bez ToList() → typ nesedí (CS0266). Stačí dopsat .ToList().
  4. Average vrací double — bez :F1 se vypíše šest desetinných míst.

Rychlíkům zadejte, ať vyřazené členy ze seznamu skutečně odeberou pomocí druzina.RemoveAll(p => !p.JeNazivu()); a vysvětlí, proč se mazání nesmí dělat uvnitř foreach.

Řešení 4 — jedna z možných variant

Toto je jedna z možných variant. Tvoje řešení se může lišit a to je v pořádku.

reseni/reseni4_druzina.cs
Tady se objeví výstupKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Blok 18Cvičení 5 — CsQuest: výprava na třídách (25 min)3. Cvičení

Zadání:

Poslední cvičení spojí celý dnešek: dvě třídy, kostka a celá výprava do jeskyně.

  1. Napiš druhou třídu Prisera s odměnou a metodou JeNazivu()
    💡 Poradit
    Vypadá skoro stejně jako Postava:
    class Prisera
    {
    public string Jmeno { get; set; }
    public int Zivoty { get; set; }
    public int Sila { get; set; }
    public int Odmena { get; set; }
    }
    Nezapomeň na konstruktor se čtyřmi parametry a na ToString().
  2. Vyrob hrdinu a List&lt;Prisera&gt; se třemi nestvůrami
    💡 Poradit
    List<Prisera> bestiar = new List<Prisera>();
    bestiar.Add(new Prisera("Skřet", 40, 6, 15));
    Pak je projdi foreach a ohlas každé setkání.
  3. Přidej souboj s hodem kostkou
    💡 Poradit
    Random kostka = new Random(7); — se semínkem 7 padne vždycky totéž, dobře se to ladí.
    V metodě: public void Utoc(Prisera cil, int hod) a uvnitř int poskozeni = Sila + hod;
    Volání: hrdina.Utoc(nestvura, kostka.Next(1, 7));
  4. Za každou poraženou nestvůru přidej hrdinovi zlato
    💡 Poradit
    Až vnitřní while skončí, zjisti proč:
    if (!hrdina.JeNazivu()) break;
    hrdina.Zlato += nestvura.Odmena;
    A vypiš hlášku o vítězství.
  5. Na konci vypiš bilanci výpravy a hodnocení
    💡 Poradit
    Poražené spočítáš takhle:
    int poraženo = bestiar.Count(p => !p.JeNazivu());
    Hodnocení zvládne if/else if podle zlata, nebo ternární operátor:
    string znamka = zlato >= 100 ? "legenda" : "učeň";
Úroveň Co má zvládnout
Minimum Body 1–2, bestiář existuje a vypíše se
Rozšíření Body 3–4, souboje s kostkou a zlato za vítězství
Výzva Bod 5 a k tomu +2 k síle hrdiny po každém vítězství
cviceni/cviceni5_vyprava.cs
Tady se objeví výstupKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Pro učitele — na co si dát pozor

Očekávaný výsledek: hrdinka projde všechny tři nestvůry (se semínkem 7 to vyjde), nasbírá 105 zlata a získá titul „legenda jeskyně".

Kde se zaseknou:

  1. Dvě třídy, které o sobě vědí. Postava.Utoc má parametr typu Prisera a naopak. Někdo se zděsí, že to nemůže fungovat, protože Prisera je napsaná níž. Uklidněte je: v jednom souboru na pořadí tříd nezáleží, překladač si nejdřív přečte celý soubor.
  2. break na špatném místě. Když break chybí, hrdina pokračuje mrtvý. Ukažte, že vnitřní while může skončit ze dvou důvodů a musíme rozlišit, který nastal.
  3. Vnořený while uvnitř foreach. Pro některé je to první dvojitá smyčka s objekty. Pomůže nakreslit to na tabuli jako „pro každou příšeru: bojuj, dokud…".
  4. Náhoda bez semínka. S new Random() se výsledek pokaždé liší a děti nevědí, jestli mají chybu, nebo smůlu. Při ladění trvejte na new Random(7).

Závěr hodiny: nechte tři dobrovolníky promítnout bilanci své výpravy. Zeptejte se, kolik proměnných by na to potřebovali bez tříd.

Řešení 5 — jedna z možných variant

Toto je jedna z možných variant. Tvoje řešení se může lišit a to je v pořádku.

reseni/reseni5_vyprava.cs
Tady se objeví výstupKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.

4. Domácí úkol

Blok 19Domácí úkol na příští hodinu4. Domácí úkol

Uprav svůj CsQuest tak, aby hrdina i příšery byly objekty, ne hromada proměnných.

  • třída Postava s konstruktorem, který vyplní všechny údaje,
  • alespoň tři metody uvnitř třídy (Utoc, JeNazivu, Uzdrav, ProuzekZivotu — vyber si),
  • vlastní ToString(), aby se postava uměla vypsat jedním řádkem,
  • alespoň jedna hlídaná vlastnost (životy nikdy pod nulu),
  • družina nebo bestiář v List<T> a alespoň jedna statická položka.

Ulož soubor a přines ho na příští hodinu — budeme z něj stavět dál.

Pro učitele

Tenhle úkol je vstupenka do příští hodiny. Dědičnost se nedá učit na dětech, které nemají vlastní třídu. Kdo úkol nemá, dejte mu na začátku příští hodiny hotovou Postava ke zkopírování — ať nezůstane mimo hru.

Na co se při kontrole dívat: ne na počet řádků, ale na to, jestli je hlavní program kratší než před hodinou. To je hlavní přínos tříd a děti to samy vidí, když si obě verze postaví vedle sebe.

Časté doma vzniklé nedorozumění: děti si myslí, že static je „lepší", protože se to píše kratší cestou. Vysvětlete znovu: static je pro to, co je společné všem, ne pro to, co má každý svoje.

Zobrazit ukázkové řešení domácího úkolu

Toto je jedna z možných variant, jak mohl úkol dopadnout. Tvoje řešení se může lišit a to je v pořádku.

domaci/domaci_ukol15.cs
Tady se objeví výstupKlikni na Spustit. Kód vlevo můžeš měnit a spouštět opakovaně klávesami Ctrl+Enter.
Kód vlevo jde upravovat. Tab odsazuje o čtyři mezery.
Blok 20Oficiální dokumentace4. Domácí úkol

Oficiální dokumentace je místo, kam se programátoři chodí podívat, když si chtějí něco ověřit nebo zjistit víc detailů. Je většinou v angličtině, ale to nevadí — zkus se orientovat podle názvu příkazu a podle ukázek kódu.

Co jsme použili Oficiální dokumentace Co tam najdeš
class Třídy co je třída a jak se deklaruje
objekty a new Objekty jak vzniká instance a co se při tom děje
{ get; set; } Vlastnosti automatické i ručně psané vlastnosti
konstruktor Konstruktory více konstruktorů a : this(...)
public / private Modifikátory přístupu kdo na co zvenku vidí
static Klíčové slovo static co patří třídě místo objektu
const Konstanty hodnoty, které se nesmí změnit
ToString() Object.ToString jak se objekt převádí na text
this Klíčové slovo this odkaz na sebe sama
Math.Max, Math.Clamp Math matematické pomůcky
List<T> List<T> seznam objektů a jeho metody
Top-level statements Program bez Main proč musí být třídy až dole
Jak s dokumentací pracovat na hodině

Stránka o vlastnostech je dnes nejužitečnější — má tam příklad ručně psaného set s kontrolou hodnoty, což je přesně to, co děláme ve cvičení 2.

Ve VS Code funguje i zkratka: napsat do třídy prop a zmáčknout Tab. Editor doplní celou vlastnost. Ukažte to až po tom, co si ji jednou napíšou ručně — jinak se ji nenaučí přečíst.

5. Umíme informatiku

Blok 21Navazující cvičení na Umíme informatiku5. Umíme informatiku

Pro rychlejší studenty, kteří dokončí cvičení dřív, nebo na posledních 10–15 minut.

Cvičení Odkaz Proč se hodí
Programování — základy umimeinformatiku.cz čtení cizího kódu, dnes hlavně práce s daty
Proměnné a výrazy umimeinformatiku.cz co je uvnitř proměnné po několika přiřazeních
Funkce a procedury umimeinformatiku.cz metoda, parametr a návratová hodnota — základ dnešních metod objektu

Sekce o funkcích je dnes obzvlášť vhodná, protože metoda objektu je pořád jen funkce — jen ví, ke komu patří.

Jak to zařadit

Nejlepší bonus pro rychlíky ale není online cvičení, ale otázka: „Vymysli třídu, která s hrou nesouvisí — třeba Kniha, Pizza nebo Mobil. Jaké má vlastnosti a co umí?" Deset minut a je hotová abstrakce, kterou by jinak vysvětlovali půl hodiny.