Jump to content
Unity Insider Forum

Movement und time.deltatime


Progmore

Recommended Posts

Hallo zusammen.

Nachdem ich viele Beiträge und ein Buch über Unity gelesen habe, bin ich nun selber im letzten Monat gestartet.

Nun bin ich aber etwas durcheinander was transform, velocity und time.deltatime betrifft.

Ich bin beim folgendem Lernvideo aktiv. Rall a Ball

Dort wird nicht mit time.deltatime gearbeitet. Und ich dachte, dass bei Characterbewegungen ein velocity verwendet werden soll.

Kann man die Vorgehensweise auch auf eine laufende Person anwenden?

Gruß Progmore

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo,

vor 2 Stunden schrieb Progmore:

Nun bin ich aber etwas durcheinander was transform, velocity und time.deltatime betrifft.

Z.B. Skalierung eines Würfels  (Gilt auch für transform)

In der Funktion Upate() wird der Würfel bei einer Bildfrequenz von 100 Bildern pro Sekunde um 200 Meter skaliert.(PC1)

Bei einer Frequenz von 50 Bildern pro Sekunde würde er nur um 100 Meter skaliert.(PC2)

void Update() {

//Veränderung der Skalierung um 2 Meter/Bild

cube.scale += 2;

}

Wird der addierte Wert nun mit Time.deltaTime multipliziert, geschieht die Änderung der Größe nicht mehr pro Bild, sondern pro Sekunde.

void Update() {

//Veränderung der Skalierung um 2 Meter/Sekunde

cube.scale += 2 * Time.deltaTime;

}

Bei 50 Bilder pro Sekunde beträgt Time.deltaTime  =  1/ 50 = 0.02

            0.02 * 2 * 50 = 2m/s

Bei 100 Bilder pro Sekunde beträgt Time.deltaTime  =  1/ 100 = 0.01

            0.01 * 2 * 100 = 2m/s

Somit ist die Skalierung auf PC1 und PC2 gleich.

Wenn man dieses in der FixedUpdate()  durchführen würde, kann man auf Time.deltaTime verzichten weil diese nicht Framebasiert  sondern Zeitbasiert ist.

Dort werden auch die Physikberechnungen durchgeführt da die PhysikEngine in Zeitinterwallen arbeitet.

 

Gruß Jog

Link zu diesem Kommentar
Auf anderen Seiten teilen

Das ist alles etwas komplizierter.

Update passiert einmal pro Frame. Unity ruft überall Update auf, malt die Szene komplett auf den Bildschirm und ruft dann wieder überall Update auf. Update passiert also genau so oft, wie du Frames Per Second hast. 30 fps = 30 Updates in der Sekunde, 60 fps = 60 Updates in der Sekunde. Wenn du dich in jedem Frame 1m bewegst, dann bewegst du dich also bei 30 fps 30m und bei 60 fps 60m. Das willst du natürlich nicht, weil jeder das Spiel mehr oder weniger gleich erleben soll, egal wie viel der Rechner, die Konsole oder das Handy kann.

Time.deltaTime ist eine Property, die du auslesen kannst, und sie enthält die Zeit, die Unity seit dem letzten Update gebraucht hat. Bei 30 fps sind das 1/30, also 0,0333... Sekunden, bei 60 fps sind das 1/60, also 0,01666... Sekunden. Du siehst: Der Wert ist bei 60 fps halb so groß wie bei 30 fps. Doppelte Frames = halber Wert.

Wenn du also Time.deltaTime irgendwo draufmultiplizierst, dann gleichst du damit die Framerate aus. Wenn du 1m * Time.deltaTime gehst, dann gehst du bei 60 fps in jedem Frame nur halb so weit wie du mit 30 fps in jedem Frame gehst. Du gehst also doppelt so oft ein winziges Stückchen pro Sekunde, dafür aber nur halb so weit. Gleicht sich genau aus. Du kannst Time.deltaTime also als "Pro Sekunde" lesen. Wenn du also schreibst:

Move(10 * Time.deltaTime);

schreibst, dann kannst du das lesen als "Bewege 10 Meter pro Sekunde". "Move" gibt's jetzt so nicht, das würde also eher so aussehen:

transform.Translate(Vector3.forward * 10 * Time.deltaTime);

