Sistema de componentes de entidad - progresión del juego


8

Soy bastante nuevo en el desarrollo de juegos (pero no en la programación) y estoy tratando de descubrir cuál sería la mejor manera de manejar la comunicación entre mundos. Lo que quiero decir es esto:

He estado leyendo sobre los sistemas de componentes de entidad (ECS) y cómo la gente sugiere usar diferentes mundos / espacios ( http://gamedevelopment.tutsplus.com/tutorials/spaces-useful-game-object-containers--gamedev-14091 ) para Una subsección de un juego. Por ejemplo, un HUD, inventario o combate / movimiento obtienen cada uno un mundo / espacio separado (porque tienen diferentes gráficos y lógica subyacente.

Sin embargo, me preguntaba cómo el inventario, o el HUD sabe sobre la salud de un jugador cuando la salud es manejada por un espacio / mundo diferente, por ejemplo, en combate.

Esto también se aplica a la progresión del juego en general, por ejemplo, el diálogo con NPC (un diálogo sería un espacio separado ya que es una pantalla emergente), pero ¿cómo transmitiría las elecciones realizadas (o el estado del) diálogo a otros espacios / mundos . O básicamente cualquier otro tipo de evento que influya en la progresión del juego en diferentes espacios / mundos (salud, maná, misiones, diálogo, combate, inventario, hud, etc.)

¿Cómo se manejaría este tipo de diseño? ¿Necesita un objeto singleton (en implementación) que contenga todo este tipo de información? Eso sería extraño porque entonces la componentsnecesidad de transmitir cada cambio a este objeto singleton que se siente como hacer dos veces (ir en contra del DRY principal de la programación) ...

Estoy un poco perdido aquí en términos de diseño, ¿algún indicador?


---EDITAR---

Así que he leído algunas otras publicaciones sugeridas por los comentarios y tengo una idea general sobre las posibilidades, sin embargo, cada una de ellas parece tener una desventaja importante que las hace simplemente incorrectas. Es muy posible que esté supervisando los detalles que resolverían estos inconvenientes, así que no dude en corregirme. Trataré de dar una visión general, así como algunas respuestas a algunas preguntas.

Veo tres opciones principales para 'compartir' datos entre espacios. Aunque la mayoría de las publicaciones tratan sobre compartir datos entre sistemas, siento que lo mismo se puede aplicar para compartir datos entre sistemas.

1. Consultando

Ejemplo : si el mundo de HUD necesita conocer la salud actual del jugador, puede consultar otro mundo y preguntar por la salud actual.

Desventaja : los mundos necesitan conocerse entre sí, lo cual es un problema importante de dependencia y va en contra del desacoplamiento.

2: mensajería directa (sincronización y asíncrono)

Ejemplo : si durante el combate la salud de un jugador cambia, puede enviar mensajes (sincronización y asíncrono, lo que sea necesario) a otros mundos que necesitan saber sobre este cambio.

Desventaja : sigue siendo el problema del desacoplamiento: los mundos necesitan saber unos de otros.

3: Mensajes indirectos (sincronización y asíncrono) <- la mejor opción

Ejemplo : si durante el combate cambia la salud de un jugador, puede enviar mensajes (sincronización y sincronización, lo que sea necesario) al centro de mensajes general. Otros mundos / sistemas que necesitan saber sobre este cambio se suscriben al canal de mensajes en particular y leen los mensajes.

Al revés : completamente desacoplado, fácilmente manejable y extensible.

Desventaja / poco claro : ¿Cuándo sabe el canal de mensajes que los mensajes deben eliminarse? O tal vez el sistema que está suscrito marca (solo para sí mismo) el mensaje como leído y espera nuevos mensajes -> messagebox se vuelve enorme después de un tiempo. ¿Cómo manejan el orden los mundos / sistemas? Por ejemplo, durante un marco: si el HUD ya sondeó el mensaje de salud y después de eso el estado cambia, el siguiente marco se actualiza. Para algunas aplicaciones esto podría no ser la forma correcta.

P: Un objeto de juego único puede existir en múltiples espacios.

Estoy usando el marco Artemis ECS que viene con espacios integrados (llamados mundos). Cada entidad (y con ella, los datos en forma de componentes) se crean en un mundo y, por lo tanto, no se pueden compartir entre mundos.


La mensajería es el enfoque estándar aquí: gamedev.stackexchange.com/questions/23834/…
MichaelHouse

Por lo que puedo leer en el artículo vinculado, puede existir un solo objeto de juego en múltiples espacios. Si tiene diferentes gráficos o lógica entre espacios, separe los datos de los gráficos y la lógica. Comparta el objeto del juego de datos a través de espacios y agréguelo con diferentes gráficos y objetos de juego lógico.
Andreas

Esta respuesta que di sobre los sistemas de mensajería también puede ayudarte: gamedev.stackexchange.com/questions/7718/…
James

He implementado las tres soluciones (consulta, directa e indirecta) en mi vida de gamedev. Y puedo decir que la tercera opción funciona mejor para mí. Puede desacoplar fácilmente los sistemas y ejecutar su lógica en paralelo. El único inconveniente es que debe realizar 9 llamadas de función para enrutar cada mensaje / evento de un sistema a otro. Obviamente, puede optimizarlo y la gran ventaja es que no necesita mutexes o singletons en este enfoque.
Gregory

@ Gregory Gracias por su entrada, esperaba que los mensajes indirectos fueran la mejor opción. No estaba al tanto de las 9 llamadas a funciones, pero cuando planifiqué este mensaje me di cuenta de que en realidad serían bastantes llamadas. ¿Alguna vez encontró una buena solución / alternativa a la eliminación de mensajes cuando ningún sistema los necesita más?
Tim

Respuestas:


1

Una forma de verlo es que posiblemente estás poniendo demasiado en los objetos de tu juego.

No hay razón para que el código que realmente conecta el HUD a su juego en el mundo deba estar en un componente / sistema que viva en algún espacio en particular. Tal vez sea mejor que ese código viva en un administrador central o script global que tenga acceso a todos los espacios y todos los objetos, y luego pueda interactuar con el código que sabe cuándo crear realmente un espacio y qué poner en ellos (por ejemplo, el código que genera el jugador, guarda su estado entre niveles, etc.).

También podría tener un "espacio maestro" que contenga los objetos del juego con lógica o datos que deben persistir en el pasado o manipular los espacios utilizados para los niveles y la interfaz de usuario. Ese enfoque es común en los motores que obligan a los desarrolladores a colocar todos los scripts / lógica en componentes / objetos (por ejemplo, en Unity, haría un objeto Main global y lo configuraría para que persista en la descarga de la escena; si Unity realmente tenía espacios, usted ' d usar esos en lugar de la bandera).

Recuerde, abusar de su ECS es lo mismo que abusar de los patrones de diseño; el hecho de que tengas alguna nueva herramienta ingeniosa no significa que se supone que debes usarla para resolver cada problema que encuentres. Evalúe su espacio problemático y seleccione la solución que mejor se adapte, incluso si es la vieja cosa lúgubre que usaron sus antepasados ​​en la edad oscura de los años 90. :pags


0

Creé algunos prototipos, pero nada demasiado grande, y la forma en que solía manejar múltiples espacios era simplemente crear un objeto de juego que contuviera un mundo, un jugador, etc. , en el objeto del juego

Cada vez que se llama obtendrá la salud del jugador. de esa manera podría enviarlo al HUD y mostrar la barra de salud.

No es el más limpio, pero hace el trabajo, hice algunas pruebas de rendimiento en 2013 y todo pareció funcionar sin problemas. Para evitar tales dependencias, siempre puedes soltar la barra de salud cuando la salud del jugador es nula.

Por lo general, cuando el reproductor no existe, significa que el usuario está en un menú o en una escena de corte.

Ejemplo de código:

public float PlayerHealth {
  get {
    if (player !+ null) 
      return player.Health;
    return -1;
  }
}

Espero que esto sea lo que estabas buscando.


0

Esto es algo en lo que estoy trabajando en las últimas semanas. Estoy trabajando en mi propia biblioteca de ECS (quería hacerlo por experiencia y solo para probarlo, porque he querido hacerlo durante bastante tiempo).

Este es el enlace de github: https://github.com/gioragutt/xna-ecs

Para su problema, siempre he escrito una pequeña biblioteca de pubsub, que puede ver aquí

Básicamente, tengo una EmsClientclase, de la que pueden derivarse cosas. Actualmente, mis componentes no hacen eso, pero las clases de nivel más alto, aunque no hay razón para no hacerlo. Suscribo Nombres de mensajes, y proporcionar una respuesta con el siguiente firma: Action<JObject>. Como ya has entendido, estoy usando Json Objects como medio para transferir mensajes. Lo hice después de haber usado antes solo byte[], y descubrí que necesitaba algo más general, y como estoy acostumbrado a algo así desde mi lugar de trabajo (tenemos un IPCD que funciona de manera similar, excepto la devolución de llamada El método es siempre el mismo, ya que generalmente separamos la responsabilidad de los diferentes manejadores).

Hay un EmsServer(uno en el servidor y uno en cada cliente) que se encarga de mover los mensajes entre EmsClientsu reino ( EmsServeren el lado del servidor mueve los mensajes entre EmsClientsel lado del servidor, y viceversa para el lado del cliente).

Para la mensajería entre el Cliente y el Servidor, creé uno EmsServerEndpointque es EmsClientél mismo, él solo hace la lógica de almacenar en búfer los mensajes enviados en su reino y enjuagarlos a otros reinos (FE, el cliente envía el mensaje al servidor, mientras que cuando el servidor transfiere cada mensaje a todos los clientes conectados.

Puede ver el uso de una gran cantidad de lugares, Fe: ClientGameManager, ServerGameManager.

Mientras que, por ejemplo, si quiero agregar un componente GUI para un jugador, puede mirar AQUÍ , en los métodos BeginAllocateLocaly BeginAllocateRemote, que son responsables de la construcción GameObjectsde los jugadores. Cada uno GameObjectcontiene un Entity(de la biblioteca ECS) y un IComponentContainer(que también lo es, de la biblioteca ECS). Cada uno GameObjectobtiene automáticamente una transformación (como en la Unityque me inspiré).

Mi código habla por sí solo, y si lo logras, estoy buscando críticas, así que me gustaría una crítica constructiva :)

¡Espero que mi código te ayude con algunas ideas!


0

Considere los componentes del patrón de observador / sujeto para los componentes de su juego y los componentes de la interfaz de usuario. Los conectas al crear / cargar y luego te olvidas de ellos. Si la salud del personaje cambia, notifica a todos los observadores, que pueden hacer lo que quieran con la información.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.