Buscando una idea sobre el diseño de programación para atacar y atacar tipos en un juego

14

Entonces, estoy empezando a introducir el ataque a nuestro RTS espacial 2D (esto está en Unity, por lo que es impulsado por componentes). Inicialmente era tan simple como "enemigo en rango, daño aplicado". Sin embargo, habrá múltiples "tipos" de armas / ataques asociados con su nave o estructura particular. Además de otros factores involucrados más allá del daño bruto, como el tipo de daño y posiblemente la inercia en el futuro.

¿Tendrían ustedes que cada unidad y tipo de estructura tienen su propio tipo de ataque? Lo que significa que crea un script para cada unidad / estructura que define su tipo de ataque, daño, efectos, rango, partículas, sprites ... etc. ¿Y lo adjunta como un componente?

O haga un guión que defina un tipo de ataque, un guión para el tipo de proyectil asociado con eso ... etc. Y luego extiéndalos y modifique los de cada unidad, adjuntando cada guión a la unidad / estructura.


Espero tener sentido, he estado reflexionando sobre esto durante tanto tiempo que no estoy seguro de si estoy resolviendo un problema, o simplemente resolviendo mis propios problemas y cavando en un agujero.

Cuando tienes un juego que puede tener una multitud de tipos de ataque que pueden estar limitados o no a una unidad / estructura específica, ¿cómo diseñas el marco que lo vincula a las unidades / estructuras específicas en un entorno de diseño basado en componentes? ?

Si esto no está lo suficientemente claro, hágamelo saber.

Editar: Grandes respuestas, gracias.

Pregunta ampliada:

Las respuestas parecen variar de "cada objeto puede tener su propio guión de ataque" a "Tener los tipos de ataque como sus propios guiones y asignarlos a cada objeto para una solución más reutilizable". Digamos que tengo un ataque "bláster", dispara un proyectil rojo a cierta velocidad. Su daño, velocidad de disparo y tamaño del proyectil dependen de la unidad que lo dispara. ¿Es mejor hacer un script de ataque para esa unidad, o intentar modificar un "ataque bláster" para que se ajuste al propósito de cada unidad que quiera usarlo?

Douglas Gaskell
fuente
1
Para ideas generales de programación de juegos, me gusta referirme a la especificación completa del RPG FFV - gamefaqs.com/snes/588331-final-fantasy-v/faqs/30040
Code Whisperer

Respuestas:

12

Bueno, sinceramente, no soy un experto en esto, pero ... Creo que depende de cuán complejo y variado creas que serán los ataques. Dado que es un RTS, supongo que tendrás entre 10 y 50 unidades o estructuras diferentes con sus propios tipos de ataque.

Opción 1: si hay un número relativamente bajo de unidades que tendrán ataques que son algo similares, simplemente pondría todo en un gran script y definiría los parámetros utilizados en el inspector.

Opción 2: si, por otro lado, visualiza una gran cantidad de tipos de ataque con un comportamiento diferente, puede dividir todo para que cada unidad y edificio obtenga su propio script de ataque único. Estoy pensando que si hace esto, es posible que desee crear un script "auxiliar" que defina fragmentos de código de uso común que muchos de los scripts individuales pueden obtener. De esta manera, no tendrá que volver a escribir todo y sabrá dónde está todo.

Opción 3: lo que probablemente no debería hacer es tener ciertas agrupaciones de unidades que comparten guiones, esto probablemente lo confundirá y se convertirá en un desastre si el código que necesita para un ataque está en 10 guiones diferentes.

Aquí, te hice un dibujo.

ingrese la descripción de la imagen aquí

