Cvičenie 8
Dnes si dokončíme kúzla a pridáme si ešte zopár relatívne jednoduchších vecí, ktoré potrebujeme na vyplnenie sveta. Nič zložité... naozaj.
8.1 File not found
Minulý týždeň sme si pripravili nástroje na vytváranie kúziel. Ale žiadne kúzlo sme si nepridali. Bol to celkom zložitý proces, ktorý nám zabezpečil, že sme si nemuseli pre každé vytvárať osobitnú triedu.
Vytvorte si 2 súbory - spells.csv a effects.json v resources:
Nech v sebe spells.csv obsahuje:
name;spelltype;animationpath;animationwidth;animationheight;effect1,effect2,effect3
a effects.json nech je JArray:
[
{
"name":"directdamage",
"cost":5
},
]
Vytvorte si rozhranie ISpellDataProvider
a dve metódy:
public interface ISpellDataProvider
{
public Dictionary<string, SpellInfo> GetSpellInfo();
public Dictionary<string, int> GetSpellEffects();
}
Vytvorte si triedu SpellDataProvider
, nech táto implementuje rozhranie ISpellDataProvider
a návrhový vzor Singleton.
Môžete predpokladať, že súbory budú mať stále rovnaký názov (hardcoded file names are okay here).
Mohli by sme si pridať do SpellInfo
konštruktor, kde by sa načítaný riadok parsoval. Tiež by sme si mohli tento riadok rozdeliť už pri načítaní a nastaviť jednotlivé vlastnosti priamo. Čo keby sme sa ale rozhodli napísať niečo takéto:
SpellInfo spellInfo = "name;spelltype;animationpath;animationwidth;animationheight;effect1,effect2,effect3"
C# hneď začne protestovať - nerozumie, ako spolu súvisí SpellInfo
a string
. Vieme si (v SpellInfo
) naprogramovať operátor, ktorý nám zabezpečí konverziu.
public static implicit operator SpellInfo(string data)
{
//magic & stuff
return spellInfo;
}
Na prvý pohľad to vyzerá super, ale implicitný operátor nemusí byť správne pochopený. Dávajte si na to pozor. Možno vhodnejšie by bolo použiť explicit
- v tomto prípade je potrebné pretypovať ručne.
poznámka: String viete rozdeliť pomocou String.Split
Čo sa týka efektov, tu máme mapovanie medzi JArray a doteraz neznámym typom.
C# pozná typ dynamic
(všetko je riešené runtime), ale je podstatne pomalší. Hodí sa keď nevieme pri kompilácií povedať, čo bude obsahovať. My to ale vieme, takže nám stačí si definovať novú triedu. Nepotrebujeme, aby bola dostupná nikde inde, iba počas parsovania JSON-u. Vytvorte si v SpellDataProvider
vnorenú triedu private class SpellEffect
ktorá bude slúžiť ako model pre čítanie daného jsonu.
Na samotné čítanie použite:
JsonConvert.DeserializeObject<List<CustomerJson>>(json);
V prípade, že sa objaví pri čítaní hociktorého súboru neplatná hodnota, vyvolajte vhodnú výnimku s informatívnou chybovou správou (pravdepodobne ArgumentException
). Zabezpečte, aby sa načítali všetky platné riadky (nech program nespadne!). Ak by sa vyskytla iná (neočakávaná chyba), program má spadnúť.
Dokončite funkcionalitu kúziel tak, aby ich mohol hráč po stlačení tlačidla vyčarovať. (môžete si ich nastaviť napríklad na čísla na klávesnici).
8.2 Watch where you step
Toto by už mala byť len formalita, nič nové, ale treba nám to vo svete - vytvorte si triedy Door
, Switch
, PressurePlate
. Zabezpečte, aby sa dvere otvorili / zatvorili pri prepnutí spínača / boli otvorené, keď je stlačený tlakový senzor - stojí na ňom ICharacter
(nezabudnite na vzor observer).
Pridajte si interface IUsable
s metódou void Use(IActor user)
. Nech Player
po stlačení tlačidla použije jednu IUsable
vec, ak je v kontakte.
Nepriechodnosť prostredia zabezpečte pridaním a odstránením stien na súradniciach dverí:
World.SetWall
World.Iswall
World.GetTileHeight
World.GetTileWidth
Súradnice si musíte prerátať na pozíciu dlaždice v mriežke.
8.3 Did I ever tell you the definition of insanity
more characters + box, state
Vytvorte si triedy LivingState
a DyingState
- bude sa jednať o návrhový vzor state. Toto bude stav hráča, keď je nažive, všetko funguje normálne. Keď zomrie (zavolá sa Player.Die
) nastavte stav na DyingState
- zmení sa animácia a už nie je možné hráča ovládať.
Stav hráča viete na obrazovku zobraziť pomocou:
Message msg = new Message(String text, int x, int y); //optional arguments: fontSize, duration
GetWorld().ShowMessage(msg);
Pridajte si ešte triedu Box
. Nech sa jedná o character. Zabezpečte, aby ju hráč vedel svojím pohybom tlačiť.