Die Sache ist aber, dass du damit auch nur so und so weit kommst. Time.deltaTime funktioniert nur für lineare Abläufe. Wenn ein Ding ohne Beschleunigung - mit immer gleichbleibender Geschwindigkeit passiert. Ein Ventilator, der sich durchgehend dreht. Eine Stoppuhr, die läuft. Wenn au aber z.B. mit deinem Character springst, dann hast du die Gravitation als Beschleunigung und der ganze funktioniert nicht mehr.

Stelle dir einen Sprung vor, der genau eine Sekunde dauert. Du lässt diesen Sprung auf einem Rechner mit 60 fps laufen. Du steigst, du sinkst, du berührst den Grund nach etwa einer Sekunde. Jetzt stelle dir vor, du hast den schlechtesten Computer der Welt und dein Spiel läuft mit weniger als 1 fps. Das Ding braucht zwei Sekunden, um einen Frame zu rendern. 0,5 fps also. Du startest nach oben und... nach 2 Sekunden ist der Ball immer noch in der Luft. Einfach, weil die Richtungsänderung, die Beschleunigung, in Update stattfindet und Update innerhalb dieser zwei Sekunden nicht ein einziges Mal passiert ist. Da kannst du jetzt Time.deltaTime benutzen wie du willst, das Ende der Geschichte ist: Der Sprung dauerte nicht eine Sekunde lang, sondern länger. Das ist jetzt ein Extrembeispiel, aber du kannst dir vielleicht vorstellen, dass du bei 60 vs 30 vs 120 vs wasauchimmer fps auch schon irgendeine Art von Unterschied hast. Und dieser Unterschied kann der Unterschied zwischen "schafft den Sprung" und "kann den Sprung nicht schaffen" machen. Ich spreche da sogar aus Erfahrung... so um 2009 rum bin ich da genau drauf reingefallen - mein Freund konnte den Sprung auf seinem Rechner ums Verrecken nicht schaffen. Trotz Time.deltaTime.

FixedUpdate ist jetzt eine Event-Methode wie Update, die Unity für dich aufruft. Sie wird im Schnitt (also nicht wirklich-wirklich) 50-Mal die Sekunde aufgerufen. Das kannst du aber einstellen. Und wenn du 50-Mal die Sekunde ne Berechnung machst, dann machst du halt 50-Mal die Sekunde eine Berechnung. Da hast du einfach das Problem nicht mehr.

Time.deltaTime gibt dir, wenn du es in FixedUpdate benutzt, auch nicht die Zeit seit dem letzten Frame zurück, sondern einen konstanten Wert: Genau diese 1/50 = 0.02. Oder was auch immer du stattdessen einstellst. Damit kannst du Time.deltaTime nach wie vor als "pro Sekunde" benutzen. Die Konsistenz deiner Ergebnisse leidet nicht darunter, wenn du es weglässt, aber ich benutze es gerne, weil es die Formeln einfacher verständlich macht. Ist halt einfacher, von "pro Sekunde" zu reden als von "pro Frame". Finde ich.

Meine Zusammenfassung ist also: Benutze FixedUpdate bei allem, von dem du willst, dass es auch wirklich bei jedem gleich ist. Bei irgendeinem Ding, das im Hintergrund hübsch aussehen soll, ist es nicht so wichtig, aber wenn das Gameplay davon abhängt, dann nutze FixedUpdate. Zumindest, wenn das Ding non-linear ist. Deine Stoppuhr ist vermutlich Gameplay-relevant, darf aber trotzdem in Update laufen ;)

Und Time.deltaTime kannst du auch gerne in FixedUpdate benutzen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Naja, was ist "velocity"? Meinst du Rigidbody.velocity? Dann ist die Frage eher, wann man einen Rigidbody verwenden sollte und wann nicht. Rigidbodys sind für Physik-Objekte. Sie benutzen Collider, haben eine Geschwindigkeit und eine Rotationsgeschwindigkeit, können Kräfte auf sich wirken lassen und Kollisionen auflösen, inklusive so Sachen wie Bouncing, Reibung oder Gelenke. Rigidbodys werden im Physik-Update, das auf FixedUpdate sitzt, aktualisiert. Aktualisieren heißt: Die aktuelle Geschwindigkeit (Rigidbody.velocity) wird auf die Position (Transform.position) draufgerechnet. Ganz stumpf

