Vous cherchez des informations sur la conception de la programmation pour les types d'attaque et d'attaque dans un jeu

14

Donc, je commence à introduire l'attaque à notre espace 2D RTS (c'est dans Unity, donc il est piloté par composants). Au départ, c'était aussi simple que «ennemi à portée, dégâts infligés». Cependant, il y aura plusieurs "types" d'armes / attaques associées à leur navire ou à leur structure. Ainsi que d'autres facteurs impliqués dans le passé, des dommages bruts tels que le type de dommage, et éventuellement l'inertie à l'avenir.

Souhaitez-vous que chaque type d'unité et de structure possède son propre type d'attaque? Cela signifie que vous créez un script pour chaque unité / structure qui définit son type d'attaque, ses dégâts, ses effets, sa portée, ses particules, ses sprites ... etc. Et attachez-le en tant que composant?

Ou faire un script qui définit un type d'attaque, un script pour le type de projectile associé à cela ... etc Et puis étendre ceux-ci et les modifier pour chaque unité, en attachant chaque script à l'unité / structure.


J'espère que j'ai un certain sens, je réfléchis depuis si longtemps, je ne sais pas si je résous un problème, ou si je invente mes propres problèmes et me creuse dans un trou.

Lorsque vous avez un jeu qui peut avoir une multitude de types d'attaque qui peuvent ou non être limités à une unité / structure spécifique, comment concevez-vous le cadre qui le lie aux unités / structures spécifiques dans un environnement de conception piloté par composants ?

Si ce n'est pas assez clair, faites-le moi savoir.

Edit: Excellentes réponses, merci.

Question élargie:

Les réponses semblent varier de "chaque objet peut avoir son propre script d'attaque" à "Avoir les types d'attaque comme leurs propres scripts et les affecter à chaque objet pour une solution plus réutilisable". Disons que j'ai une attaque "blaster", il tire un projectile rouge à une certaine vitesse. Ses dégâts, sa cadence de tir et la taille du projectile dépendent de l'unité qui le tire. Est-il préférable de simplement créer un script d'attaque pour cette unité, ou d'essayer de modifier une "attaque blaster" pour l'adapter à l'objectif de chaque unité qui souhaite l'utiliser?

Douglas Gaskell
la source
1
Pour des idées générales de programmation de jeux, j'aime me référer à la spécification complète du RPG FFV - gamefaqs.com/snes/588331-final-fantasy-v/faqs/30040
Code Whisperer

Réponses:

12

Eh bien, honnêtement, je ne suis pas un expert en la matière, mais ... Je pense que cela dépend de la complexité et de la variété que vous pensez que les attaques deviendront. Comme c'est un RTS, je suppose que vous aurez peut-être 10 à 50 unités ou structures différentes avec leurs propres types d'attaque.

Option 1: S'il y a un nombre relativement faible d'unités qui auront des attaques quelque peu similaires, je mettrais tout simplement dans un gros script et définirais les paramètres utilisés dans l'inspecteur.

Option 2: Si, au contraire, vous envisagez un grand nombre de types d'attaque avec un comportement différent, vous pouvez tout casser de sorte que chaque unité et bâtiment obtienne leur propre script d'attaque unique. Je pense que si vous faites cela, vous voudrez peut-être créer un script "d'aide" qui définit des morceaux de code couramment utilisés que la plupart des scripts individuels peuvent récupérer. De cette façon, vous n'aurez pas à tout réécrire et vous saurez où tout se trouve.

Option 3: Ce que vous ne devriez probablement pas faire, c'est que certains groupes d'unités partagent des scripts, cela vous confondra probablement et deviendra un gâchis si le code dont vous avez besoin pour une attaque est dans 10 scripts différents.

Ici, je vous ai dessiné une photo.

entrez la description de l'image ici

