Wie man mit einer Schussanimation ein Geschoss loslässt

15

Nehmen wir an, Sie haben eine Animation, die beim Abfeuern einer Kugel auftreten soll. Wie würden Sie erreichen, dass die Kugel am Ende der Animation angezeigt wird? Das einzige, was ich herausfinden kann, ist, die Zeitdauer der Animation zu kennen und das Einstellen der Aufzählungszeichenposition und das Aktivieren zu verzögern, bis diese Zeitdauer verstrichen ist. Ich habe mich nur gefragt, ob dies der beste Ansatz ist. Wie gehen alle anderen damit um?

EDIT: Ich denke, ich habe Probleme, die Frage richtig zu formulieren.

Meine Frage

tp0w3rn
quelle
Vielen Dank! Viele gute Ideen von euch allen, ich mag die Idee, einen Rückruf zu benutzen. Ich denke, ich werde versuchen, das umzusetzen, ich wollte mich wirklich nicht auf die Zeiterfassung verlassen.
tp0w3rn

Antworten:

8

Grundsätzlich sind Sie auf dem richtigen Weg - Sie müssen wissen, wie lange eine Animation dauert, um so etwas zu tun. Animationen sind mehr als nur eine Sammlung von Frames, sie enthalten alle möglichen anderen Informationen, die Sie benötigen. ZB wie viele Bilder gibt es, funktioniert die Animationsschleife, wie schnell wird sie wiedergegeben (z. B. 10 Animationsbilder pro Sekunde oder 25 oder 60?). Jede Animation kann anhand einiger Daten definiert werden, die von einem generalisierten Animationscode angezeigt und wiedergegeben werden können. Sie sollten den Animationsteil in einen eigenen Code einkapseln, der nichts außer diesen Animationsdefinitionen und der Darstellung der einzelnen Bildrahmen kennt. Das heißt, Sie müssen ein Animationsobjekt haben, das Sie laden, wiedergeben, stoppen und an einer bestimmten Stelle auf dem Bildschirm rendern können.

Ein flexibler Ansatz besteht darin, eine Art Animationsdefinition zu verwenden, um diese Art von Informationen zu kapseln. Anstatt zu sagen "Animation X ist all diese Frames, spielen Sie sie einfach durch", erhalten Sie etwas komplexeres.

ZB mit einer Art verspottetem Datenformat

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

Ihr Code sagt also so etwas wie:

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

Das Erkennen von Ereignissen kann entweder über den Animationscode erfolgen, der Sie zurückruft (dh, wenn ein neues Ereignis erkannt wird, weil die Animation in einem bestimmten Frame abgespielt wurde, ruft er Ihren Spielcode auf, um ihm das neue Ereignis mitzuteilen), oder durch Abfragen von Animation wie folgt:

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);
    }
}

Punkte zu beachten:

  • Der Animationscode sollte getrennt vom Spielcode vorhanden sein. Sie möchten wirklich nicht, dass Ihr Gameplay-Code zu eng mit den Grundlagen der Animationswiedergabe verknüpft ist.
  • Der Animationscode weiß anhand der Animationsdefinition, ob eine Schleife ausgeführt werden soll oder nicht
  • Der Animationscode weiß, wann die Animation fertig ist, und kann auf einen anderen Code zurückgreifen, um zu sagen: "Hey, die Animation mit dem Namen" fire "ist gerade fertig. Was möchten Sie jetzt tun?"
  • Der Animationscode weiß nichts über Ereignisse, außer dass sie einen Namen und einige damit verbundene willkürliche Daten haben (param1 und param2).
  • Der Animationscode weiß, auf welchem ​​Frame er sich gerade befindet, und wenn er auf einen neuen Frame umschaltet, kann er prüfen und sagen: "Oh, ich bin jetzt auf Frame 4, das heißt, dieses Ereignis namens" Feuer "ist gerade passiert Meine Liste der letzten Ereignisse, damit ich jedem erzählen kann, der danach fragt.

Wenn Sie nicht brauchen, dass die Kugel in der Animation abgefeuert wird, sondern erst dann, wenn sie beendet ist, können Sie mit einem viel weniger komplexen System ohne die Vorstellung von Ereignissen davonkommen. Sie möchten jedoch weiterhin ein System, in dem Animationen von selbst wiedergegeben werden, die Dauer der Wiedergabe kennen und nach Abschluss einer Animation auf den Spielcode zurückgreifen können.

