El título es un poco confuso, pero no puedo pensar en cómo explicar mi pregunta en una frase corta. Asi que aqui esta:
Cada vez que escribo motores de juegos, ya sea física / basada en mosaicos, etc., siempre llego al punto en el que no estoy seguro de cómo debo manejar las cosas. ¿Deberían las entidades del mundo manejar por sí mismas, o debería haber algún sistema global que las administre?
Aquí hay un ejemplo fácil: mover cosas. En caso de que cada objeto vea el mundo a su alrededor (verifique las colisiones) y muévase según eso.
[nota, este es un juego basado en fichas donde el objeto se mueve por ficha, así que no estoy usando física para mover de una ficha a otra]
public class Actor : GameObject
{
private void MoveTo(Vector2 location)
{
if (world.getTile(location) != solid && world.objAtTile(location) == null)
{
Tweener.addTween(this, location);
}
}
}
¿O debería manejarse el movimiento de cada objeto en el mundo, donde el mundo verifica todo?
public class Actor : GameObject
{
private void MoveTo(Vector2 location)
{
world.moveTo(location);
}
}
public class World
{
public void moveObject(GameObject obj, Vector2 location)
{
//called from object
if (getTile(location) != solid && objAtTile(location) == null)
{
Tweener.addTween(obj, location);
}
}
}
Realmente no importa mucho para este ejemplo, supongo, pero puedo verme en problemas más adelante. Gracias por adelantado.
fuente
Actor
saber sobreworld
todo?Respuestas:
Veo que sus ejemplos están en Java, pero sus etiquetas no especifican ningún idioma. En C ++, la respuesta es ninguna de las dos : ¡no debería usar una función miembro para esto!
fuente
No hay una respuesta simple.
Como con la mayoría de las cosas en programación, es una compensación. Dar más potencia a los objetos individuales los hace más grandes y, por lo tanto, más lentos, pero hace que el motor sea más fácil de entender y extender. Tener una megaclase que pueda manejar todo junto podría ser más rápido, pero a costa de tener una megaclase; es decir, generalmente se considera mala forma hacer clases supermasivas.
He leído algunos artículos sobre diseño basado en componentes y datos, donde tiene una sola clase que representa todos los objetos de un cierto tipo, almacena sus datos en listas y pasa solo índices para obtener propiedades de un objeto individual. Aunque puedo ver esto como un tipo de arquitectura viable, creo que se atormenta con todo el punto de orientación del objeto, que también ha recibido una buena cantidad de críticas.
Yo personalmente recomiendo dar más poder a los objetos. Tiene más sentido en un lenguaje orientado a objetos y (me imagino) más fácil de entender y mantener con el tiempo.
fuente
Estoy actualizando mi respuesta porque muchas cosas no estaban claras antes de los comentarios. Por favor, descuida conmigo mientras explico mis pensamientos.
En general, dos aspectos clave a considerar en cualquier diseño es la cohesión y el acoplamiento . Todos sabemos que necesitamos una alta cohesión y un bajo acoplamiento para poder hacer un diseño más reutilizable y extensible.
Entonces, si el mundo tiene que manejar todo, eso significa que tiene una baja cohesión y un acoplamiento estrecho (porque necesita saber y hacer todo). Sin embargo, este también es el caso cuando una entidad de juego tiene que hacer todo. Actualice su ubicación, renderice su textura, etc. etc.
Lo que realmente le interesa es crear sistemas que se centren en un aspecto de la entidad. Por ejemplo, una entidad del juego podría tener una Textura, pero un Representante sería responsable de representar esa textura en la pantalla. Al Renderer no le importa qué otras propiedades tenga la entidad.
Yendo un poco más allá, una entidad de juego es simplemente una bolsa de propiedades. Estas propiedades son manipuladas por sistemas que se centran en propiedades específicas. Y aquí es donde entran en juego los sistemas de entidad basados en componentes (CBES), donde propiedades = componentes.
Específicamente, CBES con sistemas (o subsistemas). Este diseño tiende a tener unos pocos sistemas que se centran en componentes específicos de una entidad sin importar qué otros componentes tiene la entidad. Además, los sistemas se combinan solo con la información que necesitan para procesar estos componentes.
Tomemos tu ejemplo. Dado que la entrada de dónde mover la entidad se basa en el controlador del jugador, es probable que tenga un PlayerControllerSystem. Este sistema controlaría, además de muchas otras cosas, el Componente de posición de la entidad. En este caso, el PlayerControllerSystem necesitaría saber sobre el Nivel y el Componente de Posición. Si más tarde decide agregar la detección de colisión, crearía un CollisionSystem que nuevamente usaría la posición de las entidades, pero esta vez para calcular cuadros delimitadores (o podría tener un BoundingBoxComponent, su llamada). El hecho es que puede activar o desactivar fácilmente el comportamiento (incluso sobre la marcha) simplemente agregando / eliminando componentes. Entonces, más comportamiento significa que más sistemas están manipulando los componentes de una entidad, pero todos están en una clase bien definida con bajo acoplamiento. ¿Quieres scripting? Agregar un componente de secuencia de comandos. BAM! Acaba de agregar capacidades de scripting con 2 clases. ¿Física? ¿Sonido? Lo mismo de nuevo.
Entonces, la razón por la que estoy abogando por CBES con SubSystems es porque es perfectamente OO y un sistema general fácil de mantener / extensible. Agregar un comportamiento a una entidad es tan simple como decidir qué datos necesita ese comportamiento y qué entidades lo necesitan.
Para obtener más información sobre los sistemas de entidades basados en componentes con subsistemas, hay una excelente serie de publicaciones de blog de T = Machine en Entity Systems que son el futuro del desarrollo de MMOG . El autor incluso llegó a crear un wiki para recopilar varias implementaciones llamadas Entity Systems Project
Una publicación general (y bien conocida) sobre Sistemas de entidades basadas en componentes en general es Evolucionar su jerarquía que creó el sistema para Tony Hawk Pro.
Finalmente, si está buscando una biblioteca con código de ejemplo, no vaya más allá de la biblioteca Artemis . Artemis está principalmente en Java, pero aquí hay un puerto en C # (que actualmente estoy usando en mi proyecto XNA).
fuente
Por lo general, utilizo un diseño en el que los objetos se manejan solos (para eso son los métodos, después de todo), pero el mundo base tiene listas de todos los objetos y usa esas listas para coordinarlos. Entonces algo como:
fuente
Mantenlo SECO, tímido y dile al otro chico.
Es mejor pedirle al mundo que mueva a su actor que preguntarle al mundo si puede moverse a donde quiere ir. De esta manera, puede cambiar fácilmente el algoritmo de búsqueda de ruta en la clase mundial y tal. Por supuesto, podrías dejar esto en manos de una clase base para el actor, pero esa es la dirección que tomaría y el motivo.
fuente
EDITAR: Reescrito debido a los comentarios que indican que no había dibujado la línea lo suficientemente clara para esta respuesta a la pregunta original.
Me gustaría aclarar la pregunta un poco más si es posible. La lógica que actúa sobre un objeto debe ser interna o externa a ese objeto. La última parte de la publicación menciona específicamente la longevidad del diseño como la base para hacer la pregunta, para evitar problemas más adelante.
Mi respuesta simple de alto nivel es mantener toda la lógica que actúa sobre un objeto dentro de ese objeto.
No necesita que el mundo mueva un objeto, todo lo que necesita es el objeto a mover y el vector que representa la ubicación para moverlo. El mundo puede entrar en juego cuando se elige un destino o cuando se requiere una reacción al medio ambiente debido a una colisión, pero estos están fuera del ejemplo dado para trabajar.
Para abordar la parte subyacente de la pregunta y lograr la longevidad del diseño, sugeriría una arquitectura orientada a componentes. Las arquitecturas de componentes dividen un objeto en conjuntos discretos de datos y funcionalidad (suponiendo que siga con mi respuesta anterior, que establece mantener la lógica con los datos). Si su estructura se parece a CEntity-> CHuman-> CSoldier-> CPlayerCharacter, invariablemente se encontrará con problemas en los que necesita alterar alguna lógica y dependiendo de dónde vaya en ese árbol (¿Cuántos otros tipos de humanos hay, por ejemplo?) Puede tener efectos radicales en múltiples tipos de objetos.
En cambio, un sistema de componentes tendría un conjunto de interfaces que definen de qué está compuesto el objeto CEntity como ICompRenderable, ICompMoveable, ICompHealth, ICompInventory, etc. Donde tendrías CCompMoveableHuman y posiblemente un CCompMoveableSoldier y CCompMoveablePlayer para mantener separados sus patrones de movimiento individuales. Así que digamos que el Soldado está alterado para correr en formaciones. Este cambio solo afectará a las entidades creadas con ese componente.
Entonces, para resumir, sugiero que contenga la lógica con los datos a los que se aplica la lógica. También recomiendo dividir objetos en componentes discretos para reducir el '¿Dónde pongo esto?' preguntas y proporcionar estabilidad en el futuro con facilidad de mantenimiento y es extensible.
Espero que esto ayude.
fuente
Le recomiendo que intente leer sobre arquitecturas basadas en componentes. Hay bastantes publicaciones de blog, presentaciones y redacciones sobre ellos que pueden hacer un mejor trabajo que yo.
AltDevBlogADay tiene bastantes publicaciones al respecto, una muy buena es esta serie sobre entidades del juego: http://altdevblogaday.com/2011/07/10/the-game-entity-–-part-ia-retrospect/ Hay múltiples partes que se centran en el problema que está tratando de resolver.
fuente