Unity: Update Versus FixedUpdate

Ein weiterer Artikel über die Verwendung der Methoden Update und FixedUpdated.

TD;LR: Mit , ziemlich leicht, das Problem des Mischens und Übereinstimmens von Zeitschritten neu erstellt, Ich habe mich davon überzeugt, dass ich den gesamten Spielstatus in FixedUpdate-Methoden setzen sollte.

Bevor ich auf den Inhalt dieses Artikels eingehe, wollte ich klarstellen, warum ich überhaupt an Unity interessiert bin:

  • Ich habe KEIN großes Interesse daran, Videospiele zu spielen oder zu erstellen
  • Ich habe ein Interesse daran, nützliche Tools zu entwickeln (ich bin seit VIELEN Jahren Webentwickler)
  • Ich bin KEIN Early Adopter
  • Unity ist eine ETABLIERTE Lösung für die Erstellung von plattformübergreifenden 3D-Erlebnissen

Vor diesem Hintergrund muss ich lernen, mit Unity praktische Augmented Reality (AR) -Lösungen (webbasierte Augmented Reality) zu entwickeln.

Um Unity zu lernen, fand ich die offiziellen Unity-Tutorials NICHT besonders nützlich. Ich fand den Udemy-Kurs Learn Unity 3D für absolute Anfänger hervorragend.

Ich bin durch die Materialien gekreuzt und habe festgestellt, dass ich den Unterschied zwischen Update und FixedUpdate aufgehängt habe. Ein bisschen mehr recherchieren, Der Kern des Problems war, dass ich die folgende Begründung nicht verstand.

Update();… Wird für regelmäßige Updates verwendet, z. B.: Verschieben von nicht-physikalischen Objekten

FixedUpdate();… Wird für regelmäßige Updates verwendet, z: Physik (Rigidbody) -Objekte anpassen

Unity — Update und FixedUpdate — Offizielle Tutorials von Unity

Ein bisschen mehr Forschung ist aufgetaucht:

Legen Sie abschließend Ihre gesamte Spiellogik entweder in Update oder FixedUpdate. Mischen Sie keine Zeitschritte, es sei denn, Sie sind bereit, in die Kugel zu beißen und etwas Stottern zu akzeptieren. Darüber hinaus ist es dringend eine Überlegung wert, den gesamten Spielstatus in FixedUpdate , wobei Update ausschließlich für Benutzereingaben, visuelle Effekte und Interpolation zwischen Spielzuständen verwendet wird. Während dies erfordert eine Änderung, wie Sie Ihre Spiele strukturieren, es ist eine bewährte Design-Struktur mit vielen Vorteilen.

— KinematicSoup — Zeitschritte und reibungslose Bewegung in Unity

Ein Videoclip im Artikel veranschaulicht das Problem des Mischens und Anpassens von Zeitschritten.

roblem beim Mischen und Anpassen von Zeitschritten auf eigene Faust.

Die endgültige Version des Projekts, das ich beim Schreiben dieses Artikels verwendet habe, steht zum Download zur Verfügung.

Update Versus FixedUpdate

Wir müssen mit einem grundlegenden Verständnis des Unterschieds zwischen den Methoden Update und FixedUpdate beginnen. Zur Veranschaulichung erstellen wir ein leeres GameObject namens Setup und fügen die folgende Skriptkomponente hinzu:

Assets/Setup.cs (incomplete)

Unsere Konsolenausgabe nach 3 Sekunden sah so aus:

Beobachtungen:

  • Update wird vor jedem Rendern aufgerufen; Die Häufigkeit (Framerate) variiert je nach Komplexität des Renderns und des Hostgeräts. Leistungsstarke Computer können Bildraten von mehr als 150 fps erreichen; Mein Entwicklungscomputer lief ungefähr 50 fps. Unter 30 fps, wird als eine schlechte Erfahrung sein.
  • FixedUpdate wird vor jedem internen Physik-Update aufgerufen (Dinge aufgrund der Physik bewegen, z. B. Schwerkraft). Der feste Zeitschritt von Unity ist standardmäßig 0,02. führt dazu, dass FixedUpdate 50 Mal pro Sekunde aufgerufen wird.

Langsame Bildrate simulieren

Um eine langsame Bildrate (10fps) zu simulieren, aktualisieren wir das Setup.cs-Skript wie folgt:

Assets/Setup.cs (incomplete)

Unsere Konsolenausgabe nach 3 Sekunden sah so aus:

  • Wenn Sie vSyncCount auf 0 setzen, wird die Synchronisierung von Renderings und Bildschirmaktualisierungsraten durch Unity deaktiviert.
  • Die tatsächliche Bildrate kann aufgrund der Einschränkungen des Hostgeräts und der Komplexität des Renderings niedriger sein als die TARGET_FRAME_RATE.

Manuelle Animation

Um die Wirkung verschiedener Animationen zu beobachten, platzieren wir zunächst einen festen Würfel als Referenz.

We add our first animated GameObject (Sphere) in front of it with the following script component.

Assets/Sphere.cs (incomplete)

Running it with the normal frame rate:

Running it with 10fps frame rate:

