2010-02-08 10 views
7

Ich arbeite an einem Rollenspiel zum Spaß und um Designmuster zu üben. Ich möchte, dass Spieler sich in verschiedene Tiere verwandeln können. Zum Beispiel könnte ein Druide in der Lage sein, sich in einen Gepard zu verwandeln. Im Moment plane ich, das Dekoratormuster zu benutzen, aber meine Frage ist - wie kann ich es so machen, dass, wenn ein Druide in der Gepardenform ist, er nur auf Fähigkeiten für den Gepard zugreifen kann? Mit anderen Worten, sie sollten nicht in der Lage sein, auf ihre normalen Druidenfähigkeiten zuzugreifen.Überlegungen zum Design für die vorübergehende Umwandlung eines Spielers in ein Tier in einem Rollenspiel

Mit dem Dekorator-Muster erscheint es, dass sogar in der Cheetah-Form mein Druide in der Lage ist, auf ihre normalen Druidenfähigkeiten zuzugreifen.

class Druid : Character 
{ 
    // many cool druid skills and spells 
    void LightHeal(Character target) { } 
} 

abstract class CharacterDecorator : Character 
{ 
    Character DecoratedCharacter; 
} 

class CheetahForm : CharacterDecorator 
{ 
    Character DecoratedCharacter; 
    public CheetahForm(Character decoratedCharacter) 
    { 
     DecoratedCharacter= decoratedCharacter; 
    } 

    // many cool cheetah related skills 
    void CheetahRun() 
    { 
     // let player move very fast 
    } 
} 

mit jetzt den Klassen

Druid myDruid = new Druid(); 
myDruid.LightHeal(myDruid); // casting light heal here is fine 
myDruid = new CheetahForm(myDruid); 
myDruid.LightHeal(myDruid); // casting here should not be allowed 

Hmmmm ... jetzt, wo ich darüber nachdenke, wird myDruid die Druid Klasse Zauber/Fähigkeiten, um uns nicht in der Lage sein, es sei denn, die Klasse nach unten gegossen wird? Aber selbst wenn das der Fall ist, gibt es eine bessere Art und Weise, dass myDruid an dieser Stelle um sicherzustellen, dass von allen Druid bezogenen Zaubern gesperrt/Fähigkeiten, bis er zu gießt ein Druid zurück (da zur Zeit ist es in CheetahForm)

Antwort

10

Sie sollten nicht Ihre Zaubersprüche und Fähigkeiten als Methode in der Klasse haben. Sie sollten eine Sammlung von Zauber- und Fertigkeitsobjekten sein, auf die über die Charakter- (oder möglicherweise Kreaturen-) Oberfläche zugegriffen werden kann. Dann könnte Ihr CheetaForm die getSkills getSpells-Methoden überschreiben, um eine neue modifizierte Sammlung von geeigneten Skills zurückzugeben.

+0

Ich mag diese Idee sehr. Ich habe das für ein Spiel gemacht, als ich in der Universität war, und es funktioniert gut. Die Benutzeroberfläche wurde dynamisch ausgefüllt, wenn sich ein Skill-Set änderte. – Codesleuth

+1

"Sie können nicht" oder "Sie sollten nicht"? –

+0

@ mark.withers - LOL fairer Punkt Ich werde meinen Beitrag aktualisieren :) – willcodejavaforfood

1

Vielleicht eher Anstatt die Fähigkeiten eines Druiden in die Druid-Klasse zu legen, könntest du diese Fähigkeit in einen Dekorateur selbst verwandeln.

Druid myDruid = new Druid(); 
myDruid = new StandardDruid(myDruid); 

Ignorieren der schrecklich Namen „StandardDruid“ Klasse, ich hoffe, dass Sie sehen können, wo ich mit diesem gehe :)

Es upsides dieser Anordnung sind, nämlich, dass alle Ihre Fähigkeiten basiert Der Code wird konsistent in den Dekoratoren enthalten sein, und nicht nur zur Hälfte in der ursprünglichen Druid-Klasse und den restlichen Fähigkeiten in Dekorateuren. Wenn du eine andere Klasse hättest, die sich in ein Druide verwandeln könnte, könntest du das ohne Code-Duplizierung machen.

+0

Ich dachte fast, das würde funktionieren! Aber für meinen Fall wird das nicht funktionieren. Zum Beispiel, 'Druid' leitet sich von' Charakter' ab, so dass ich 'Druid' zu einem' Charakter' herabstufen konnte, bevor ich mit 'CheetahForm' dekorierte. Aber wenn ich das tue, werde ich einige Informationen über den 'Druiden' verlieren, der zum Beispiel den Charakter buchstabiert, den er sich gerade eingeprägt hat. – mikedev

0

