Después de hacer dos preguntas sobre los sistemas de entidades ( 1 , 2 ) y leer algunos artículos sobre ellos, creo que los entiendo mucho mejor que antes. Todavía tengo algunas incertidumbres, principalmente sobre la construcción de un emisor de partículas, un sistema de entrada y una cámara. Obviamente todavía tengo algunos problemas para comprender los sistemas de entidades, y podrían aplicarse a una gama de objetos completamente diferente, pero elegí estos tres porque son conceptos muy diferentes, deberían cubrir un terreno bastante amplio y ayudarme a comprender los sistemas de entidades y cómo manejar problemas como estos, a medida que surgen.
Estoy construyendo un motor en JavaScript, y he implementado la mayoría de las características principales, que incluyen: manejo de entrada, sistema de animación flexible, emisor de partículas, clases y funciones matemáticas, manejo de escena, una cámara y un render, y un montón de otras cosas que los motores suelen soportar. Leí la respuesta de Byte56, que me interesó en convertir el motor en un sistema de entidad. Seguiría siendo un motor de juego HTML5, con la filosofía básica de la escena, pero debería admitir la creación dinámica de entidades a partir de componentes.
El problema que tengo ahora es adaptar mi viejo concepto de motor a este nuevo paradigma de programación. Estas son algunas de las definiciones de las preguntas anteriores, actualizadas:
Una entidad es un identificador. No tiene ningún dato, no es un objeto, es una identificación simple que representa un índice en la lista de escenas de todas las entidades (que realmente planeo implementar como una matriz de componentes).
Un Componente es un titular de datos, pero con métodos que pueden operar con esos datos. El mejor ejemplo es un
Vector2D
componente de "Posición". Tiene datos:x
yy
, pero también algunos métodos que hacen que operan en los datos un poco más fácil:add()
,normalize()
y así sucesivamente.Un sistema es algo que puede operar en un conjunto de entidades que cumplen con ciertos requisitos; por lo general, las entidades necesitan tener un conjunto específico de componentes para ser operados. El sistema es la parte "lógica", la parte "algoritmo", toda la funcionalidad suministrada por los componentes es puramente para facilitar la gestión de datos.
Cámara
La cámara tiene una Vector2D
propiedad de posición, una propiedad de rotación y algunos métodos para centrarla alrededor de un punto. Cada cuadro, se alimenta a un renderizador, junto con una escena, y todos los objetos se traducen según su posición. Luego se representa la escena.
¿Cómo podría representar este tipo de objeto en un sistema de entidad? ¿Sería la cámara una entidad, un componente o una combinación (según mi respuesta )?
Emisor de Partículas
El problema que tengo con mi emisor de partículas es, de nuevo, qué debería ser qué. Estoy bastante seguro de que las partículas en sí mismas no deberían ser entidades, ya que quiero admitir más de 10,000 de ellas, y creo que crear tantas entidades sería un duro golpe para mi rendimiento.
¿Cómo podría representar este tipo de objeto en un sistema de entidad?
Gerente de entrada
El último del que quiero hablar es cómo deben manejarse las entradas. En mi versión actual del motor, hay una clase llamada Input
. Es un controlador que se suscribe a los eventos del navegador, como las pulsaciones de teclas y los cambios de posición del mouse, y también mantiene un estado interno. Luego, la clase de jugador tiene un react()
método que acepta un objeto de entrada como argumento. La ventaja de esto es que el objeto de entrada podría serializarse en .JSON y luego compartirse a través de la red, lo que permite simulaciones fluidas para varios jugadores.
¿Cómo se traduce esto en un sistema de entidad?
Así es como me acerqué a esto:
Cámara
Mi cámara es una entidad como cualquier otra, que tiene componentes adjuntos:
Transform
tieneTranslation
,Rotation
yScale
propiedades, además de otros para velocidad, etc.Pov
(Punto de vista) haFieldOfView
,AspectRatio
,Near
,Far
, y cualquier otra cosa necesaria para producir una matriz de proyección, además de unaIsOrtho
bandera utiliza para cambiar entre la perspectiva y proyecciones ortográficas.Pov
también proporciona unaProjectionMatrix
propiedad de carga diferida utilizada por el sistema de representación que se calcula internamente en lectura y se almacena en caché hasta que se modifique cualquiera de las otras propiedades.No hay un sistema de cámara dedicado. El sistema de renderizado mantiene una lista de
Pov
's y contiene lógica para determinar cuál usar al renderizar.Entrada
Un
InputReceiver
componente se puede adjuntar a cualquier entidad. Esto tiene un controlador de eventos adjunto (o lambda si su idioma lo admite) que se utiliza para mantener el procesamiento de entrada específico de la entidad, que toma parámetros para el estado actual y anterior de la tecla, la ubicación actual y anterior del mouse y el estado del botón, etc. (En realidad, hay manejadores separados para mouse y teclado).Por ejemplo, en un juego de prueba similar a los asteroides que creé cuando me acostumbré a Entity / Component, tengo dos métodos lambda de entrada. Uno maneja la navegación del barco procesando las teclas de flecha y la barra espaciadora (para disparar). El otro maneja la entrada general del teclado: teclas para salir, pausar, etc., reiniciar el nivel, etc. Creo dos componentes, adjunto cada lambda a su propio componente, luego asigno el componente receptor de navegación a la entidad del barco, y el otro a un entidad de procesador de comandos no visible.
Aquí está el controlador de eventos para manejar las teclas que se mantienen entre cuadros que se adjuntan al
InputReceiver
componente del barco (C #):Si la cámara es móvil, darle su propia
InputReceiver
yTransform
componentes, adjuntar una lambda o controlador que implementa cualquier tipo de control que desea, y ya está.Esto es bastante bueno, ya que puedes mover el
InputReceiver
componente con el controlador de navegación conectado desde la nave a un asteroide, o cualquier otra cosa, y volar en su lugar. O, al asignar unPov
componente a cualquier otra cosa en su escena, un asteroide, farola, etc., puede ver su escena desde la perspectiva de esa entidad.Una
InputSystem
clase que mantiene un estado interno para el teclado, el mouse, etc.InputSystem
filtra su colección de entidades internas a entidades que tienen unInputReceiver
componente. En suUpdate()
método, itera a través de esa colección y llama a los controladores de entrada adjuntos a cada uno de esos componentes de la misma manera que el sistema de representación dibuja a cada entidad con unRenderable
componente.Partículas
Esto realmente depende de cómo planeas interactuar con las partículas. Si solo necesita un sistema de partículas que se comporte como un objeto, por ejemplo, un espectáculo de fuegos artificiales que el jugador no puede tocar ni golpear, entonces crearía una sola entidad y un
ParticleRenderGroup
componente que contiene la información que necesita para las partículas. descomposición, etc., eso no está cubierto por suRenderable
componente. Al renderizar, el sistema de renderizado vería si una entidad tiene elRenderParticleGroup
adjunto y lo manejaría en consecuencia.Si necesita partículas individuales para participar en la detección de colisiones, responder a la entrada, etc., pero solo desea procesarlas como un lote, crearía un
Particle
componente que contiene esa información por partícula, y las crearía como entidades separadas. El sistema de procesamiento aún puede agruparlos, pero los demás sistemas los tratarán como objetos separados. (Esto funciona muy bien con las instancias).Luego, ya sea en su
MotionSystem
(o lo que sea que esté usando que maneje la posición de la entidad de actualización, etc.) o en dedicadoParticleSystem
, realice el procesamiento requerido para cada partícula por cuadro. ElRenderSystem
sería responsable de la construcción / de lotes y el almacenamiento en caché colecciones de partículas a medida que se crean y se destruyen, y hacerlos según sea necesario.Una cosa buena de este enfoque es que no tiene que tener ningún caso especial para colisión, eliminación, etc. de partículas; el código que escribes para cualquier otro tipo de entidad aún se puede usar.
Conclusión
Si está considerando ir multiplataforma, no es súper aplicable a JavaScript, todo el código específico de su plataforma (es decir, representación y entrada) está aislado en dos sistemas. La lógica de su juego permanece en clases agnosíticas de plataforma (movimiento, colisión, etc.), por lo que no debería tener que tocarlas al portarlas.
Entiendo y estoy de acuerdo con la posición de Sean de que las cosas de horquilla de zapatos en un patrón para adherirse estrictamente al patrón, en lugar de ajustar el patrón para satisfacer las necesidades de su aplicación, es malo. Simplemente no veo nada en Entrada, Cámara o Partículas que requiera ese tipo de tratamiento.
fuente
La lógica de entrada y juego probablemente se manejará en un fragmento de código dedicado fuera del sistema de componentes de la entidad. Es técnicamente posible introducirlo en el diseño, pero hay pocos beneficios: la lógica del juego y la interfaz de usuario son extravagantes y están llenas de abstracciones permeables sin importar lo que hagas, e intentar forzar la clavija cuadrada en un agujero redondo solo por la pureza arquitectónica es un desperdicio de tiempo.
Del mismo modo, los emisores de partículas son bestias especiales, especialmente si te importa el rendimiento. Un componente emisor tiene sentido, pero los gráficos van a hacer algo de magia especial con esos componentes, entremezclados con la magia para el resto del renderizado.
Con respecto a su cámara, simplemente déles a las cámaras una bandera activa y quizás un índice de "profundidad", y deje que el sistema de gráficos muestre todas las que están habilitadas. Esto es realmente útil para muchos trucos, incluidas las GUI (¿quieres que tu GUI se muestre en modo ortográfico en la parte superior del mundo del juego? No hay problema, son solo dos cámaras con máscaras de objetos diferentes y una GUI configurada en una capa superior). También es útil para capas de efectos especiales y demás.
fuente
No estoy seguro de qué es realmente esta pregunta. Dado que las únicas cosas que tienes en el juego son entidades, las cámaras deben ser entidades. La funcionalidad de la cámara se implementa a través de algún tipo de componente de la cámara. No tenga componentes separados de "Posición" y "Rotación", eso es un nivel demasiado bajo. Deben combinarse en algún tipo de componente de WorldPosition que se aplique a cualquier entidad ubicada en el mundo. En cuanto a cuál usar ... tienes que poner la lógica en el sistema de alguna manera. O lo codifica en el sistema de manejo de su cámara, o adjunta scripts, o algo así. Puede tener un indicador habilitado / deshabilitado en un componente de la cámara si es útil.
Yo también. Un emisor de partículas sería una entidad, y el sistema de partículas rastrearía las partículas asociadas con una entidad dada. Cosas como esta es donde te das cuenta de que "todo es una entidad" es absurdamente impráctico. En la práctica, las únicas cosas que son entidades son objetos relativamente complejos que se benefician de combinaciones de componentes.
En cuanto a la entrada: la entrada no existe en el mundo del juego como tal, por lo que es manejada por un sistema. No necesariamente es un 'sistema de componentes' porque no todo en tu juego girará en torno a los componentes. Pero habrá un sistema de entrada. Es posible que desee marcar la entidad que responde a la entrada con algún tipo de componente Player, pero la entrada será compleja y completamente específica del juego, por lo que no tiene sentido tratar de crear componentes para esto.
fuente
Estas son algunas de mis ideas para resolver estos problemas. Probablemente tendrán algo mal con ellos, y probablemente habrá un mejor enfoque, así que, por favor, ¡diríjame a aquellos en su respuesta!
Cámara :
Hay un componente "Cámara", que se puede agregar a cualquier entidad. Sin embargo, no puedo entender qué datos debo poner en este componente: ¡podría tener componentes separados de "Posición" y "Rotación"! ¡
follow
No es necesario implementar el método porque ya está siguiendo la entidad a la que está conectado! Y soy libre de moverlo. El problema con este sistema serían muchos objetos de cámara diferentes: ¿cómo puedeRendererSystem
saber cuáles usar? Y también, solía pasar el objeto de la cámara, pero ahora parece queRendererSystem
tendrá que iterar dos veces sobre todas las entidades: primero para encontrar las que actúan como cámaras y, en segundo lugar, para renderizar todo.Emisor de partículas :
Habría una
ParticleSystem
que actualizaría todas las entidades que tenían un componente "Emisor". Las partículas son objetos tontos en un espacio de coordenadas relativo, dentro de ese componente. Hay un problema de renderizado aquí: necesitaría crear unParticleRenderer
sistema o ampliar la funcionalidad del existente.Sistema de entrada :
La principal preocupación para mí aquí era la lógica o el
react()
método. La única solución que se me ocurrió es un sistema separado para eso, y un componente para cada sistema, que indicaría cuál usar. Esto realmente parece demasiado hacky, y no sé cómo manejarlo bien. Una cosa es que, en lo que a mí respecta,Input
pueden mantenerse implementadas como una clase, pero no veo cómo podría integrarlo al resto del juego.fuente