Observations:

  • Offensichtlich haben wir ein Problem. Wir möchten nicht, dass die Animationsgeschwindigkeit von der Bildrate abhängt.
  • Das Problem liegt darin, dass wir die GESCHWINDIGKEIT auf 0,1 Einheiten / Sekunde einstellen; Wir möchten, dass die Geschwindigkeit in Einheiten / Sekunde gemessen wird.

Die Lösung besteht darin, die GESCHWINDIGKEIT in Einheiten / Sekunde anzugeben; 0,1 Einheiten / Frame * 50 Frames / Sekunde = 5 Einheiten / Sekunde. Dann nutzen wir die Zeit.deltaTime zu wissen, die Zeit seit dem letzten Aufruf zu aktualisieren. Dann ist die zurückgelegte Strecke GESCHWINDIGKEIT * deltaTime.

Vermögen/Sphäre.cs (incomplete)

Mit diesem Fix erhalten wir die gleiche Animation unabhängig von der Bildrate (aber mit 10fps ruckelt es wie erwartet).

Nachdem die reduzierte Bildrate verwendet wurde, um die Notwendigkeit um die Geschwindigkeit in Einheiten / Sekunde anzugeben, können wir die Zeilen im Setup auskommentieren.cs, die eine langsame Bildrate simuliert.

Animation in der Physik

Anstatt ein GameObject manuell zu animieren, können wir es animieren, indem wir Physik darauf anwenden. Wir können einen Zylinder animieren (sich um 5 Einheiten / Sekunde nach rechts bewegen) durch:

  • Erstellen einer Ebene (Ebene genannt)
  • Erstellen eines Zylinders (Zylinder genannt)
  • Fügen Sie dem Zylinder eine Rigidbody-Komponente hinzu (und frieren Sie die Rotation in alle Richtungen ein)
  • Erstellen Sie ein physikalisches Material, rutschig, ohne Reibung und wenden Sie es auf Zylinder und Ebene an
  • Starte den Zylinder mit einer Anfangsgeschwindigkeit mit einer Skriptkomponente

/Zylinder.cs

Damit können wir sehen, dass sich Kugel und Zylinder mit der gleichen Geschwindigkeit nach rechts bewegen.

Beobachtungen:

  • Die Position der Kugel wird unmittelbar vor dem Rendern aktualisiert (manuell in der Update-Methode)
  • Die Position des Zylinders wird im internen Physik-Update aktualisiert.

Animation mit Animation

Eine dritte Möglichkeit, ein GameObject zu animieren, ist mit einer Animation (offensichtlich). Wir können eine Kapsel animieren (versuchen, sich um 5 Einheiten / Sekunde nach rechts zu bewegen), indem wir:

  • Erstellen einer Kapsel (genannt Capsule)
  • Erstellen eines Animationscontrollers (auch Capsule) und Hinzufügen als Komponente zum Capsule GameObject.
  • Erstellen einer Animation (auch Capsule).
  • Erstellen Sie im Animationscontroller einen Zustand (Start) mit seiner Bewegung, um die Kapselanimation zu sein.
  • Schließlich animieren wir die Position so, dass die horizontale Position der Kapsel 5 Einheiten in 1 Sekunde beträgt.

Damit können wir sehen, dass sich Kugel, Zylinder und Kapsel (fast) mit der gleichen Geschwindigkeit nach rechts bewegen.

Beobachtungen:

  • Nicht sicher, warum, aber die Kapsel bewegte sich etwas schneller als erwartet; Trouble Shot für eine Weile und nicht herausfinden, warum.
  • Die Position der Kapsel kann so konfiguriert werden, dass sie vor dem Rendern (Standard) oder während des Physik-Updates aktualisiert wird.

Implikation einer schnellen Bildrate

Auf leistungsstarken Computern kann man Bildraten von bis zu 150 fps erreichen. Auf diesen Computern mit den standardmäßigen Physikaktualisierungen 50 Mal pro Sekunde (0,02 Sekunden zwischen den Aktualisierungen) werden die Elemente, die vor jedem Rendern aktualisiert werden, häufiger aktualisiert als die in den Physikaktualisierungen aktualisierten. Diese Diskrepanz ist die Ursache für Probleme beim Mischen und Anpassen von Zeitschritten.

Während ich die Bildrate meiner Entwicklungsmaschine nicht erhöhen kann (begrenzt auf etwa 50 fps), kann ich die Physik-Updates künstlich auf 10 Updates pro Sekunde verlangsamen (0.1 sekunde zwischen Updates) mit den Projekteinstellungen.

Wie Sie sehen können, durch Mischen und passende Zeitschritte wir haben das Problem (inkonsistente Bewegung zwischen GameElements) neu erstellt.

Zur Korrektur können wir die Animation der Kapsel so ändern, dass sie bei Physik-Updates aktualisiert wird, und ebenso die Skriptkomponente der Kugel wie folgt aktualisieren:

Kugel.cs

Damit werden alle Animationen vor jedem Physik-Update konsequent aktualisiert.

Schließlich geben wir unser Physik-Update zurück, um 50fps (oder alle 0,02 sekunden); erreichen sowohl konsistente und rechtzeitige updates.

Schlussfolgerungen

, ziemlich leicht, das Problem des Mischens und Übereinstimmens von Zeitschritten neu erstellt, Ich habe mich davon überzeugt, dass ich den gesamten Spielstatus in FixedUpdate-Methoden setzen sollte.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.