Crear un sistema basado en comportamiento / componentes para juegos

11

Antecedentes

Hago desarrollo de juegos como un hobby, y estoy buscando una mejor manera de diseñarlos. Actualmente, estoy usando un enfoque OOP estándar (he estado haciendo desarrollo empresarial durante 8 años, por lo que viene de manera natural). Tomemos por ejemplo un "malo"

public class Baddie:AnimatedSprite //(or StaticSprite if needed, which inherit Sprite)
{
    //sprite base will have things like what texture to use, 
    //what the current position is, the base Update/Draw/GetInput methods, etc..
    //an AnimatedSprite contains helpers to animated the player while 
    //a StaticSprite is just one that will draw whatever texture is there
}

El problema

Digamos que estoy haciendo un juego de plataformas en 2D, y necesito al malo para poder saltar. Por lo general, lo que hago es agregar el código apropiado en los métodos Update / GetInput. Entonces, si necesito hacer que el jugador se arrastre, se agache, suba, etc., el código irá allí.

Si no tengo cuidado, esos métodos se desordenan, así que termino creando pares de métodos como este

CheckForJumpAction(Input input) y DoJump()

CheckforDuckAction(Input input) y DoDuck()

entonces GetInput parece

public void DoInput(Input input)
{
    CheckForJumpAction(input);
    CheckForDuckAction(input);
}

y la actualización se ve así

public void Update()
{
    DoJump();
    DoDuck();
}

Si voy y creo otro juego donde el jugador necesita saltar y agacharse, generalmente entro en un juego que tiene la funcionalidad y lo copio. Desordenado, lo sé. Por eso estoy buscando algo mejor.

¿Solución?

Realmente me gusta cómo Blend tiene comportamientos que puedo adjuntar a un elemento. He estado pensando en usar el mismo concepto en mis juegos. Así que veamos los mismos ejemplos.

Crearía un objeto de comportamiento base

public class Behavior
{
    public void Update()
    Public void GetInput()
}

Y puedo crear comportamientos usando eso. JumpBehavior:BehavioryDuckBehavior:Behavior

Luego puedo agregar una colección de comportamientos a la base de Sprite y agregar lo que necesito a cada entidad.

public class Baddie:AnimatedSprite
{
    public Baddie()
    {
        this.behaviors = new Behavior[2];
        this.behaviors[0] = new JumpBehavior();
        //etc...
    }

    public void Update()
    {
        //behaviors.update
    }

    public GetInput()
    {
        //behaviors.getinput
    }
}

Así que ahora, si quisiera usar Jump and Duck en muchos juegos, simplemente puedo traer los comportamientos. Incluso podría hacer una biblioteca para los comunes.

¿Funciona?

