Unity: uppdatera kontra FixedUpdate

ännu en artikel om när du ska använda uppdaterings-och FixedUpdated-metoderna.

td;LR: efter att ha, ganska enkelt, återskapat problemet med att blanda och matcha timesteps, har jag övertygat mig själv om att jag borde lägga alla speltillstånd i fixedupdate-metoder.

innan jag kom in i innehållet i denna artikel ville jag klargöra varför jag är intresserad av enhet i första hand:

  • jag har inte mycket intresse av att antingen spela eller skapa videospel
  • jag har ett intresse av att bygga användbara verktyg (varit en webbutvecklare i många år)
  • Jag är inte en tidig adopter
  • Unity är en väletablerad lösning för att skapa multi-platform 3D-upplevelser

med allt detta i åtanke, bygga praktiska webbdrivna Augmented Reality (AR) lösningar med Unity är något som jag behöver lära mig.

När det gäller att lära Unity, jag inte särskilt hitta den officiella Unity tutorials användbar. Jag hittade Udemy-kursen Learn Unity 3D för absoluta nybörjare att vara utmärkt.

jag kryssade igenom materialet och fann mig själv hängde på lektionsskillnaden mellan Uppdatering och FixedUpdate. Forska lite mer, den springande punkten i problemet var att jag inte förstod följande motivering.

Update (); … används för regelbundna uppdateringar som: Flytta icke-fysik objekt

FixedUpdate (); … används för regelbundna uppdateringar som: Justera fysik (Rigidbody) objekt

Unity — uppdatera och FixedUpdate — Unity officiella Tutorials

lite mer forskning dök upp:

Sammanfattningsvis lägger du all din spellogik i antingen Update eller FixedUpdate. Blanda inte och matcha tidssteg om du inte är villig att bita ihop och acceptera lite stamning. Dessutom, det är starkt värt att överväga att sätta alla spel tillstånd i FixedUpdate, med hjälp av Uppdatering uteslutande för användarinmatning, visuella effekter, och interpolering mellan speltillstånd. Även om detta kräver en förändring hur du strukturera dina spel, det är en beprövad designstruktur med många fördelar.

— KinematicSoup — Timesteps och uppnå smidig rörelse i Unity

ett videoklipp i artikeln illustrerar problemet med att blanda och matcha timesteps.

innan jag följde detta råd ville jag återskapa problemet med att blanda och matcha timesteps på egen hand.

den slutliga versionen av projektet som jag använde för att skriva den här artikeln är tillgänglig för nedladdning.

Uppdatering kontra FixedUpdate

Vi måste börja med en grundläggande förståelse för skillnaden mellan uppdaterings-och FixedUpdate-metoderna. För att illustrera skapar vi ett tomt spelobjekt som heter Setup och lägger till följande skriptkomponent:

Assets/Setup.cs (ofullständig)

vår konsolutgång efter 3 sekunder såg ut som:

observationer:

  • uppdatering anropas före varje rendering; vars frekvens (bildhastighet) varierar beroende på komplexiteten hos renderingen och värdenheten. Kraftfulla datorer kan uppnå bildhastigheter på över 150fps; min utvecklingsdator körde cirka 50fps. Under 30 fps, anses vara en dålig upplevelse.
  • FixedUpdate anropas före varje intern fysik uppdatering (flytta saker på grund av fysik, t.ex. gravitation). Unitys fasta tidssteg är som standard 0,02; leder till att FixedUpdate anropas 50 gånger per sekund.

simulera långsam bildhastighet

för att simulera en långsam bildhastighet (10fps) uppdaterar vi inställningen.cs-skript enligt följande:

Assets / Setup.cs (ofullständig)

vår konsolutgång efter 3 sekunder såg ut som:

observationer:

  • inställning av vsynccount till 0 inaktiverar Unity från synkronisering av renderingar och skärmuppdateringsfrekvenser.
  • den faktiska Bildhastigheten kan vara lägre än TARGET_FRAME_RATE på grund av värdenhetens begränsningar och renderingens komplexitet.

Manuell animering

För att observera effekten av olika animationer börjar vi med att placera en fast kub som referens.

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:

  • uppenbarligen har vi ett problem. Vi vill inte att animeringshastigheten ska vara beroende av bildhastigheten.
  • problemet är att vi ställer in hastigheten till 0,1 enheter / ram; vi vill att hastigheten ska mätas i enheter / sekund.

