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
  • cv5

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

cv5

Cvičenie 5

BREAKING CHANGES: PREMENOVANÉ ROZHRANIA - PRIDANÁ PREDPONA I (ICommand, IWorld, IPhysics) aby boli dodržané C# naming conventions

5.1 There are no ghosts here

Pri implementácií Move ste zatiaľ neriešili kolíziu s prostredím. Napriek tomu, že už od nepamäti poznáme spôsob, ako prechádzať cez steny (nazvali ho dvere), v hre by bolo implementovať funkcionalitu, ako postavičke zabrániť v pohybe cez stenu.

Každý actor v sebe udržuje referenciu na svet, v ktorom existuje. Viete sa k nej dostať cez GetWorld(). Svet má v sebe uložených všetkých actorov a takiež pozná rozloženie mapy - máte dostupnú metódu bool IntersectsWithWall(IActor). Použite ju a doplňte implementáciu tak, aby sa pomocou Move nedalo chodiť cez stenu.

5.2 Newton's legacy

Píše sa rok 1687 a sir Isaac Newton práve publikoval dielo, ktoré zmenilo svet, s názvom Principia. Zažite tento slávny moment a objavte gravitáciu:

Vytvorte si triedu Gravity v priečinku Commands. Nech implementuje rozhranie IPhysics - jedná sa o okrášlený ICommand - je tu navyše metóda SetWorld - táto sa volá automaticky v rámci frameworku pri nastavení fyziky sveta a dostanete v nej referenciu na IWorld - uložte si ju, budete ju potrebovať.

IPhysics.Execute() sa automaticky volá stále v hernej slučke - viete teda v Gravity implementovať postupné padanie predmetov:

  • Každý actor implementuje 2 metódy - bool IsPhysicsEnabled() a void SetPhysics(bool isPhysicsEnabled) - pomocou nich dokážeme regulovať, či bude daný actor ovplyvnený fyzikou alebo nie - môžeme takto nechať nejaký predmet lietať vo vzduchu.
  • IWorld má v sebe metódu GetActors() - táto vráti zoznam všetkých actorov vo svete.
  • Zatiaľ využite Move na pád, ale musíte stále vytvárať nové inštancie (dočasne zakomentujte typovú kontrolu pre IMovable v Move (a upravte ho, nech akceptuje IActor nie IMovable) - za chvíľu sa k tomu vrátime a ukážeme si niečo viac o práci s typovými parametrami a Action design pattern) - nevýhoda je zvytočné vytváranie množstva objektov.
  • v cykle, napríklad foreach si implementujte pád, nezabudnite zohľadniť či je daný predmet ovplyvnený gravitáciou.

Nezabudnite si pridať do sveta gravitáciu - container.GetWorld().SetGravity(new Gravity())!

5.3 Aaaand Action<T>

V priečinku commands si vytvorte Interface IAction:

public interface IAction<T>
{
    public void Execute(T t);
}

ako už deklarácia napovedá, jedná sa o niečo podobné ako ICommand ale je tu jeden rozdiel - v rámci execute vieme poslať nejaký parameter. Toto vieme využiť pri našej implementácií pádu - nepotrebujeme vytvárať nový objekt pre každého actora ale použijeme stále ten istý.

Pridajte si do Commands triedu Fall, nech implementuje IAction - máme tu dva spôsoby implementácie (použite druhý):

public class Fall : IAction<IActor>
{
    public void Execute(IActor t)
    {
        //magic with actor
    }
}

public class Fall<T> : IAction<T> where T : IActor
{
    public void Execute(T t)
    {
        //magic with something, that implements IActor
    }
}

Takýmto spôsobom sa vyhneme unboxingu a samozrejme aj zbytočnému vytváraniu množstva objektov - to však neznamená, že Command je zlý, ešte sa nám bude hodiť.

Implementujte pád (nezabudnite odstrániť komentáre).

5.4 LINQ and Lambdas

Stále prechádzať zoznamy je často nutné a nie veľmi praktické. Našťastie máme funkcionalitu, ktorá nám toto vie zjednodušiť. V C# vieme aplikovať rôzne filtre na kolekcie pomocou fukcií, ktoré dostanú ako vstupný parameter filter (lambda výraz alebo referenciu na funkciu).

Najprv potrebujeme pridať zodpovedajúci namespace (using System.Linq) - následne vieme aplikovať tzv. extension methods na rôzne kolekcie, napríklad:

List<int> values;
//add some values into the list

List<int> negativeValues = values.Where(x => x < 0).ToList(); //select values smaller than 0, the result is then converted into a list (it is IEnumerable by default)
int smallestValue = values.OrderBy(x => x).First(); //select the smalest value (order them and select the first one)
int firstPositive = values.First(x => x > 0); //select the first positive value from the list
int numberOfPositiveValues = values.Where(x => x > 0).Count(); //count the number of positive values

List<IActor> actors//init and stuff...

IActor actor = actors.Find(a => a.GetName().Equals("player")); //select single entry

Samozrejme, dostupných metód je oveľa viac, ako sme tu ukázali, môžete si ich pozrieť napr. cez dopĺňanie kódu alebo na internete.

Modifikujte foreach tak, aby prechádzal iba actorov, na ktorých vplýva gravitácia.

tip: ak trošku predbehneme, existuje aj foreach verzia, ktorá akceptuje lambda výraz, tu by to fungovalo nasledovne:

//void DoStuff(IActor actor);
actors.ForEach(a => DoStuff(a));

Viac o lambda výrazoch nájdete tu: Microsoft dokumentácia

5.5 Jump

Vytvorte triedu Jump, ktorá umožní hráčovi skákať, zvážte použité rozhranie.

5.6 My very own enemy

Vytvorte triedu Enemy (rozširuje AbstractActor).

Použite enemy.png ako animáciu.

V Update implementujte funkcionalitu, že ak sa hráč k nepriateľovi priblíži na vzdialenosť N pixelov, začne ho prenasledovať. Pokiaľ je obeť v nedohľadne, nech sa nepriateľ náhodne prechádza po mape.

Random random = new Random(); //initialize pseudorandom number generator, do this only once

//some awesome code...

int x = random.Next(min,max); //get random number from the given range
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