MrCranky
quelle
Ich bin nicht damit einverstanden, dass die Logik Animationen berücksichtigt (in Bild 4 bedeutet dies, dass dieses Ereignis namens "Feuer" gerade passiert ist). Animationen sollten blind und dumm sein. Ich musste einige serverseitige Logiken ausführen und Animationen herausreißen, und die Benutzeroberfläche eines Spiels ist etwas, das ich nicht noch einmal machen möchte. Ich würde wirklich empfehlen, sehr kurze und segmentierte Animationen zu verwenden und diese parallel zur Logik abzuspielen, damit die Logik Animationssequenzen mit der von der Logik festgelegten Geschwindigkeit auslöst. Lassen Sie niemals Logik den Status einer Animation testen.
Coyote
Das Aufteilen der Animation in Teile erscheint ziemlich unnötig. Ich würde dem zustimmen, den Status der Animation nicht abzufragen, aber das lässt immer noch seine erste Empfehlung. Ich weiß nicht, ob er ein separates Ereignissystem meinte, um den Animationscode vom Rest des Spiels zu entkoppeln (Beobachtermuster?), Aber so würde ich es machen. Weder die "Logik", wie Sie sagen, sollte etwas über den Animationscode wissen, noch umgekehrt.
jhocking
@Coyote Ich würde sagen, da mischst du zwei verschiedene Dinge. Ja, serverseitige Logik sollte immer unabhängig von visuellen Elementen sein (da Sie das Animationssystem nicht ausführen müssen, um herauszufinden, wann ein Aufzählungszeichen abgefeuert wird), aber dies hilft Ihnen nicht beim Erstellen eines Animationssystems auf dem Client . Auf dem Client möchten Sie auf keinen Fall, dass die Grafik auf den Server übertragen wird, denn das würde schrecklich aussehen - Kugeln, die zu ungewöhnlichen Zeiten auftauchen und nicht mit dem Charakter synchron sind, weil zwischen dem Spiel und dem Server eine Verzögerung aufgetreten ist . Es gibt keinen Grund, warum Sie nicht beides haben können (Forts.)
MrCranky
@Coyote (Forts.), Das Gameplay kann durch den Server gesteuert werden, der von der Grafik abgekoppelt ist. Die Kugel wird also zum Zeitpunkt X auf dem Server abgefeuert, und der Client spiegelt diese Aktion wider, indem er sofort mit dem Abspielen der Feueranimation beginnt, wobei das visuelle Abfeuern der Kugel einige Frames hinter der Simulation des Geschossspiels zurückbleibt. Es müssen alle möglichen Kompromisse zwischen visueller Wiedergabetreue und Gameplay-Simulation geschlossen werden. "Animationen sollten blind und dumm sein" ist also einfach naiv. Manchmal müssen Ereignisse unbedingt an Animationsrahmen gebunden werden, da sie auf keine andere Weise richtig aussehen oder klingen.
MrCranky
@Coyote Eigentlich denke ich jetzt darüber nach, der Schuss ist ein schreckliches Beispiel dafür, vor allem wegen der Antwort von Thedaian unten. Das Brennen sollte sofort erfolgen. Ein besseres Beispiel wäre ein Staub-VFX-Schuss, wenn ein Charakter landet - der Server und der Client würden synchronisiert, wenn der Charakter zu springen beginnt, aber die visuelle Anzeige bleibt dem Client überlassen. Und wenn die Animation auf das richtige Bild trifft, auf dem der Fuß den Boden berührt, sollte das VFX-Ereignis ausgelöst werden. Ebenso werden Ereignisse benötigt, wenn in einem bestimmten Animationsframe entschieden werden muss, ob zu einer anderen Animation verzweigt werden soll.
MrCranky
3

In gewisser Weise müssen Sie warten, bis die Animation fertig ist, und dann die Kugel erstellen.

Das Einstellen eines Timers funktioniert, wenn Sie sicher sind, dass Ihre Animationsrate festgelegt ist. Eine geringfügige Änderung ist, dass Sie möglicherweise Code innerhalb des Aufzählungszeichens haben, der es unsichtbar auf einen Moment warten lässt, bevor es angezeigt und verschoben wird.