Mir
fuente
2
Muchas gracias por la respuesta. Por alguna razón, estaba empezando a inclinarme hacia la opción 3, y estaba teniendo dificultades para encontrar una manera de justificarla. Probablemente iré a la segunda ruta, cada unidad obtiene su propio script de ataque personalizado con código común que se comparte al atacar el código común como un componente de cada unidad / edificio. No estoy seguro de a dónde iba con el tren de pensamiento que me llevó a la opción 3, gracias. Dejaré esto abierto hasta que me levante en la mañana en caso de que haya otros carteles que quieran intervenir.
Douglas Gaskell
No hay problema, no es una respuesta definitiva, pero espero que ayude.
Mir
1
Puede hibridar 1 y 2 al poner ataques similares en un gran guión y separar los ataques diferentes
monstruo de trinquete el
44
Me sorprende que se recomiende el n. ° 3. ¿No es el punto completo de las clases modulares / genéricas para que cada unidad no tenga que definir su propio tipo? Si un juego es un RTS, y el daño de Asedio (generalmente "largo alcance") es un tipo de daño, querrás definirlo una vez y hacer que varias unidades de estilo de artillería se refieran a él al realizar sus cálculos de daño, de modo que si el daño de Asedio ¿Alguna vez necesitó ser nerfed (reequilibrado), solo tendría que actualizar una clase?
HC_
1
"Here, I drew you a picture."me recordó esto
FreeAsInBeer
4

No sé mucho sobre Unity y no he hecho desarrollo de juegos en mucho tiempo, así que déjame darte una respuesta general de programación a esta pregunta. Basé mi respuesta en el conocimiento que tengo sobre los sistemas de entidad-componente en general, donde una entidad es un número asociado con N muchos componentes, un componente solo contiene datos y un sistema opera en conjuntos de componentes que están asociados con la misma entidad

Su espacio problemático es este:

  • Hay múltiples formas de atacar a un enemigo en el juego como un todo.
  • Cada barco, estructura, etc., puede tener múltiples formas de ataque (cada una determinada de alguna manera)
  • Cada ataque puede tener sus propios efectos de partículas.
  • El ataque debe tener en cuenta algunos factores (como la inercia o la armadura, por ejemplo), que están presentes en el objetivo y en el usuario.

Estructuraría la solución de la siguiente manera:

  • Un ataque tiene un identificador, esto podría ser una cadena.
  • Una entidad 'sabe' que puede usar un ataque (basado en el identificador del ataque).
  • Cuando la entidad usa el ataque, el componente de visualización correspondiente se agrega a la escena.
  • Tienes cierta lógica que conoce el objetivo del ataque, el atacante y el ataque que se está utilizando; esta lógica debería decidir cuánto daño haces (y tener acceso a la inercia o lo que sea de ambas entidades).

Es importante que el punto de contacto entre los ataques y las entidades sea lo más delgado posible; esto mantendrá su código reutilizable y evitará que tenga que encontrar un código duplicado para cada tipo diferente de entidad que usa el mismo tipo de ataque. . En otras palabras, aquí hay un pseudocódigo de JavaScript para darle una idea.

// components
var bulletStrength = { strength: 50 };
var inertia = { inertia: 100 };
var target = { entityId: 0 };
var bullets = {};
var entity = entityManager.create([bulletStrength, inertia, target, bullets]);

var bulletSystem = function() {
  this.update = function(deltaTime, entityId) {
    var bulletStrength = this.getComponentForEntity('bulletStrength', entityId);
    var targetComponent = this.getComponentForEntity('target', entityId);
    // you may instead elect to have the target object contain properties for the target, rather than expose the entity id
    var target = this.getComponentForEntity('inertia', targetComponent.entityId);

    // do some calculations based on the target and the bullet strength to determine what damage to deal
    target.health -= ....;
  }
};

register(bulletSystem).for(entities.with(['bullets']));

