|
|
# 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:
|
|
|
|
|
|
```json
|
|
|
[
|
|
|
{
|
|
|
"name":"directdamage",
|
|
|
"cost":5
|
|
|
},
|
|
|
]
|
|
|
```
|
|
|
|
|
|
Vytvorte si rozhranie `ISpellDataProvider` a dve metódy:
|
|
|
|
|
|
```csharp
|
|
|
public interface ISpellDataProvider
|
|
|
{
|
|
|
public Dictionary<string, SpellInfo> LoadSpellInfo();
|
|
|
public Dictionary<string, int> LoadSpellEffects();
|
|
|
}
|
|
|
```
|
|
|
|
|
|
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:
|
|
|
|
|
|
```csharp
|
|
|
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.
|
|
|
|
|
|
```csharp
|
|
|
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:
|
|
|
|
|
|
```csharp
|
|
|
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í:
|
|
|
|
|
|
```csharp
|
|
|
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:
|
|
|
|
|
|
```csharp
|
|
|
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ť. |