Abhängig von Ihrer Entwicklungsplattform verfügen Sie möglicherweise über eine Art Animationsaktualisierungsfunktion oder Rückruffunktion, mit der Sie genau in dem Moment reagieren können, in dem die Animation den gewünschten Punkt erreicht. So würde ich es zum Beispiel mit Flixel machen.

Gregory Avery-Weir
quelle
1
Die addAnimationCallbackMethode von Flixel kann auf das feuernde Objekt angewendet werden. In der Rückruffunktion können Sie sehen, ob das aktuelle Bild der Feueranimation das Bild ist, das ein Aufzählungszeichen erzeugen soll. Wenn dies der Fall ist, können Sie eine Kugel auf dem Bildschirm hinzufügen.
Snow Blind
2

Direkte Antwort: Angenommen, Sie haben eine Animation, die Sie wiedergeben möchten, wenn der Spieler den Feuerknopf drückt, und nach dem Abspielen wird eine Kugel abgefeuert. Im Idealfall sollten Sie vermeiden, die Animationszeit fest zu codieren, und das Aufzählungszeichen abfeuern, wenn die Animation abgeschlossen ist (mithilfe einer Rückruffunktion oder Ähnlichem, abhängig von Ihrer Plattform). Ich kann mir keine andere Methode vorstellen, die nicht allzu komplex ist.

Antwort von Alternate Game Design: Wenn es keinen wirklich, wirklich guten Grund dafür gibt, würde ich vermeiden, dass das Drücken des Feuerknopfs und das Erscheinen der Kugel verzögert wird. Wenn die Animation nicht sehr, sehr kurz ist (ein oder zwei Frames, maximal, im Grunde ein Mündungsblitz), fühlt sich die Feuerknopfreaktion langsam an und wird für einen typischen Spieler nur ärgerlich. Selbst wenn Sie sich dafür entscheiden, eine Animation zu verwenden, bevor die Kugeln herauskommen (rundenbasierte RPGs und taktische Spiele wären akzeptable Gründe dafür), würde ich darüber nachdenken, irgendwo eine Option zum Deaktivieren von Animationen einzufügen, um die zuzulassen Spiel schneller zu bewegen, wenn der Spieler will.

thedaian
quelle
Ja, lass das Feuer nicht langsam reagieren. Dies ist genau wie das übliche Problem beim Springen. Animatoren machen einen großen Windup, aber die Spieler erwarten, in der Luft zu sein, sobald sie auf den Knopf tippen.
jhocking
2

Wie MrCranky sagt; Halten Sie Animation und Logik getrennt.

Vor allem aber muss die Logik der Hauptteil bleiben .

  • Wenn der Feuerknopf gedrückt wird , sollten Sie die Auslosung „auslösen Aktion “ im Zustand deines Charakters (Logik).
  • Diese Aktion sollte die Zeichnung auslösen Animation mit allen Parametern (Zeit zu leben usw.).
  • Sobald die Auslosung Aktion beendet ist können Sie das Feuer auslösen Aktion (könnte Feuer einmal oder mehrmals auf die Waffe je)
  • Diese Aktion kann Kugeln erzeugen und das Feuer auslösen Animation .

Beachten Sie, dass die Steuerung der Benutzeroberfläche über die Logik der einzige Weg ist, um sicherzustellen, dass Sie Ihre Logik später behalten, wiederverwenden und freigeben können (neuer Renderer, neues Spiel, Serverversion ohne Renderer ...).

Kojote
quelle
1

Zunächst würde ich ein Ereignissystem (Beobachtermuster?) Verwenden, um Teile des Codes zu entkoppeln. Dies gilt nicht nur für die Animation, sondern sicherlich auch dort. Dann kann der Animationscode einfach dispatchEvent (event) sagen und ein anderer Teil des Codes lauscht auf dieses Ereignis, ohne dass ein Teil des Codes voneinander Kenntnis haben muss.

Jetzt muss der Animationscode tatsächlich einen Verweis auf den Event-Dispatcher haben (einfach mit Abhängigkeitsinjektion durchzuführen) und Sie müssen über XML oder JSON verfügen, das Ihre Animationen tatsächlich definiert. Etwas wie:

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

Lesen Sie die Daten ein, wenn Sie die Animation laden, und lassen Sie den Animationscode das Ereignis auslösen, wenn es sich während der Wiedergabe auf diesem Frame befindet.

schockierend
quelle