2010-02-08 11 views
7

Estoy trabajando en un juego de rol para divertirme y practicar patrones de diseño. Me gustaría que los jugadores puedan transformarse en diferentes animales. Por ejemplo, un druida podría ser capaz de cambiar de turno a un guepardo. En este momento estoy planeando usar el patrón de decorador para hacer esto, pero mi pregunta es: ¿cómo lo hago para que cuando un druida esté en forma de guepardo, solo puedan acceder a las habilidades del guepardo? En otras palabras, no deberían poder acceder a sus habilidades Druidas normales.Consideraciones de diseño para transformar temporalmente a un jugador en un animal en un juego de rol

Usando el patrón de decorador parece que incluso en la forma de guepardo mi druida podrá acceder a sus habilidades normales de druida.

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 
    } 
} 

ahora utilizando las clases

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 ... ahora que lo pienso, se myDruid ser incapaz de nosotros los Druid clase hechizos/habilidades a menos que se coló abajo a la clase? Pero incluso si ese es el caso, ¿existe una mejor manera de asegurar que myDruid en este momento está bloqueada desde todos Druid hechizos relacionados/habilidades hasta que es puesto de nuevo a un Druid (ya que actualmente está en CheetahForm)

Respuesta

10

Usted no debe tener sus hechizos y habilidades como método en la clase. Deben ser una colección de objetos Spell and Skill accesibles a través de la interfaz Character (o posiblemente Creature). Entonces su CheetaForm podría anular los métodos getSkills getSpells para devolver una nueva colección modificada de habilidades apropiadas.

+0

Me gusta mucho esta idea. Hice esto para un juego cuando estaba en la universidad, y funciona bien. La interfaz de usuario se llena dinámicamente cada vez que se cambia un conjunto de habilidades. – Codesleuth

+1

'No puedes' o 'No deberías'? –

+0

@ mark.withers - Punto justo de LOL Voy a actualizar mi publicación :) – willcodejavaforfood

1

Tal vez que colocando las habilidades establecidas para un Druida en la clase Druida, puedes mover este conjunto de habilidades a un decorador.

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

Haciendo caso omiso de la clase horrible llamado "StandardDruid", espero que pueda ver dónde voy con esto :)

Hay aspectos positivos a esta disposición, a saber, que toda su habilidad basa el código se incluirá consistentemente dentro de los decoradores, en lugar de la mitad dentro de la clase Druid original, y las habilidades restantes en los decoradores. Si tuviera otra clase que pudiera transformarse en un Druida, podría hacerlo fácilmente sin duplicación de código.

+0

¡Casi pensé que esto funcionaría! Pero para mi caso, esto no funcionará. Por ejemplo, 'Druid' se deriva de' Character' así que podría bajar 'Druid' a' Character' antes de decorar con 'CheetahForm'. Pero si lo hago, perderé algo de información sobre el 'Druid', por ejemplo, que deletrea el personaje actualmente memorizado. – mikedev

0

Me gustaría resolver esto cambiando el método LightHeal a virtual, y luego anularlo en la clase CheetahForm ya sea una excepción, o mostrar un mensaje al usuario de que no pueden hacer eso ahora:

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."); 
    } 
} 

Cada vez que juego en un juego que involucre este tipo de escenario (por ejemplo, World of Warcraft) la UI cambia para evitar que estos hechizos sean lanzados, pero el usuario aún puede intentar lanzar estos hechizos por medio de macros, y así manejarlo de esta manera ayuda a detener esto.

No creo que hay una manera de 'ocultar' el método sin utilizar un interface en lugar de una clase para describir la CheetahForm, como referencia a ella a esto sería sólo muestran métodos disponibles en la interface.

0

Me gustaría hacer una propiedad en la clase de druida "Forma" y hacer una comprobación si al lanzar el hechizo independientemente de si el druida está transformado o no.

0

¿Qué tal esto?

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; 

    ... 
} 

y, por ejemplo:

class Spell : ISkill {} 

class SpellState : ISkillState {} 
1

En lugar de hacer Druid una clase derivada de carácter, considerar el uso del patrón Type Object. En primer lugar, dividir a cabo las habilidades específicas de clase de caracteres en sus propios objetos:

abstract class Skill 
{ 
    void Perform(); 
} 

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

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

// other skill classes... 

Ahora, deshacerse de las clases de caracteres derivados al hacer esto en su lugar:

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

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

    private CharacterType mType; 
} 

tu personaje "clases" puede ser ahora creado como objetos :

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

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

ahora, cambiando mType en Character de druid a cheetah, puede cambiar su clase y cambiar sus habilidades disponibles.

+0

¡Estoy empezando a cavar este enfoque! Una cosa más que puedo hacer es convertir 'CharacterType' en' List '. Entonces, incluso puedo permitir que los personajes se subclases para que puedan mantener todas las habilidades/hechizos en los que se clasifican. Voy a hacer un prototipo de esto y ver cómo va. – mikedev

+0

Sí, eso es exactamente correcto. Una vez que esté utilizando Type Objects, puede implementar una herencia individual o incluso múltiple con ellos. El cielo es el límite. – munificent

+2

finalice su libro de patrones de diseño de programación de juegos para que pueda comprar una copia! :) – mikedev

1

Lo sentimos informarle chicos, pero que están mal tratando de usar un martillo en algo que no es un clavo :-P

para resolver su problema mikedev tiene que ir más allá de programación orientada a objetos POO ya no puede resolver esto correctamente . Echa un vistazo a Sistemas de entidades/Sistemas de componentes.

Primera lectura que debe hacer es http://www.devmaster.net/articles/oo-game-design/

A continuación, comenzará su viaje al mundo del diseño de juegos.

Cuestiones relacionadas