Mir
la source
2
Merci beaucoup pour votre réponse. Pour une raison quelconque, je commençais à pencher vers l'option 3, et j'avais du mal à trouver un moyen de la justifier. Je vais probablement emprunter la deuxième voie, chaque unité obtient son propre script d'attaque personnalisé avec du code commun partagé en faisant attaquer le code commun en tant que composant de chaque unité / bâtiment. Je ne sais pas où j'allais avec le courant de pensée qui m'a conduit à l'option 3, merci. Je laisse cela ouvert jusqu'à ce que je me lève le matin au cas où d'autres affiches voudraient sonner.
Douglas Gaskell
Pas de problème, ce n'est pas une réponse définitive mais j'espère que ça aide.
Mir
1
Vous pouvez hybrider 1 et 2 en plaçant des attaques similaires dans un seul gros script et en séparant les attaques dissemblables
ratchet freak
4
Je suis surpris que # 3 soit déconseillé? N'est-ce pas tout l'intérêt des classes modulaires / génériques pour que chaque unité n'ait pas à définir son propre type? Si un jeu est un RTS et que les dégâts de siège (généralement "longue portée") sont un type de dégâts, vous voudrez le définir une fois et avoir plusieurs unités de style artillerie qui s'y réfèrent lors de l'exécution de leurs calculs de dégâts, de sorte que si les dégâts de siège jamais eu besoin d'être nerfé (rééquilibré), vous n'auriez qu'à mettre à jour une classe?
HC_
1
"Here, I drew you a picture."m'a rappelé ce
FreeAsInBeer
4

Je ne sais pas grand-chose sur Unity et je n'ai pas fait de développement de jeux depuis un moment, alors permettez-moi de vous donner une réponse de programmation générale à cette question. J'ai basé ma réponse sur les connaissances que j'ai sur les systèmes à composants d'entité en général, où une entité est un nombre associé à N nombreux composants, un composant ne contient que des données et un système fonctionne sur des ensembles de composants associés à la même entité.

Votre espace de problème est le suivant:

  • Il existe plusieurs façons d'attaquer un ennemi dans le jeu dans son ensemble.
  • Chaque vaisseau, structure, etc., peut avoir plusieurs façons d'attaquer (chacune déterminée d'une certaine manière)
  • Chaque attaque peut avoir ses propres effets de particules.
  • L'attaque doit tenir compte de certains facteurs (tels que l'inertie ou l'armure, par exemple), qui sont présents sur la cible et sur l'utilisateur.

Je structurerais la solution comme suit:

  • Une attaque a un identifiant - cela pourrait être une chaîne.
  • Une entité «sait» qu'elle peut utiliser une attaque (basée sur l'identifiant de l'attaque).
  • Lorsque l'attaque est utilisée par l'entité, le composant d'affichage correspondant est ajouté à la scène.
  • Vous avez une logique qui connaît la cible de l'attaque, l'attaquant et l'attaque utilisée - cette logique devrait décider de la quantité de dégâts que vous faites (et avoir accès à l'inertie ou à quoi que ce soit des deux entités).

Il est important que le point de contact entre les attaques et les entités soit aussi fin que possible - cela gardera votre code réutilisable et vous évitera de devoir créer un code en double pour chaque type différent d'entité qui utilise le même type d'attaque . En d'autres termes, voici un pseudo-code JavaScript pour vous donner une idée.

// 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']));

Désolé, cette réponse est un peu «aqueuse». Je n'ai qu'une pause déjeuner d'une demi-heure et il est difficile de trouver quelque chose sans bien connaître Unity :(

Dan Pantry
la source
3

