Różnica między metodą aktualizacji a FixedUpdate w Unity?

14

zaczynam się uczyć Unity3d, a jednym z nieporozumień jest różnica między Update()i FixedUpdate().

UpdateŚledzę tam samouczek tworzenia gier Lynda Unity 2D, instruktor używa metody, gracz ma komponent RigidBody2D i moduł zderzający Box, używa Updatemetody do tłumaczenia odtwarzacza, ale kiedy robię to samo w Updateodtwarzaczu się nie rusza, ale kiedy robię to FixedUpdatewszystko działa. Prowadzi samouczek z Unity 4.3, a ja rozpoczynam kurs z Unity 4.6.

Gdzie powinienem używać Updatei FixedUpdate?

mnich
źródło

Odpowiedzi:

14

Chciałem napisać to jako komentarz, ale skończyło się to dość długim rozwiązywaniem, więc przekształciłem to w odpowiedź.

Obecne odpowiedzi są w większości poprawne, ale kilka wspomnianych rzeczy jest mylących / błędnych.

Ogólnie rzecz biorąc, większość zadań związanych z grą zostanie wykonana Update.

Na przykład nie chcesz odpytywać danych wejściowych FixedUpdate(nie ze względu na wydajność, ale ponieważ wywołania po prostu nie będą działać poprawnie). AI wpada do tej samej łodzi.

Ciągle aktualizowana fizyka to jedyne zadanie związane z rozgrywką, do którego FixedUpdatenależy się zastosować. Nieciągłe / raz na jakiś czas połączenia do takich rzeczy Physics.Raycast, a nawet do nich Rigidbody.AddForcenależą Update. Moja wzmianka o Rigidbody.AddForcepozornie jest sprzeczna z tym, co może wynikać z dokumentacji, ale kluczem jest ciągły kontra nieciągły.

Jednym z ogromnych powodów, dla których należą tylko ciągła fizyka, FixedUpdatejest faktyczna natura FixedUpdate. W innych odpowiedziach wspomniano, w jaki sposób FixedUpdate jest wywoływany jako fixed interval, but that's slightly misleading. In reality, a script is passed a time in Time.deltaTime/ Time.fixedDeltaTime*, który nie odpowiada bezpośrednio faktycznemu czasowi między rozmowami, ale raczej symulowanemu czasowi między rozmowami.

(* Time.deltaTimei Time.fixedDeltaTimemają tę samą wartość, gdy są wywoływane w FixedUpdate[Unity jest w stanie stwierdzić, czy bieżące wywołanie zostało nawiązane Time.deltaTimepodczas FixedUpdatei zwraca Time.fixedDeltaTime])

Oczywiście tego samego sposobu Updatenie można wywoływać w sposób ciągły ze względu na różną wydajność, nie można tego zrobić FixedUpdate. Kluczową różnicą jest to, że każda ramka, jeśli FixedUpdatenie była wywoływana wystarczająco często, aby uśrednić prawidłowy odstęp między połączeniami, jest wywoływana wiele razy (lub nie jest nazywana średnia jest zbyt wysoka). Oto do czego odnoszą się dokumenty dotyczące polecenia wykonania, mówiąc, że FixedUpdate można wywoływać wiele razy ramkę:

... FixedUpdate: FixedUpdate jest często nazywany częściej niż Aktualizacja. Może być wywoływany wiele razy na klatkę, jeśli częstotliwość klatek jest niska i może nie być w ogóle wywoływana między klatkami, jeśli częstotliwość klatek jest wysoka ...

Nie wpływa to na fizykę ze względu na naturę pozostałej kolejności wykonania i silnika, ale FixedUpdatewpłynie to na wszystko, co włożysz , i spowoduje problemy.

