Comment lier une sortie de balle avec une animation de tir

15

Supposons que vous ayez une animation à réaliser lors du tir d'une balle. Comment voulez-vous que la balle apparaisse à la fin de l'animation. La seule chose que je peux comprendre est de connaître la durée de l'animation, et de retarder la définition de la position des balles et de l'activer jusqu'à ce que cette durée se soit écoulée. Je me demandais simplement si c'était la meilleure approche, comment tout le monde gère-t-il cela?

EDIT: Je pense que j'ai du mal à formuler la question correctement.

Ma question

tp0w3rn
la source
Merci! Beaucoup de bonnes idées de vous tous, j'aime l'idée d'utiliser un rappel. Je pense que je vais essayer de mettre en œuvre cela, je ne voulais vraiment pas compter sur le suivi du temps.
tp0w3rn

Réponses:

8

Fondamentalement, vous êtes sur la bonne voie - vous devez savoir combien de temps dure une animation pour faire ce genre de chose. Les animations sont plus qu'une simple collection de cadres, il y a toutes sortes d'autres informations autour d'eux dont vous avez besoin. Par exemple, combien d'images y a-t-il, la boucle d'animation est-elle bouclée, à quelle vitesse est-elle lue (par exemple 10 images d'animation par seconde ou 25, ou 60?). Chaque animation peut être définie en termes de quelques éléments de données, que certains codes d'animation généralisés peuvent regarder et lire. Vous devez encapsuler la partie d'animation dans son propre morceau de code, qui ne connaît rien à part ces définitions d'animation et comment afficher les images individuelles. C'est-à-dire, avoir un objet d'animation que vous pouvez charger, commencer à jouer, arrêter de jouer et dire de rendre à un emplacement particulier à l'écran.

Une approche flexible consiste à utiliser une sorte de définition d'animation pour encapsuler ce type d'informations. Donc, plutôt que de simplement dire "l'animation X est l'ensemble de ces images, il suffit de les lire", vous obtenez quelque chose d'un peu plus complexe.

Par exemple, avec une sorte de format de données simulé

animations =
{
  {name = "walk", files = "walk * .png", frameCount = "12", loop = "true"},
  {name = "fire" files = "fire * .png" frameCount = "6",
       événements = {
           {name = "bulletLeavesGun", frame = "4", param1 = "43", param2 = "30"}
       }
  }
}

Donc, votre code dit quelque chose comme:

currentAnimation = animations.Get("fire");
currentAnimation.Play();

La façon dont vous détectez les événements peut être soit avec le code d'animation qui vous rappelle (c'est-à-dire quand il détecte un nouvel événement parce que l'animation a joué sur une certaine image, il appelle votre code de jeu pour lui parler du nouvel événement), ou en interrogeant le animation comme ça:

List<Event> events = currentAnimation.EventsSinceLastCheck();
foreach (AnimationEvent event in events)
{
    if (event.name == "bulletLeavesGun")
    {
        Vector2 bulletPosition = new Vector2(event.param1, event.param2);
        Vector2 actualBulletPosition = new Vector2(
                 character.x + bulletPosition.x, 
                 character.y + bulletPosition.y);
        CreateBulletAt(actualBulletPosition);
    }
}

Points à noter:

  • Le code d'animation doit exister séparément du code de jeu. Vous ne voulez vraiment pas que votre code de jeu soit trop étroitement lié aux écrous et boulons de la lecture d'animation.
  • Le code d'animation sait s'il faut ou non boucler en fonction de la définition de l'animation
  • Le code d'animation sait quand l'animation est terminée et peut rappeler un autre code pour dire «hé, l'animation appelée« feu »vient de se terminer, que voulez-vous faire maintenant?
  • Le code d'animation ne sait rien des événements autres que le fait qu'ils ont un nom et des données arbitraires qui leur sont associées (param1 et param2)
  • Le code d'animation sait sur quelle image il se trouve actuellement, et lorsqu'il passe à une nouvelle image, il peut vérifier et dire «oh, je suis sur l'image 4 maintenant, cela signifie que cet événement appelé« feu »vient de se produire, ajoutez cela à ma liste des événements récents pour que je puisse en parler à tous ceux qui le demandent ».