Quand une unité / structure / arme attaque, je créerais probablement une attaque (sous-classée avec tous vos détails amusants) qui prend l'attaquant et le défenseur (ou les défenseurs). L'attaque peut alors interagir avec la cible / le défenseur (lent, poison, dégâts, changement d'état), se dessiner (faisceau, rayon, balle) et se débarrasser d'elle-même quand c'est fait. Je peux prévoir certains problèmes comme plusieurs attaques empoisonnées, alors peut-être que vos cibles implémenteraient une interface endommageable avec laquelle l'attaque interagit, mais je pense que c'est une approche pratique modulaire et flexible à changer.

Réponse élargie
Voici comment j'aborderais l'attaque blaster avec cette approche . Je laisserai les autres répondre d'eux-mêmes.

Je voudrais que mes unités implémentent une interface ou une classe IAttacker avec des statistiques / méthodes d'attaque de base. Lorsqu'un IAttacker attaque un IDamageable, il crée son Attack spécifique se passant lui-même et sa cible (l'IAttacker et l'IDamageable, ou peut-être une collection d'IDamageables). L'attaque saisit les statistiques dont elle a besoin de l'IAttacker (pour éviter les changements pendant les mises à niveau ou quelque chose comme ça - nous ne voulons pas que l'attaque modifie ses statistiques après qu'elle ait déjà été lancée) et si elle a besoin de statistiques spécialisées, jette l'IAttacker vers son type nécessaire (ex. IBlasterAttacker) et obtient les statistiques spécialisées de cette façon.

En suivant cette approche, un BlasterAttacker a juste besoin de créer un BlasterAttack, et BlasterAttack s'occupe du reste. Vous pouvez sous-classer BlasterAttack ou créer des FastBlasterAttacker, MegaBlasterAttacker, SniperBlasterAttacker, etc. séparés et le code d'attaque pour chacun est le même (et peut-être hérité de BlasterAttack): créez le BlasterAttack et passez moi-même et mes cibles dans. BlasterAttack gère les détails. .

ricksmt
la source
Essentiellement, l'unité hérite d'une interface IAttacker (je l'ai déjà), et il y a une interface IDamageable pour "l'ennemi" (ayez-la aussi). Lorsque l'attaquant attaque, un BlasterAttack (ou une classe dérivée) est appelé. Cette "attaque" va récupérer les données dont il a besoin de l'IAttacker, et l'appliquer sur l'IDamageable lorsque le projectile frappe? Le projectile lui-même contient-il la classe BlasterAttack, de sorte qu'une fois qu'il est tiré, il n'est plus affecté par les modifications apportées à l'IAttacker et ne peut appliquer ses dégâts / effets sur l'IDamageable que si son projectile frappe réellement.
Douglas Gaskell
Lorsque vous dites "un BlasterAttack (ou une classe dérivée) est appelé", je dirais qu'un BlasterAttack est créé. Cette instance nouvellement créée de BlasterAttack représente le faisceau (ou une balle ou rayon ou autre), il est le projectile. BlasterAttack copie toutes les statistiques dont il a besoin à partir de l'IAttacker et des objets IDamageable: les positions, les statistiques de l'attaquant, etc. Le BlasterAttack suit ensuite sa propre position et, le cas échéant, applique des dégâts au "contact". Vous devrez déterminer ce qu'il faut faire s'il manque ou atteint sa destination (l'ancienne position de la cible). Brûler le sol? Disparaître? Ton appel.
ricksmt
Pour une attaque à zone d'effet, vous voudrez peut-être accéder à une collection globale d'unités (ennemies), car qui est à portée et qui est hors de portée peut changer entre le tir et l'impact. Bien sûr, un argument similaire pourrait être avancé pour le BlasterAttack: vous manquez votre cible initiale, mais frappez le gars derrière lui. Ma seule préoccupation est que vous pourriez avoir beaucoup d'attaques à travers de nombreux ennemis essayant de déterminer si et ce qu'ils ont touché. C'est une préoccupation de performance.
ricksmt
Ah, ça a du sens. Pour une attaque manquée, le projectile aura sa propre portée / durée de vie prédéfinie. S'il frappe autre chose avant la fin de cette durée de vie, il recevra une référence à tout objet possédant le corps rigide avec lequel il entre en collision, et les dommages seront appliqués de cette façon. En fait, c'est ainsi que fonctionneront tous les projectiles, ils ne savent pas «vers quoi» ils se dirigent, juste qu'ils voyagent (à l'exclusion des projectiles de type homing comme les missiles). Les effets AEO peuvent simplement activer un collisionneur de sphères à destination et obtenir tous les objets qui s'y trouvent. Merci pour l'aide.
Douglas Gaskell
Aucun problème. Heureux de pouvoir. Oublié que l'unité facilite toutes ces collisions.
ricksmt