Lo que no puedo entender es cómo compartir el estado entre ellos. Mirando a Jump and Duck, ambos afectan no solo la porción actual de la textura que se está dibujando, sino también el estado del jugador. (Jump aplicará una cantidad decreciente de fuerza ascendente con el tiempo, mientras que el pato solo detendrá el movimiento, cambiará la textura y el tamaño de colisión del malo.

¿Cómo puedo unir esto para que funcione? ¿Debo crear propiedades de dependencia entre los comportamientos? ¿Debería tener cada comportamiento saber sobre el padre y modificarlo directamente? Una cosa que pensé fue poder pasar un delegado a cada comportamiento para que se ejecute cuando se activa.

Estoy seguro de que hay más problemas que estoy revisando, pero el propósito es que pueda reutilizar fácilmente estos comportamientos entre juegos y entidades en el mismo juego.

Así que te lo entrego a ti. ¿Le gustaría explicar cómo / si esto se puede hacer? Tienes una mejor idea? Soy todo oídos.


fuente
Esto se puede pedir mejor en gamedev.stackexchange.com ?
rcapote
Me gusta a dónde vas, pero no estoy seguro de cómo abordar los problemas que planteas. Muy interesante y tiene implicaciones más allá del desarrollo del juego.
Edward Strange
¿@rcapote no es este sitio para pizarra / discusiones?
2
@ Joe - no, no. Ni siquiera menciones "discusión" aquí o serás modificado fuera de existencia. Este sitio es solo para el tipo de interacción Pregunta-> Respuesta-> Hecho.
Edward Strange
Bueno, los sistemas de entidades basados ​​en componentes es algo que ha comenzado a ser tendencia en la comunidad de desarrolladores de juegos últimamente, así que pensé que podrías obtener una mejor atención allí, pero probablemente obtendrás buenas respuestas aquí de todos modos. Aquí hay una discusión interesante en gamedev.net sobre este problema que puede encontrar interesante: gamedev.net/topic/…
rcapote el

Respuestas:

1

Echa un vistazo a esta presentación. Suena bastante parecido al tipo de patrón que estás buscando. Este patrón admite comportamientos y propiedades vinculables. No creo que la presentación lo mencione, pero también puede crear eventos adjuntos. Esta idea es similar a las propiedades de dependencia utilizadas en WPF.

Nieldy
fuente
9

Para mí, esto parece un caso casi de libro de texto para usar el Patrón de estrategia . En este patrón, sus comportamientos genéricos se pueden definir en interfaces que le permitirán intercambiar diferentes implementaciones de comportamientos en tiempo de ejecución (piense en cómo un encendido puede afectar la capacidad de saltar o correr de su personaje).

Por ejemplo (artificial):

// The basic definition of the jump behavior
public interface IJumpBehavior {
    void Jump();
}

Ahora puedes implementar varios tipos de saltos que tu personaje puede usar, sin conocer necesariamente los detalles sobre cada salto específico:

// This is the jump the character may have when first starting
public class NormalJump : IJumpBehavior {

     public void Jump() {
         Console.WriteLine("I am jumping, and being pretty boring about it!");
     }

}

// This is the jump of a character who has consumed a power-up
public class SuperJump : IJumpBehavior {
    public void Jump() { 
         Console.WriteLine("I am all hopped up on star power, now my jumps can do damage!");
     }
}

Cualquier personaje que desee tener la capacidad de saltar puede ahora contener una referencia a un IJumpable y puede comenzar a consumir sus diversas implementaciones

public class HeroCharacter {

    // By default this hero can perform normal jump.
    private IJumpBehavior _jumpBehavior = new NormalJump();

    public void Jump() {
        _jumpBehvaior.Jump();
    }

    // If you want to change the hero's IJumpable at runtime
    public void SetJump(IJumpBehavior jumpBehavior) {
      _jumpBehavior = jumpBehavior;
    }

}

Entonces su código puede verse así:

HeroCharacter myHero = new HeroCharacer();

// Outputs: "I am jumping, and being pretty boring about it!"
myHero.Jump()

// After consuming a power-up
myHero.SetJump(new SuperJump());

// Outputs: "I am all hopped up on star power, now my jumps can do damage!"
myHero.Jump();

Ahora puede reutilizar fácilmente estos comportamientos, o incluso extenderlos más tarde, ya que desea agregar más tipos de saltos, o crear más juegos construidos en una sola plataforma de desplazamiento lateral.

mclark1129
fuente
aunque no es exactamente lo que estoy buscando, esto está muy cerca y me gusta. Voy a jugar con eso para asegurarme. ¡Gracias!
1

Eche un vistazo a la arquitectura DCI, una versión interesante de la programación OO que puede ayudar.

La implementación de una arquitectura de estilo DCI en C # requiere el uso de clases de dominio simples y el uso de objetos de contexto (comportamientos) con métodos de extensión e interfaces para permitir que las clases de dominio colaboren bajo diferentes roles. Las interfaces se utilizan para marcar los roles necesarios para un escenario. Las clases de dominio implementan las interfaces (roles) que se aplican a su comportamiento previsto. La colaboración entre los roles tiene lugar en los objetos de contexto (comportamiento).

Podría crear una biblioteca de comportamientos y roles comunes que se puedan compartir entre objetos de dominio de proyectos separados.

Ver DCI en C # para ejemplos de código en C #.

Ed James
fuente
0

¿Qué pasa con pasar un objeto de contexto a un comportamiento que proporciona métodos para cambiar el estado de los objetos / objetos afectados por un comportamiento? Ahora, si un objeto tiene varios comportamientos, cada uno de ellos se llama en un ciclo que les da la oportunidad de cambiar el contexto. Si una determinada modificación de una propiedad descarta / restringe la modificación de otras propiedades, el objeto de contexto puede proporcionar métodos para establecer algún tipo de indicadores para indicar este hecho, o simplemente puede negar modificaciones no deseadas.

Jonny Dee
fuente