Cvičenie 7
Changelog:
-
IMovable: double GetSpeed(double speed)fixed definition to properly reflect strategy pattern (originallydouble GetSpeed())
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(double speed). 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:
void ChangeHealth(int delta);
int GetHealth();
void Die();
void AddEffect(ICommand effect);
void RemoveEffect(ICommand effect);
Do IMovable pridajte nasledujúce metódy:
void SetSpeedStrategy(ISpeedStrategy);
double GetSpeed(double speed);
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, ISpellSelfCastSpell : ISpellProjectileSpellBuilder : ISpellBuilderSelfCastSpellBuilder : ISpellBuilderSpellEffectFactory : IFactorySpellDirector : ISpellDirectorSpellInfo
- enum
SpellType
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.