Skip to content

GitLab

  • Projects
  • Groups
  • Snippets
  • Help
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in
P PVJCs20
  • Project overview
    • Project overview
    • Details
    • Activity
    • Releases
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 0
    • Issues 0
    • List
    • Boards
    • Labels
    • Service Desk
    • Milestones
  • Merge requests 0
    • Merge requests 0
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Operations
    • Operations
    • Incidents
    • Environments
  • Packages & Registries
    • Packages & Registries
    • Container Registry
  • Analytics
    • Analytics
    • CI/CD
    • Repository
    • Value Stream
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Members
    • Members
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Ing. Lukáš Hruška
  • PVJCs20
  • Wiki
  • cv4

Last edited by Ing. Lukáš Hruška Oct 12, 2020
Page history

cv4

Cvičenie 4

Cieľom dnešného cvičenia bude precvičiť si dedenie, abstraktné triedy a ukážeme si ďalší návrhový vzor - Command a tiež sa pohráme s užívateľským vstupom.

4.1 Observer - part 2

Na minulom cvičení sme si ukázali jednoduchú implementáciu observera. Malo to však zásadnú chybu - nedokázal zistiť, v akom stave aktuálne IObservable je.

Toto vieme vyriešiť niekoľkými spôsobmi. Jedno riešenie (bez použitia typových parametrov) si uvedieme:

Pridajte do konštruktora pre Crystal referenciu na PowerSource ku ktorému bude pripojený. Následne z tohoto konštruktora viete priamo dať subscribe a keďže máte referenciu, viete sa aj spýtať na stav.

Ďalší krok (aj keď teraz nie úplne nutný, keďže PowerSource nadobúda iba 2 stavy) je získať aktuálny stav - upravte teda IObserver:

void Notify(IObservable)

V Crystal upravte zodpovedajúcu metódu aby ste získali

4.2 Abstract thinking

Naposledy sme si vytvorili 2 triedy, ktoré mali časť funkcionality rovnakú, dnes sa pozrieme ako by sme mohli túto časť dať dokopy.

Vytvorte si triedu AbstractSwitchable nech táto rozširuje AbstractActor a implementuje ISwitchable.

Metódy Toggle(), IsOn(), TurnOn(), TurnOff() v Crystal majú na prvý pohľad veľmi podobnú implementáciu ako aj v PowerSource. Rozdiel je len v UpdateAnimation() na ktorý sa odkazujú.

Z Crystal presuňte Toggle, IsOn, TurnOn, TurnOff do AbstractSwitchable (samozrejme to vymažte z PowerSource). Chýbajúcu UpdateAnimation() iba deklarujte ako abstract a ponechajte implementácie, ktoré už máte v Crystal a PowerSource - toto zabezpečí, že budú použité zodpovedajúce implementácie, ale nemusíte zbytočne opakovať kód, ktorý je spoločný. Nastala chyba... C# neumožňuje prekrývať ľubovoľné metódy, iba tie, ktoré sú na to označené - keyword virtual. Doplňte ho tam.

private virtual void UpdateAnimation()

_UpdateAnimation() nepotrebujete volať z iných tried, teda by mala byť private - keďže ale ju chceme prekrývať, tak musí byť minimálne dostupná v triedach potomkov, ale nechceme aby bola verejná. Tu sa nám hodí použiť tretí modifikátor prístupu - protected (dostupné iba vrámci triedy a jej potomkov).

4.3 base class

Vytvorte si triedu CrackedCrystal - bude sa jednať o kryštál, ktorý je poškodený a dá sa rozsvietiť len x-krát. Ako predka(rodiča) zoberte Crystal.

Prekryte TurnOn() (nezabudnite v AbstractSwitchable upraviť deklaráciu aby obsahovala virtual)

Teraz už je možné túto metódu prekryť, tak v CrackedCrystal upravte implementáciu tak, aby sa len x-krát zapol, potom sa už nič nestane.

Prekrytím metódy je schovaný pôvodný kód, ale nie je úplne stratený - pomocou base sa k nemu vieme dostať:

base.TurnOn();

Pridajte aj nový konštruktor s ďalším parametrom - počtom zapnutí (int). Využite kód, ktorý ste už implementovali v Crystal. Konštruktory je možné vzájomne volať pomocou this (vrámci jednej triedy) a base pre konštruktor rodičovskej triedy:

public class DerivedClass : BaseClass
{
    public DerivedClass() : base()
    {
        //magic happens here
    }
    public DerivedClass(string s) : base()
    {
        //some more magic happens here
    }

    public DerivedClass(int x) : this()
    {
        //and magic again
    }
}

4.4 Cometh forth mine own apprentice

Nadišiel čas, vševediaci Merlin volá svojho učňa. Predstúp!

Vytvorte si triedu Player (rozširuje AbstractActor), ako animáciu použite player.png - v prípade, že sa hráč otočí, použite Animation.FlipAnimation() a keď sa nehýbe Animation.Stop()

4.5 Didst thee forget how to moveth?

Ale, ako sa hýbať?

Asi najjednoduchšie by bolo priamo do update implementovať čítanie klávesnice a upravovať takto pozíciu. Ale prečo si to trošku neskomplikovať?

Vytvorte si interface IMovable (nech sa nachádza v namespace Merlin.Actors) - tento interface v sebe nebude mať žiadnu funkcionalitu, jedná sa o tzv. marker interface - slúži len na odlíšenie tried.

Nech Player implementuje IMovable

V engine máte definovaný ďalší interface:

public interface Command
{
    void Execute();
}

Jedná sa o základ rovnomenného návrhového vzoru. Teraz si ho implementujeme.

Vytvorte si priečinok Commands a pridajte si do neho triedu Move (implementuje Command).

Nech je konštruktor deklarovaný nasledovne: public Move(IMovable movable, int step, int dx, int dy) kde step udáva rýchlosť a dx a dy udávajú smer pohybu.

Svet používa klasické indexovanie súradníc ako v poli, kde ľavý horný roh má [0,0], X-ová súradnica je vodorovná a rastie doprava, Y-ová je zvislá a rastie smerom dole.

Nezabudnite vykonať typovú kontrolu, či ste dostali objekt, ktorý je aj Actor. Ak by to neplatilo, program nesmie pokračovať - vyvolajte chybu (s vhodnou chybovou hláškou):

throw new ArgumentException("error message goes here");

Ak chybu nikde v kóde neošetríme, toto spôsobí, že program spadne - čo je dnes náš cieľ.

V Execute() zabezpečte zmenu pozície IMovable actora - využite metódy GetX, GetY a SetPosition

V triede Player si na vhodnom mieste (asi konštruktor) inicializujte veci potrebné pre pohyb zabezpečte, aby sa v metóde Update vykonalo čítanie z klávesnice a zodpovedajúci pohyb vykonajte pomocou návrhového vzoru command.

Čítanie z klávesnice je dostupné pomocou triedy Input. Táto implementuje vzor Singleton, ktorý umožňuje mať vždy len jednu dostupnú inštanciu - dostanete sa ku nej pomocou GetInstance()

Príklad použitia ste mali na minulom cvičení. Okrem IsKeyPressed je dostupná aj metóda IsKeyDown, vyskúšajte si ich, aký je v nich rozdiel?

Klávesy sú vymenované v Input.Key, zatiaľ sú pre nás zaujímavé Input.Key.UP / DOWN /LEFT / RIGHT - tieto mapujú šípky.

Nezabudnite si hráča pridať do sveta a svoju implementáciu vyskúšať.

S využitím command dokážeme zabezpečiť aj viaceré nezávislé pohyby - napríklad vstup od užívateľa a gravitáciu, prípadne odkopnutie atď.

Clone repository
  • assignment2
  • cv2
  • cv3
  • cv4
  • cv5
  • cv6
  • cv7
  • cv8
  • cv9
  • exams
    • 1.md
    • 2.md
    • 3.md
    • 3b.md
    • 4.md
    • 5.md
View All Pages