fixen är att ge hastigheten i enheterna av enheter / sekund; 0,1 enheter / ram * 50 ramar / sekund = 5 enheter / sekund. Då använder vi tiden.deltaTime att veta tiden sedan det senaste samtalet för att uppdatera. Då är det körda avståndet hastighet * deltaTime.

tillgångar / sfär.cs (ofullständig)

Med denna fix på plats får vi samma animering oberoende av bildhastigheten (men med 10fps är den ryckig som förväntat).

Efter att ha använt den reducerade bildhastigheten för att illustrera behovet av att ge hastighet i enheter / sekund kan vi kommentera raderna i installationen.cs som simulerade en långsam bildhastighet.

Animering i fysik

istället för att manuellt animera ett GameObject kan vi animera det genom att tillämpa fysik på det. Vi kan animera en cylinder (flytta höger med 5 enheter / sekund) genom att:

  • skapa ett plan (kallat plan)
  • skapa en Cylinder (kallad Cylinder)
  • Lägg till en Styvkroppskomponent till cylindern (och frysa rotationen i alla riktningar)
  • skapa ett Fysikmaterial, halt, utan friktion och applicera det på både Cylinder och plan
  • starta Cylinder med en initialhastighet med en skriptkomponent

tillgångar/cylinder.cs

med detta på plats kan vi se att sfären och cylindern rör sig åt höger i samma takt.

observationer:

  • sfärens position uppdateras omedelbart före renderingen (manuellt i uppdateringsmetoden)
  • cylinderns position uppdateras i den interna fysikuppdateringen.

animering med animering

ett tredje sätt att animera ett spelobjekt är med en animering (uppenbarligen). Vi kan animera en kapsel (försöker flytta höger med 5 enheter / sekund) genom att:

  • skapa en kapsel (kallad kapsel)
  • skapa en animationskontroller (även kapsel) och lägga till som en komponent i Kapselspelet.
  • skapa en animering (även kapsel).
  • i animeringskontrollen skapar du ett tillstånd (Start) med dess rörelse som Kapselanimering.
  • slutligen animerar vi positionen så att kapselns horisontella position är 5 enheter på 1 sekund.

med detta på plats kan vi se att sfären, cylindern, kapseln (nästan) rör sig åt höger i samma takt.

observationer:

  • inte säker på varför, men kapseln rörde sig något snabbare än väntat; problem sköt ett tag och förstod inte varför.
  • kapselns position kan konfigureras för att uppdateras före rendering (standard) eller under fysikuppdateringen.

implikationer av en snabb bildhastighet

på kraftfulla datorer kan man uppnå bildhastigheter upp till 150fps. På dessa datorer med standard fysikuppdateringar 50 gånger per sekund (0,02 sekunder mellan uppdateringarna) uppdateras de element som uppdateras före varje rendering oftare än de som uppdateras i fysikuppdateringarna. Denna skillnad är källan till problem med att blanda och matcha tidssteg.

medan jag inte kan öka bildhastigheten för min utvecklingsmaskin (begränsad till cirka 50 fps), kan jag artificiellt sakta ner fysikuppdateringarna till 10 uppdateringar per sekund (0.1 sekunder mellan uppdateringar) med hjälp av projektets inställningar.

som du kan se, genom att blanda och matcha tidssteg har vi återskapat problemet (inkonsekvent rörelse mellan spelelement).

för att korrigera kan vi ändra kapselns animering för att uppdatera fysikuppdateringar och på samma sätt uppdatera sfärens skriptkomponent enligt följande:

tillgångar/sfär.cs

med detta uppdateras alla animationer konsekvent före varje fysikuppdatering.

slutligen returnerar vi vår fysikuppdatering till 50fps (eller var 0.02: e sekund); uppnå både konsekventa och aktuella uppdateringar.

slutsatser

Efter att ha, ganska enkelt, återskapat problemet med att blanda och matcha timesteps, har jag övertygat mig själv om att jag borde lägga alla speltillstånd i fixedupdate-metoder.

Lämna ett svar

Din e-postadress kommer inte publiceras.