transform.position += rigidbody.velocity * Time.deltaTime;

Naja, wenn man die Drehung außer Acht lässt zumindest. Du kannst also einen Rigidbody nehmen, dem sagen wo's gerade langgeht und der macht das dann für dich, inklusive Nicht-durch-Wände-fliegen und so.

Das Problem ist, dass es einige Dinge gibt, bei denen Physik-Objekte einfach zu viel machen. Ein klassisches Problem ist, dass eine Kugel, die über eine gerade Fläche rollt, kurz hüpft wenn diese Fläche aus mehreren flachen Kollidern besteht und man über eine Kante rollt - selbst, wenn die Bodencollider exakt auf derselben Höhe sind. Rigidbodys machen halt einige Dinge, und einige dieser Dinge können einfach zu viel sein für so Sachen wie Charaktere, die der Spieler steuert. In solchen Fällen muss man dann anfangen, den Rigidbody zu zügeln und gegen seine Features anzukämpfen. Und ab einem bestimmten Punkt wird es weniger Arbeit, selber Features zu schreiben, als bestehende Features zu zähmen. Heißt: Dann kommt der Rigidbody weg. Als Alternative in 3D gibt's den CharacterController. In 2D gibt's so etwas nicht von Haus aus. Da schreibt man sich dann schweißtreibend was selber, wenn's gut werden soll.

Aber der Punkt dabei ist: Auch eine Spielfigur hat immer eine Geschwindigkeit. Sonst könnte man z.B. niemals runterfallen. Wenn du keinen Rigidbody benutzt, dann baust du dir dein "velocity" halt eben selbst. Ist auch nur ein Vector2 bzw. Vector3, den du dann in FixedUpdate auf deine Position draufrechnest.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Danke sehr.

ABER...wie kommt es dann, dass einige das in´s UPDATE packen wie hier unten?

using UnityEngine;
using System.Collections;

public class Bewegen : MonoBehaviour
{
    // public member eines Scripts können bequem im Unity Editor gesetzt
    // und auch während das Spiel getestet wird verändert werden.
    public float Geschwindigkeit;
    public float Beschleunigung;

    float aktuelleGeschwindigkeit = 0;
    Vector3 richtung = Vector3.zero;

    void Start()
    {
    }

    void Update()
    {
        if (EingabeÜberprüfen())
        {
            if (aktuelleGeschwindigkeit < Geschwindigkeit)
            {
                aktuelleGeschwindigkeit += Beschleunigung * Time.deltaTime;
            }
            this.transform.position += richtung * aktuelleGeschwindigkeit * Time.deltaTime;
        }
        else
        {
            aktuelleGeschwindigkeit = 0f;
        }
    }

    private bool EingabeÜberprüfen()
    {
        bool eingabe = false;
        float x = 0f;
        float z = 0f;

        // Input.GetKey gibt true zurück wenn die gefragte Taste gedrückt ist
        if (Input.GetKey(KeyCode.RightArrow))
        {
            x++;
            eingabe = true;
        }
        if (Input.GetKey(KeyCode.LeftArrow))
        {
            x--;
            eingabe = true;
        }
        if (Input.GetKey(KeyCode.UpArrow))
        {
            z++;
            eingabe = true;
        }
        if (Input.GetKey(KeyCode.DownArrow))
        {
            z--;
            eingabe = true;
        }
        richtung = new Vector3(x, 0f, z);
        return eingabe;
    }
}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Die Unity Manuals sind definitiv nicht frei von Fehlern und schon gar nicht von schlechten Ratschlägen. Falsch ist das Codeschnipsel allerdings nicht. Das Objekt bewegt sich konstant in eine Richtung... naja, zweimal. Aber jeweils halt konstant in eine Richtung. Keine Beschleunigung oder so. Und wie ich schon schrieb:

Am 28.2.2021 um 21:00 schrieb Sascha:

Time.deltaTime funktioniert nur für lineare Abläufe. Wenn ein Ding ohne Beschleunigung - mit immer gleichbleibender Geschwindigkeit passiert. Ein Ventilator, der sich durchgehend dreht. Eine Stoppuhr, die läuft.

Ist also in diesem Fall in Ordnung.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.

×
×
  • Neu erstellen...