Ich würde dieses Problem lösen, indem die LightHeal Methode, um virtuelle ändern, dann außer Kraft setzen es in der CheetahForm Klasse entweder eine Ausnahme aus, oder zeigen Sie eine Nachricht an den Benutzer, dass sie nicht, dass gerade jetzt tun können:

class Druid : Character 
{ 
    // many cool druid skills and spells 
    virtual void LightHeal(Character target) { } 
} 

abstract class CharacterDecorator : Character 
{ 
    Character DecoratedCharacter; 
} 

class CheetahForm : CharacterDecorator 
{ 
    Character DecoratedCharacter; 
    public CheetahDecorator(Character decoratedCharacter) 
    { 
     DecoratedCharacter= decoratedCharacter; 
    } 

    // many cool cheetah related skills 
    void CheetahRun() 
    { 
     // let player move very fast 
    } 

    override void LightHeal(Character target) 
    { 
     ShowPlayerMessage("You cannot do that while shape shifted."); 
    } 
} 

Immer wenn ich ein Spiel mit dieser Art von Szenario (zB World of Warcraft) spiele, ändert sich die Benutzeroberfläche, um zu verhindern, dass diese Zaubersprüche gewirkt werden, aber der Benutzer kann immer noch versuchen, diese Zaubersprüche über Makros zu wirken und damit zu handeln auf diese Weise hilft, dies zu stoppen.

Ich glaube nicht, es gibt einen Weg von ‚versteckt‘ das Verfahren ohne eine interface anstelle einer Klasse mit dem CheetahForm, als Referenzierung es dies würde nur zeigen Methoden aus dem interface zur Verfügung zu beschreiben.

0

Ich würde nur eine Eigenschaft in der Druidenklasse "Form" machen und eine if-Kontrolle machen, wenn der Zauberspruch gesprochen wird, ob der Druide transformiert ist oder nicht.

0

Wie wäre es damit?

interface ISkillState { ... } 

interface ISkill { ... } 

interface IForm 
{ 
    Collection<ISkill> skills { get; set; } 
    Dictionary<ISkill,ISkillState> skillStates { get; set; } 
} 

class Character 
{ 
    private IForm actualForm; 
    private Collection<IForm> currentForms; 

    ... 
} 

und zum Beispiel:

class Spell : ISkill {} 

class SpellState : ISkillState {} 
1

anstatt, Druid eine abgeleitete Klasse von Zeichen, betrachten die Type Object Muster. Zuerst aufzuschlüsseln Charakter klassenspezifische Fähigkeiten in ihre eigenen Objekte:

abstract class Skill 
{ 
    void Perform(); 
} 

class LightHeal : Skill 
{ 
    public void Perform() 
    { 
     // stuff... 
    } 
} 

class CheetahRun : Skill 
{ 
    public void Perform() 
    { 
     // stuff... 
    } 
} 

// other skill classes... 

nun der abgeleiteten Charakterklassen loszuwerden durch diese stattdessen tun:

class CharacterType 
{ 
    public readonly List<Skill> Skills = new List<Skill>(); 
} 

class Character 
{ 
    public IEnumerable<Skill> Skills { get { return mType.Skills; } } 

    private CharacterType mType; 
} 

Charakter „Klassen“ kann nun sein erstellt als Objekte:

CharacterType druid = new CharacterType(); 
druid.Skills.Add(new LightHeal()); 

CharacterType cheetah = new CharacterType(); 
cheetah.Skills.Add(new CheetahRun()); 

, nun von mType in Character vonÄndernzu cheetah, können Sie in der Tat seine Klasse ändern und seine verfügbaren Fähigkeiten austauschen.

+0

Ich fange wirklich an, diesen Ansatz zu graben! Eine weitere Sache, die ich tun kann, ist, den 'CharacterType' eine' List ' zu machen. Dann kann ich sogar erlauben, dass Charaktere Unterklassen bilden, damit sie alle Fertigkeiten/Zaubersprüche, in denen sie Unterklassen haben, behalten können. Ich werde dies prototypieren und sehen, wie es geht. – mikedev

+0

Ja, das stimmt genau. Sobald Sie Typobjekte verwenden, können Sie mit ihnen eine einzelne oder sogar mehrfache Vererbung implementieren. Der Himmel ist das Limit. – munificent

+2

bitte beende dein Spiel Programmierung Design Muster Buch, so kann ich eine Kopie kaufen! :) – mikedev

1

Leider euch zu informieren, aber sie sind alle falsch versucht, einen Hammer auf, was zu verwenden, die nicht ein Nagel ist :-P

Ihr Problem zu lösen mikedev Sie über OOP gehen müssen, da OOP dies nicht lösen können richtig . Werfen Sie einen Blick auf Entity Systems/Komponentensysteme.

Zuerst lesen Sie tun sollten, ist http://www.devmaster.net/articles/oo-game-design/

Dann ist Ihre Reise in die Welt der Spielgestaltung beginnen.

Verwandte Themen