Estoy empezando a entender realmente el diseño basado en componentes. No sé cuál es la forma "correcta" de hacer esto.
Aquí está el escenario. El jugador puede equipar un escudo. El escudo se dibuja como una burbuja alrededor del jugador, tiene una forma de colisión separada y reduce el daño que el jugador recibe de los efectos de área.
¿Cómo se crea tal escudo en un juego basado en componentes?
Donde me confundo es que el escudo obviamente tiene tres componentes asociados.
- Reducción de daños / filtrado
- Un sprite
- Un colisionador.
Para empeorar las cosas, diferentes variaciones de escudo podrían tener incluso más comportamientos, todos los cuales podrían ser componentes:
- impulsar la salud máxima del jugador
- regeneración de la salud
- desviación del proyectil
- etc.
¿Estoy pensando demasiado en esto? ¿Debería el escudo ser un súper componente?
Realmente creo que esta es una respuesta incorrecta. Entonces, si cree que este es el camino a seguir, explique.¿Debería ser el escudo su propia entidad que rastrea la ubicación del jugador?
Eso podría dificultar la implementación del filtro de daños. También difumina las líneas entre los componentes y las entidades adjuntas.¿Debería ser el escudo un componente que alberga otros componentes?
Nunca he visto o escuchado algo así, pero tal vez es común y todavía no soy lo suficientemente profundo.¿Debería el escudo ser solo un conjunto de componentes que se agregan al reproductor?
Posiblemente con un componente adicional para administrar los demás, por ejemplo, para que todos puedan eliminarse como grupo. (accidentalmente dejar atrás el componente de reducción de daños, ahora eso sería divertido).¿Algo más que sea obvio para alguien con más experiencia en componentes?
fuente
Respuestas:
Editar: Creo que no hay suficiente "comportamiento autónomo" para una entidad separada. En este caso específico, un escudo sigue al objetivo, funciona para el objetivo y no lo sobrevive. Si bien tiendo a estar de acuerdo en que no hay nada de malo en el concepto de "objeto de escudo", en este caso estamos lidiando con el comportamiento, que encaja perfectamente en un componente. Pero también soy un defensor de las entidades puramente lógicas (a diferencia de los sistemas de entidades completos en los que puede encontrar componentes de transformación y renderizado).
Véalo en una perspectiva diferente; agregar un componente también agrega otros componentes, y al eliminarlos, los componentes adicionales también desaparecen.
Esto podría ser una solución, promovería la reutilización, sin embargo, también es más propenso a errores (para el problema que mencionó, por ejemplo). No es necesariamente malo. Es posible que descubras nuevas combinaciones de hechizos con prueba y error :)
Voy a elaborar un poco.
Creo que notó cómo algunos componentes deben tener prioridad sin importar cuándo se hayan agregado a una entidad (esto también respondería a su otra pregunta).
También voy a suponer que estamos usando comunicación basada en mensajes (por el bien de la discusión, es solo una abstracción sobre una llamada de método por el momento).
Cada vez que se "instala" un componente de protección, los manejadores de mensajes del componente de protección se encadenan con un orden específico (superior).
El componente "estadísticas" instala un manejador de mensajes "daños" en el índice In / Invariant / Normal. Cada vez que se recibe un mensaje de "daño", disminuya el HP por su cantidad de "valor".
Comportamiento bastante estándar (poner algo de resistencia al daño natural y / o rasgos raciales, lo que sea).
El componente de escudo instala un manejador de mensajes de "daño" en el índice In / Pre / High.
Puede ver que esto es bastante flexible, aunque requeriría una planificación cuidadosa al diseñar la interacción de componentes, ya que tendrá que determinar en qué parte de la tubería de manejo de mensajes se instalan los controladores de eventos de mensajes de componentes.
¿Tiene sentido? Avísame si puedo agregar más detalles.
Editar: con respecto a las instancias de múltiples componentes (dos componentes de armadura). Puede realizar un seguimiento del recuento total de instancias en una sola instancia de entidad (sin embargo, esto elimina el estado por componente) y seguir agregando controladores de eventos de mensaje, o asegurarse de que sus contenedores de componentes permitan tipos de componentes duplicados por adelantado.
fuente
Tal vez, depende de qué tan reutilizable desee que sea su código y si tiene sentido.
No, a menos que este escudo sea una especie de criatura que pueda caminar independientemente en algún momento.
Esto se parece mucho a la entidad, por lo que la respuesta es no.
Es probable.
fuente
Un escudo, como entidad física , no es diferente de cualquier otra entidad física , por ejemplo, un avión no tripulado que te rodea (y que, de hecho, ¡podría ser un tipo de escudo!). Por lo tanto, haga que el escudo sea una entidad lógica separada (lo que le permite mantener sus propios componentes).
Dale a tu escudo un par de componentes: un componente Físico / Espacial para representar su forma de colisión, y un componente DamageAffector que tiene una referencia a alguna entidad a la que aplicará un daño aumentado o reducido (por ejemplo, tu personaje jugador) cada vez que la entidad sostener el DamageAffector sufre daños. Por lo tanto, tu jugador recibe daño "por poder"
Establece la posición de la entidad de escudo en la posición del jugador en cada tic. (Escriba una clase de componente reutilizable que haga esto: escriba una vez, use muchas veces).
Tendrá que crear la entidad de escudo, por ejemplo. en recoger un powerup. Utilizo un concepto genérico llamado Emitter, que es un tipo de componente de entidad que genera nuevas entidades (generalmente mediante el uso de una EntityFactory a la que hace referencia). El lugar donde decida ubicar el emisor depende de usted, por ejemplo. póngalo en un encendido y haga que se active cuando se recoja el encendido.
Existe una línea muy fina entre los subcomponentes lógicos (espacial, IA, ranuras de armas, procesamiento de entrada, etc., etc.) y los subcomponentes físicos. Debe decidir en qué lado se encuentra, ya que esto define en gran medida qué tipo de sistema de entidad tiene. Para mí, el subcomponente Física de mi Entidad maneja las relaciones jerárquicas físicas (como las extremidades en un cuerpo, piense en los nodos de escena), mientras que los controladores lógicos mencionados anteriormente son típicamente lo que están representados por los componentes de su entidad, en lugar de estos "fixtures" físicos individuales.
fuente
Quizás no alberga otros componentes, pero controla la vida útil de los subcomponentes. Entonces, en un pseudocódigo aproximado, su código de cliente agregaría este componente "escudo".
fuente
this
significa en su respuesta. ¿Sethis
refiere al componente Escudo o se refería a la entidad que usa el escudo, su padre? La confusión podría ser mi culpa. "Basado en componentes" es algo vago. En mi versión de entidades basadas en componentes, una entidad es simplemente un contenedor de componentes con alguna funcionalidad mínima propia (nombre de objeto, etiquetas, mensajes, etc.).gameObject
o algo así. Es una referencia al objeto / entidad del juego actual / lo que sea que posea los componentes.Si su sistema de componentes permite secuencias de comandos, el componente de protección podría ser casi un súper componente que solo llama a una secuencia de comandos por su parámetro "efecto". De esta forma, mantiene la simplicidad de un solo componente para los escudos y descarga toda la lógica de lo que realmente hace a los archivos de script personalizados que se alimentan a los escudos mediante las definiciones de su entidad.
Hago algo similar para mi componente Moveable, contiene un campo que es de secuencia de comandos de reacción clave (una subclase de secuencia de comandos en mi motor). Esta secuencia de comandos define un método que sigue mi mensaje de entrada. como tal, simplemente puedo hacer algo como esto en mi archivo de definición de plantilla
luego, en mi componente móvil durante el registro de mensajes, registro los scripts Método Do (código en C #)
Por supuesto, esto se basa en mi método Do siguiendo el patrón de funciones que toma mi RegisterHandler. En este caso es (remitente IComponent, argumento de tipo de referencia)
así que mi "script" (en mi caso también C # solo compila el tiempo de ejecución) define
y mi clase base KeyReactionScript
luego, cuando un componente de entrada envía un mensaje del tipo MessageTypes.InputUpdate con el tipo como tal
El método en el script que estaba vinculado a ese mensaje y tipo de datos se activará y manejará toda la lógica.
El código es bastante específico para mi motor, pero la lógica debería ser funcional en cualquier caso. Hago esto para muchos tipos para mantener la estructura de componentes simple y flexible.
fuente