|
|
# Cvičenie 7
|
|
|
|
|
|
## 7.1 Gimme a plan
|
|
|
|
|
|
Player a Enemy majú niečo spoločné vo svete - sú to postavičky. Zatiaľ sme ich považovali iba za actorov, ale narozdiel od predmetov (kotlík, pec) by mali mať ešte niečo navyše - život a pohyb.
|
|
|
|
|
|
Vytvorte si rozhranie `ISpeedStrategy` ktoré bude mať jednu metódu: `double GetSpeed()`. Vytvorte si triedy `NormalSpeedStrategy` a `ModifiedSpeedStrategy`.
|
|
|
|
|
|
Vytvorte si teda rozhranie `ICharacter` nech rozširuje `IMovable`. Vytvorte si abstraktnú triedu `AbstractCharacter`, ktorá bude implementovať `ICharacter, IMovable` a samozrejme rozširovať `AbstractActor`
|
|
|
|
|
|
nech `ICharacter` definuje nasledujúce metódy:
|
|
|
|
|
|
```csharp
|
|
|
void ChangeHealth(int delta);
|
|
|
int GetHealth();
|
|
|
void Die();
|
|
|
void AddEffect(ICommand effect);
|
|
|
void RemoveEffect(ICommand effect);
|
|
|
```
|
|
|
|
|
|
Do `IMovable` pridajte nasledujúce metódy:
|
|
|
|
|
|
```csharp
|
|
|
void SetSpeedStrategy(ISpeedStrategy);
|
|
|
double GetSpeed();
|
|
|
```
|
|
|
|
|
|
kde effect bude uložený do zoznamu a vykonaný počas update. Môžu tu byť veci, ako periodické dopĺňanie života / many, DoT efekty, spomalenie, zrýchlenie...
|
|
|
|
|
|
Triedu `Move` upravte Move tak, aby pracovala s desatinnými číslami. Speed sa nebude udávať v konštruktore, ale bude pýtaný od `IMovable` (keďže pozícia actora musí byť celé číslo, zabezpečte, aby sa rozdiel akumuloval a následne pripočítal keď dosiahne 1).
|
|
|
|
|
|
Obidve triedy SpeedStrategy implementujte tak, aby používali __návrhový vzor strategy__ a tiež modifikujte AbstractCharacter tak, aby využíval spomínané triedy na nastavenie rýchlosti.
|
|
|
|
|
|
Upravte triedy `Player` a `Enemy` tak aby rozširovali `AbstractCharacter`. `Enemy` premenujte na `Skeleton`.
|
|
|
|
|
|
Pridajte si enum `ActorOrientation` ktorý bude obsahovať dve hodnoty: `FacingLeft` a `FacingRight`. Využite ho na určenie orientácie actora vo svete.
|
|
|
|
|
|
## 7.2 I smell magic in here
|
|
|
|
|
|
Vytvorte si:
|
|
|
|
|
|
- priečinok Spells
|
|
|
- rozhrania `IWizard`, `ISpell`, `ISpellBuilder`, `ISpellDirector`
|
|
|
- triedy
|
|
|
- `ProjectileSpell : AbstractActor, IMovable, ISpell`
|
|
|
- `SelfCastSpell : ISpell`
|
|
|
- `ProjectileSpellBuilder : ISpellBuilder`
|
|
|
- `SelfCastSpellBuilder : ISpellBuilder`
|
|
|
- `SpellEffectFactory : IFactory`
|
|
|
- `SpellDirector : ISpellDirector`
|
|
|
- `SpellInfo`
|
|
|
- enum `SpellType`
|
|
|
|
|
|
```csharp
|
|
|
public Interface IWizard : IActor
|
|
|
{
|
|
|
void ChangeMana(int delta);
|
|
|
int GetMana();
|
|
|
void Cast(ISpell spell);
|
|
|
}
|
|
|
|
|
|
public class ISpell
|
|
|
{
|
|
|
ISpell AddEffect(ICommand effect);
|
|
|
void AddEffects(IEnumerable<ICommand> effects);
|
|
|
int GetCost();
|
|
|
void Cast();
|
|
|
}
|
|
|
|
|
|
public interface ISpellBuilder
|
|
|
{
|
|
|
ISpellBuilder AddEffect(string effectName);
|
|
|
ISpellBuilder SetAnimation(Animation animation); //unused for self-cast spells
|
|
|
ISpellBuilder SetSpellCost(int cost);
|
|
|
ISpell CreateSpell(IWizard caster);
|
|
|
}
|
|
|
|
|
|
public interface ISpellDirector
|
|
|
{
|
|
|
ISpell Build(string spellName);
|
|
|
}
|
|
|
|
|
|
public class SpellInfo
|
|
|
{
|
|
|
public string Name { get; set; }
|
|
|
public SpellType SpellType { get; set; }
|
|
|
public IEnumerable<string> EffectNames { get; set; }
|
|
|
public string AnimationPath { get; set; }
|
|
|
public int AnimationWidth { get; set; }
|
|
|
public int AnimationHeight { get; set; }
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Nech `ProjectileSpell` a `SelfCastSpell` majú v sebe konštruktor v ktorom dostanú referenciu na toho, kto to vyčaroval a `IEnumerable<ICommand>` zoznam efektov.
|
|
|
|
|
|
Nech `SpellType` určuje, či sa jedná o self-cast alebo projektil.
|
|
|
|
|
|
Vytvorte si efekty (triedy, implementujúce ICommand): damage over time, speed change, heal, heal over time a samozrejme podľa chuti ďalšie.
|
|
|
|
|
|
Každý efekt má svoju cenu, výsledná cena kúzla bude súčet cien jednotlivých efektov (pre self-cast nech je táto cena upravená, napr. 70%).
|
|
|
|
|
|
Implementujte `ProjectileSpellBuilder`, `SelfCastSpellBuilder` a `SpellDirector` ako návrhový vzor builder a nech `SpellDirector` v sebe obsahuje dva slovníky: `Dictionary<string, int>` kde bude cena jednotlivých efektov a `Dictionary<string, SpellInfo>` kde budú uložené zoznamy efektov pre jednotlivké kúzla. Zatiaľ si tieto slovníky inicializujte ručne, nabudúce si ukážeme ako si ich načítať zo súboru. |