Lo siento, esta respuesta es un poco "acuosa". Solo tengo media hora para almorzar y es difícil encontrar algo sin saber completamente acerca de Unity :(

Dan Pantry
fuente
3

Cuando una unidad / estructura / arma ataca, probablemente crearía un Ataque (subclasificado con todos tus detalles divertidos) que lleva al atacante y al defensor (o defensores). El ataque puede interactuar con el objetivo / defensor (lento, veneno, daño, cambio de estado), dibujarse (rayo, rayo, bala) y deshacerse de sí mismo cuando está hecho. Puedo prever algunos problemas como múltiples ataques de veneno, por lo que tal vez sus objetivos implementarían una interfaz Damageable con la que interactúa el ataque, pero creo que es un enfoque viable que es modular y flexible para cambiar.

Respuesta ampliada
Así es como abordaría el ataque bláster con este enfoque . Dejaré que los demás respondan por sí mismos.

Me gustaría que mis unidades implementen una interfaz o clase IAttacker con estadísticas / métodos básicos de ataque. Cuando un IAttacker ataca a un IDamageable, crea su Ataque específico pasándose a sí mismo y a su objetivo (el IAttacker y el IDamageable, o tal vez una colección de IDamageables). El Ataque toma las estadísticas que necesita del IAttacker (para evitar cambios durante las actualizaciones o algo así; no queremos que el Ataque cambie sus estadísticas después de que ya se haya lanzado) y si necesita estadísticas especializadas, lanza el IAttacker a su tipo necesario (por ejemplo, IBlasterAttacker) y obtiene las estadísticas especializadas de esa manera.

Siguiendo este enfoque, un BlasterAttacker solo necesita crear un BlasterAttack, y BlasterAttack se encarga del resto. Puedes subclasificar BlasterAttack o crear FastBlasterAttacker, MegaBlasterAttacker, SniperBlasterAttacker, etc., y el código de ataque para cada uno es el mismo (y posiblemente heredado de BlasterAttack): Crea el BlasterAttack y pásame a mí y a mis objetivos. BlasterAttack maneja los detalles. .

ricksmt
fuente
Esencialmente, la unidad hereda de una interfaz IAttacker (ya tengo esto), y hay una interfaz IDamageable para el "enemigo" (tenga esto también). Cuando el atacante ataca, se llama a BlasterAttack (o clase derivada). Este "ataque" recuperará los datos que necesita del IAttacker y los aplicará en el IDamageable cuando el proyectil golpee. ¿El proyectil en sí contiene la clase BlasterAttack, de modo que una vez que se dispara ya no se ve afectado por los cambios en el IAttacker, y puede aplicar sus daños / efectos en el IDamageable solo si su proyectil realmente impacta.
Douglas Gaskell
Cuando dice "se llama un BlasterAttack (o clase derivada)", diría que se crea un BlasterAttack. Esta instancia recién creada de BlasterAttack representa el haz (o bala o rayo o lo que sea), por lo que es el proyectil. BlasterAttack copia cualquier estadística que necesite del IAttacker y los objetos IDamageable: las posiciones, las estadísticas del atacante, etc. BlasterAttack luego rastrea su propia posición y, si corresponde, aplica daño al "contacto". Tendrá que averiguar qué hacer si se pierde o llega a su destino (la posición anterior del objetivo). Quemar el suelo? ¿Desaparecer? Tu llamada.
ricksmt
Para un Ataque de área de efecto, es posible que desee acceder a una colección global de unidades (enemigas) ya que quién está dentro del alcance y quién está fuera del alcance puede cambiar entre fuego e impacto. Por supuesto, se podría hacer un argumento similar para el BlasterAttack: fallas tu objetivo inicial, pero golpeas al tipo detrás de él. Mi única preocupación es que podrías tener muchos Ataques iterando a través de muchos Enemigos tratando de descubrir si y a qué golpearon. Esa es una preocupación de rendimiento.
ricksmt
Ah, eso tiene sentido. Para un ataque perdido, el proyectil tendrá su propio rango / vida preestablecido. Si golpea algo más antes del final de esa vida, recibirá una referencia a cualquier objeto que posea el cuerpo rígido con el que colisiona, y el daño se aplicará de esa manera. En realidad, así es como funcionarán todos los proyectiles, no saben "hacia" hacia dónde están viajando, solo que están viajando (excluyendo proyectiles de referencia como misiles). Los efectos AEO pueden habilitar un colisionador de esferas en el destino y obtener todos los objetos que están dentro de él. Gracias por la ayuda.
Douglas Gaskell
No hay problema. Me alegro de que pude. Olvidé que Unity hace que todas estas cosas de colisión sean más fáciles.
ricksmt