Na przykład, jeśli umieścisz w nim przetwarzanie AI, FixedUpdatenie ma powodu, aby zakładać, że AI nie pominie aktualizacji wielu ramek z rzędu. Dodatkowo, za każdym razem, gdy `FixedUpdate pozostaje w tyle, twoja sztuczna inteligencja aktualizuje się wiele razy w jednej klatce, zanim zostaną przetworzone takie rzeczy jak fizyka i wejście / ruch gracza, co jest co najmniej marnotrawstwem przetwarzania, ale jest również bardzo prawdopodobne, że spowoduje trudne aby wyśledzić błędy i nieprawidłowe zachowanie.

Jeśli chcesz coś zrobić w ustalonym odstępie czasu, użyj innych metod, które zapewnia Unity, takich jak Coroutinesi InvokeRepeating.

I mała uwaga na temat Time.deltaTimei kiedy go używać:

Najłatwiejszym sposobem opisania efektu Time.deltaTime jest zmiana liczby z jednostki na ramkę na jednostkę na sekundę . Na przykład, jeśli masz skrypt z czymś takim jak transform.Translate(Vector3.up * 5)w aktualizacji, zasadniczo przesuwasz transformację z prędkością 5 metrów na klatkę . Oznacza to, że jeśli liczba klatek na sekundę jest niska, ruch jest wolniejszy, a jeśli liczba klatek na sekundę jest wysoka, ruch jest szybszy.

Jeśli weźmiesz ten sam kod i zmienisz na transform.Translate(Vector3.up * 5 * Time.deltaTime), obiekt będzie przemieszczany z prędkością 5 metrów na sekundę . Oznacza to, że bez względu na liczbę klatek na sekundę obiekt porusza się o 5 metrów co sekundę (ale im wolniejsza liczba klatek na sekundę, tym bardziej ruch obiektu będzie się pojawiał, ponieważ nadal porusza się o tę samą wartość co X sekund)

Ogólnie rzecz biorąc, chcesz, aby twój ruch był na sekundę. W ten sposób, bez względu na prędkość komputera, fizyka / ruch będą się zachowywać w ten sam sposób i nie będziesz mieć dziwnych błędów pojawiających się na wolniejszych urządzeniach.

I nie ma sensu z niego korzystać FixedUpdate. Z powodu tego, o czym wspomniałem powyżej, będziesz otrzymywać tę samą wartość dla każdego połączenia (wartość ustalonego timepeptu aktualizacji) i nie wpłynie to na twoje wartości. Zdefiniowany ruch / fizyka FixedUpdatebędzie już w jednostkach na sekundę, więc go nie potrzebujesz.

Selali Adobor
źródło
4

UpdateFunkcja nazywana jest każda ramka. Jego częstotliwość zależy od tego, jak szybko komputer jest w stanie renderować obrazy. Na wolniejszym komputerze Updatejest wywoływany rzadziej niż na szybszym. Jeśli wykonujesz obliczenia oparte na czasie, możesz je znormalizować za pomocą tego, Time.deltaTimektóry mówi, ile czasu upłynęło od ostatniego Updatewywołania (mają zastosowanie zastrzeżenia).
Zazwyczaj będziesz używać go Updatedo wykonywania zadań związanych z wyświetlaniem (np. Aktualizowanie elementu interfejsu użytkownika)

FixedUpdateFunkcja nazywa się w ustalonych odstępach czasu. Bez względu na to, jak często obraz się odświeża, FixedUpdatebędzie nazywał się 1/Time.fixedDeltaTimerazy na sekundę
Zazwyczaj będziesz używać FixedUpdatedo wykonywania zadań związanych z rozgrywką (np. Aktualizowanie fizyki)

3Doubloons
źródło
Czy jest to alternatywa dla mnożenia przez czas.delta? Czy istnieje powód do korzystania z jednego lub drugiego?
Ben
@Ben mają dwa różne cele i powinieneś używać właściwej funkcji do tego, co robisz.
o0 ”.
@Lohoris Przepraszam, miałem na myśli, czy istnieje powód, aby używać FixedUpdate zamiast aktualizacji i mnożenia rzeczy przez Time.deltaTime, aby uniezależnić je od ramki?
Ben
@Ben tak, precyzja. W systemie z powolnym renderowaniem Updatewywoływany jest coraz rzadziej, a twoja symulacja bardzo na tym ucierpi. Możesz nie zauważyć, gdy symulacja jest prosta, ale łatwo się przerwie, gdy tak nie jest.
o0 ”.
1
@Ben no: jeśli chcesz, aby twoja symulacja była dokładna, musisz zrobić wiele małych kroków, a nie dużych losowo za każdym razem większych lub mniejszych. I nie, cały sens FixedUpdate polega na tym, że wywoływana jest tak wiele razy, bez zadawania pytań.
o0 ”.
2

Od: http://unity3d.com/learn/tutorials/modules/beginner/scripting/update-and-fixedupdate

Krok czasowy zastosowany w FixedUpdate nie jest zmienny.

Jeśli gra zacznie się opóźniać, gdy się wróci, nie chcesz> 10 sekund fizyki w jednej aktualizacji, więc zazwyczaj odbywa się to w FixedUpdate, która jest wywoływana w ustalonych odstępach czasu.

Na przykład:

Update(float elapsedSeconds)
{
  Position += Velocity * 34.23423; //Windows Update is self-important
}
FixedUpdate(float elapsedSeconds)
{
  Position += Velocity * 0.0166; //60fps
}

Gdzie:

Update(34.23423)

==

FixedUpdate(10.0)
FixedUpdate(10.0)
FixedUpdate(10.0)
//4.23423 + 5.76577 game-seconds later...
FixedUpdate(10.0)
Jon
źródło
Wspomniałem o tym w mojej odpowiedzi, ale FixedUpdatetak naprawdę nie jest wywoływany w ustalonych odstępach czasu. Rzeczywistą naturą FixedUpdatejest ściskanie wielu cykli fizyki w jednej klatce, jeśli gra zacznie się opóźniać i pomijać cykle, jeśli idzie za szybko, aby średnia osiągnęła ustalony czas aktualizacji. Jedność nie jest wielowątkowa, więc nie byłoby sposobu, aby zagwarantować wywołania FixedUpdate w ustalonych odstępach czasu (co dzieje się, gdy jedna FixedUpdate trwa zbyt długo). Nawet gdyby tak było, prawdopodobnie byłoby to prawie niemożliwe.
Selali Adobor
Większość osób [Unity?] Nie wie, że Renderowanie / Aktualizacja / FixedUpdate są wywoływane z poziomu jednej metody wywołania zwrotnego, więc wpadłem na pomysł. Dzięki za twój wysiłek!
Jon
2

Updatejest wywoływany tak szybko, jak to możliwe. Zmienna „Time.deltaTime” jest ustawiona na faktyczny czas, który upłynął od ostatniego połączenia. Jeśli opóźnienie lub coś podobnego spowalnia grę, Updatenadal będzie wywoływane tylko raz, gdy minie opóźnienie, z wysoką wartością deltaTime.

FixedUpdatejest wywoływany w regularnych odstępach czasu. Nigdy nie będzie wywoływany częściej niż stosunek określony w „Time.fixedDeltaTime”. Jeśli opóźnienie lub coś podobnego spowalnia grę, FixedUpdatebędzie wywoływane wiele razy w krótkich odstępach czasu, aby umożliwić dogonienie gry. Time.deltaTimejest ustawiony na równy Time.fixedDeltaTimeprzed FixedUpdateuruchomieniem, ale jest to tylko krówka, aby ułatwić migrację kodu między nimi.

Zasadniczo Updatepowinien być stosowany w przypadku zachowań interpolowanych i FixedUpdatezachowań, które muszą być obliczane krok po kroku lub zależą od tych, które to robią, takich jak ruch oparty na fizyce. Jeśli piszesz jakąkolwiek pętlę Updatewzdłuż linii for(time=0;time<=deltaTime;time+=someStep)..., prawdopodobnie powinieneś to zrobić w FixedUpdate.

Mark Green
źródło