Skip to content

GitLab

  • Projects
  • Groups
  • Snippets
  • Help
    • Loading...
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in
P PVJCs2021
  • 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
    • Package Registry
    • 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
  • PVJCs2021
  • Wiki
  • cv4

Last edited by Ing. Lukáš Hruška Oct 10, 2021
Page history
This is an old version of this page. You can view the most recent version or browse the 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
  • assignment 1
  • assignment 2
  • cv10
  • cv2
  • cv3
  • cv4
  • cv5
  • cv7
  • cv8
  • cv9
  • exam 0
  • exam 1
  • exam 2
  • exam 3
  • exam 4
View All Pages