Si vous n'avez pas besoin que le tir de balle se produise dans l'animation, mais seulement une fois qu'elle est terminée, vous pouvez vous en sortir avec un système beaucoup moins complexe sans notion d'événements. Mais vous voudrez toujours un système dans lequel les animations sont lues par elles-mêmes, sachez combien de temps elles sont et pouvez rappeler le code du jeu lorsqu'une animation se termine.

MrCranky
la source
Je ne suis pas d'accord pour garder les animations sensibles à la logique (sur l'image 4 maintenant, cela signifie que cet événement appelé "feu" vient de se produire). Les animations doivent être aveugles et muettes. J'ai dû faire des logiques côté serveur et des animations déchirantes et l'interface utilisateur d'un jeu est quelque chose que je ne veux pas refaire. Je recommanderais vraiment d'utiliser des animations très courtes et segmentées, jouez-les en parallèle aux logiques, laissez les logiques déclencher des séquences d'animation à la vitesse définie par les logiques. Ne jamais tester la logique du statut d'une animation.
Coyote
Diviser l'animation en morceaux semble assez inutile. Je serais d'accord pour ne pas interroger le statut de l'animation, mais cela laisse toujours sa première recommandation. Je ne sais pas s'il voulait un système d'événement séparé pour dissocier le code d'animation du reste du jeu (modèle d'observateur?) Mais c'est comme ça que je le ferais. Ni les "logiques" comme vous le dites ne devraient connaître le code d'animation, ou vice versa.
jhocking
@Coyote, je dirais que vous mélangez deux choses distinctes. Oui, la logique côté serveur doit toujours être indépendante des visuels (parce que vous ne voulez pas avoir à exécuter le système d'animation juste pour savoir quand une balle est tirée), mais cela ne vous aidera pas à construire un système d'animation sur le client . Sur le client, vous ne voulez absolument pas que les visuels soient asservis inconsidérément au serveur, car cela aurait l'air horrible - des balles apparaissant à des moments étranges et désynchronisées avec le personnage car il y avait un pic de décalage entre le jeu et le serveur . Il n'y a aucune raison pour que vous ne puissiez pas avoir les deux (suite ...)
MrCranky
@Coyote (suite ...), le gameplay peut être piloté par le serveur découplé des visuels. Ainsi, la balle est tirée au moment X sur le serveur, et le client reflète cette action en commençant immédiatement à jouer l'animation de tir, avec le tir visuel de balle en retard de quelques images derrière la simulation de jeu de balle. Toutes sortes de compromis doivent être faits entre fidélité visuelle et simulation de gameplay, donc dire que "les animations doivent être aveugles et muettes" est tout simplement naïf. Parfois, les événements doivent absolument être liés à des images d'animation, car aucune autre méthode ne les fera paraître ou sonner correctement.
MrCranky
@Coyote En fait maintenant, j'y pense, le tir de balle en est un terrible exemple, principalement à cause de la réponse de thedaian ci-dessous. Le tir devrait avoir lieu immédiatement. Un meilleur exemple serait un VFX poussiéreux se déclenchant lorsqu'un personnage atterrit - le serveur et le client se synchroniseraient quand le personnage commencerait à sauter, mais l'affichage visuel est laissé au client. Et lorsque l'animation frappe le cadre droit où le pied touche le sol, l'événement VFX devrait se déclencher. De même, des événements sont nécessaires si une décision doit être prise sur une certaine image d'animation pour se ramifier à une autre animation.
MrCranky
3

D'une certaine manière, vous devrez attendre la fin de l'animation et créer la puce à ce stade.

Le simple réglage d'une minuterie fonctionnera, si vous êtes sûr que votre taux d'animation est fixe. À titre de variante mineure, vous pourriez avoir du code interne à la puce qui le fait attendre de manière invisible pendant un moment avant d'apparaître et de bouger.

Selon votre plate-forme de développement, vous pouvez avoir une sorte de fonction de mise à jour d'animation ou de rappel qui vous permettra de répondre au moment exact où l'animation atteint le point souhaité. C'est ainsi que je le ferais avec Flixel, par exemple.

Gregory Avery-Weir
la source
1
La addAnimationCallbackméthode de Flixel peut être utilisée sur l'entité de tir. Dans la fonction de rappel, vous pouvez voir si l'image actuelle de l'animation de tir est l'image qui doit créer une entité puce. Si c'est le cas, vous pouvez ajouter une puce à l'écran.
Snow Blind
2

Réponse simple: en supposant que vous ayez une animation que vous souhaitez jouer lorsque le joueur appuie sur le bouton «tirer», puis qu'une balle sorte une fois la lecture terminée. Idéalement, vous devez éviter de coder en dur la durée de l'animation et tirer la balle lorsque l'animation se termine (en utilisant une fonction de rappel ou quelque chose, selon votre plate-forme). Je ne peux penser à aucune autre méthode pour le faire qui ne soit pas trop complexe.

Réponse alternative de Game Design: à moins qu'il n'y ait une très, très bonne raison de le faire, j'éviterais d'avoir un retard en appuyant sur le bouton `` tirer '' et en faisant apparaître la balle. À moins que l'animation ne soit vraiment, vraiment courte (une ou deux images, max, essentiellement un flash de bouche), cela va ralentir la réponse du bouton de tir, et cela deviendra ennuyeux pour un joueur typique. Même si vous décidez d'utiliser une animation avant la sortie des balles (les RPG au tour par tour et les jeux tactiques seraient des raisons acceptables de le faire), je penserais à inclure une option "désactiver les animations" quelque part, pour permettre au jeu pour se déplacer plus rapidement si le joueur le souhaite.

thédaïen
la source
Ouais, ne fais pas réagir le feu lentement. C'est comme le problème commun avec le saut; les animateurs font une grande liquidation, mais les joueurs s'attendent à être en l'air dès qu'ils tapent sur le bouton.
jhocking
2

Comme le dit MrCranky; séparez l'animation et les logiques.

Mais surtout, la logique doit rester la partie principale.

  • Lorsque vous appuyez sur le bouton de tir, vous devez déclencher "l' action " de tirage dans l'état de votre personnage (logiques).
  • Cette action devrait déclencher l' animation du dessin avec tous les paramètres (durée de vie, etc.).
  • Une fois l' action de tirage terminée, vous pouvez déclencher l' action de tir (peut tirer une ou plusieurs fois selon l'arme)
  • Cette action peut générer des balles et déclencher l' animation de tir .

Gardez à l'esprit que le contrôle de l'interface utilisateur à partir des logiques est le seul moyen de vous assurer que vous pourrez conserver, réutiliser et partager vos logiques plus tard (nouveau moteur de rendu, nouveau jeu, version serveur sans moteur de rendu ...)

Coyote
la source
1

Tout d'abord, j'utiliserais un système d'événements (modèle d'observateur?) Pour découpler des morceaux du code. Ce n'est pas seulement pour l'animation, mais s'applique certainement là-bas. Ensuite, le code d'animation peut simplement dire dispatchEvent (événement) et une autre partie du code écoute cet événement, sans que l'une ou l'autre partie du code ait besoin de se connaître.

Maintenant, le code d'animation doit avoir une référence au répartiteur d'événements (facile à faire avec l'injection de dépendances) et vous devez avoir du XML ou JSON qui définit réellement vos animations. Quelque chose comme:

{
  animation: {
    name: shoot,
    length: 12,
    spritesheet: shoot.png
    event: {
      frame: 4,
      name: bulletLeavesGun,
    },
  },
}

Lisez les données lors du chargement de l'animation et demandez au code d'animation de distribuer l'événement lorsqu'il se trouve sur cette image pendant la lecture.

jhocking
la source