Så här fixar du vanliga fysikproblem i ditt spel

Många spel använder fysikmotorer för att driva hur sakerna rör sig och reagerar. Genom att använda en fysikmotor kan man lägga till nedsänkning, ögonsocker och, bäst av allt, framväxande gameplay, men kan också, om de används felaktigt, leda till orealistiska resultat eller spelproblem. I det här inlägget kommer jag att förklara hur man identifierar och åtgärdar vanliga problem som ses i dagens spel. 

Vi kommer att undersöka och lösa dessa problem som ses i Unity, med inriktning på den inbyggda 3D-fysikmotorn Nvidia PhysX, men kärnprinciperna kan tillämpas på någon annan plattforms- och fysikmotor.

Obs! Du kan hitta ett brett urval av 3D-modeller för att komma igång på Envato Market.

demo

Denna demo visar de flesta misstag som nämns i den här artikeln i både felaktigt eller brutet tillstånd och i ett fast tillstånd:

Normal skala

Detta är en enkel scen med en boll som träffar en stapel fat. Den alternativa versionen Felaktig skala (10x) visar hur scenen ändras med 10x skala (se skala markeringar på demoens golv). Lägg märke till hur det verkar vara i slowmotion, men denna effekt beror helt enkelt på scenens skala.

Karaktärskontroller

Detta visar en enkel sida-scroller spel som fungerar. Det "dåliga" alternativet; Rigidbody & Character Controller tillsammans visar samma spel, men med en Rigidbody-komponent kopplad till tecknet. Lägg märke till hur Rigidbody bryter upp beteendet hos Character Controller.

Objekt med brådska

Flikar skottas från scenens sida och kastas in i luften. När de kraschar ner, studsar de av marken och rör sig på enkla men majestätiska sätt. Den trasiga versionen visar samma scen utan studs och det ser så mycket ut som tråkigt i jämförelse.

Direkt Ändra inte en Rigidbodys Transform

I detta scenario trycks en tung boll upp en ramp med Rigidbody.AddForce (). I det andra scenariot, istället för att använda Rigidbody.AddForce () att flytta bollen uppför rampen, Transform.position är använd. Resultatet av att använda Transform.position är det att bollen rullar tillbaka ner på grund av att den styva kroppen inte korrekt tar hänsyn till den styva kroppens hastighetsförändring, men då ändrar positionändringen bollen att jitter upp och ner rampen.

Vanliga misstag

Felaktig skala

I de flesta spel skulle spelare anta att världens skala är relaterad till jordens skala. De skulle exempelvis förvänta sig att en fiende som faller från ett vaktornat faller i samma takt som du skulle uppleva på jorden. Om fienden faller för långsamt eller för snabbt, kan det förringa fördjupningen - särskilt om fienden är mänsklig storlek!

Nvidia PhysX i Unity är inställd för att använda en enhet per meter. Du kan använda denna egenskap för att kontrollera om skalan av dina objekt är korrekta genom att helt enkelt lägga till i en Unity primitiv kub. Den primitiva kuben är exakt en kubikmeter. Om du exempelvis märker att en oljecylinder i din scen är 2x större än kuben, betyder det att din oljecylinder är två meter lång (6,56 fot)!

Att fixera skalan är lika lätt som att skala varje objekt i scenen. Välj bara alla objekt i din scen och använd Skala verktyg för att göra dem större eller mindre. Om du märker att dina föremål rör sig för snabbt, gör objekten större. Om du märker det motsatta - att föremålen rör sig för långsamt - ska du skala ned objekten.

Du kan skala dina objekt med mer precision genom att gruppera dem i ett nollobjekt och skala det där objektet. Till exempel ställer du in skalan av moderobjektet till 1,2 På varje axel ökar storleken på varje objekt inom objektet med 20%. Du kan också skala objekten i steg med hjälp av skalverktyget genom att hålla ned Ctrl-LMB (Windows) eller Cmd-LMB (OS X).

Använda en Rigidbody och en Character Controller tillsammans

Jag har sett detta hända ett par gånger, och det är faktiskt meningslöst hur ofta det här inträffar. Utvecklaren förutsätter att en teckenkontroller är nödvändig för att kontrollera deras avatar, men de vill att avataren påverkas av gravitation och andra objekt i miljön.

Problemet är att a Karaktärskontroller är utformad för mer klassiska kontroller, som de som vanligtvis hittas i en plattformsspelare eller första personskytte. en Rigidbody är helt enkelt ett icke-deformerbart objekt som påverkas av tyngdkraften och andra fysiska krafter (som andra föremål som kolliderar med det). Dessa är två mycket separata komponenter, med olika avsedda användningsområden.

Välj bara en karaktärskontroll när du vill slutföra kontrollen över hur spelaren rör sig. Å andra sidan, om du vill att din karaktär ska drivas av fysikmotorn, använd en Rigidbody. När du lägger till en Rigidbody till en karaktär, kommer du förmodligen att begränsa rotation så att spelaren inte topplar över.

Direkt Ändra en Rigidbodys Transform

Till skillnad från en karaktärskontroller är det inte bra att ställa positionen eller rotationen på en styv kropp, eller ständigt skala ett styvkroppsobjekt (för spelarkontroll och liknande). Istället bör du använda AddForce () och AddTorque () -metoderna som finns i klassen Rigidbody. Det är okej att direkt ställa in en Rigidbodys position och rotation om du till exempel gyter i objektet för första gången eller återställer scenen. I den situationen kommer det att bli bra, så länge som Rigidbody inte korsar andra föremål.

Detta betyder att när en stel kropp flyttas till en exakt position eller rotationsläge, kan den passera genom ett objekt. Fysikmotorn måste sedan korrigera denna fråga, och mestadels fysikmotorn kör inte samtidigt Unitys Uppdatering() meddelandet gör det. Slutresultatet är jitterigt beteende när det finns ett korsning, och det är möjligt att den styva kroppen kan passera genom objekt helt.

En annan dålig bieffekt som kan uppstå när man säger att man rör en styv kropp längs en axel för spelarrörelsen är att den styva kroppen internt simuleras och sedan applicerar den sin position. Uppdatering av positionen flyttar sedan den styva kroppen utan hänsyn till hastighetsbyte och sådant. Om den styva kroppen rullar tillbaka nerför en lutning kommer den att flytta den styva kroppen bakåt medan din position ändrande kod flyttar den styva kroppen tillbaka uppför backen.

Objekt Rolling Forever

Låt oss säga att du utvecklar ett golfspel. Det finns ett problem med hur golfbollen inte slutar rulla och på något sätt lyckas fortsätta rulla på för evigt så länge det inte finns någon form av hål eller grus i sin väg. Anledningen till att detta händer är att bollen i det verkliga livet skulle sakta ner genom gräset som det löper över (bland annat), eftersom det måste pressa de lilla gräsbladen ner är gräset i huvudsak som en konstant ramp. Det här kallas rullmotstånd. Enhet kan inte simulera detta beteende exakt, så i stället måste konstgjorda stoppkrafter användas.

I enhet är den bästa kraften att använda för att stoppa ett objekt från att rulla för alltid "vinkeldrag". Att ändra vinkeln på golfbollen är sättet att lösa problemet. Det exakta värdet beror verkligen på beteendet du letar efter, men du kanske märker att ett värde på 1,0 vinkeldrag inte ens kan räcka i vissa fall.

Objekt utan uppror

Nästan varje objekt i världen studsar efter en inverkan. Enhetens interna standardfysikmaterial har ingen studs alls. Att innebära att varje objekt inte studsar om du inte åsidosätter standardfysikmaterialet eller tillämpar ett fysikaliskt material på objekten i din scen med ett stigningsvärde högre än 0.

Ett av de bästa sätten att lösa problemet är att skapa en egen standardfysikmaterial och tilldela den i Fysikchef hittades genom att klicka på Redigera> Projektinställningar> Fysik.

Rigidbodies Delvis Sinking In Geometry

De flesta fysikmotorer har någon form av parameter som dikterar hur mycket två föremål som kan skjutas upp eller skärs tills de skjuts iväg från varandra. Denna parameter kallas Min Penetration för straff i enhet. Som standard är detta värde 0,01 (meter), vilket innebär att objekten som standard kan skjuta upp till 1 centimeter (nästan 0,4 tum) innan de trycks in.

Du borde ställa in Min penetration för straff till ett värde där det knappast är märkbart att föremål skär varandra. Ställ in värdet till något litet, till exempel 0,0001, kan resultera i jittery rigidbodies.

Hur man förebygger misstag

Skriven kod för Rigidbodies (för programmerare)

Om du inte är programmerare behöver du inte oroa sig för följande scenario. När du skriver kod som rör sig, roterar eller vågar fasta kroppar, är det viktigt att hålla detta i FixedUpdate-slingan. Skriva den här koden i Uppdatering loop kan eventuellt leda till instabila resultat, eftersom Uppdatering funktionen kan kallas vid 1000 Hz, medan fysikmotorn och FixedUpdate funktionen kallas som standard vid 50 Hz. 

Du kan ändra frekvensen på fysiksteg genom att ändra parametern Fast Timestep, hittades i Redigera> Projektinställningar> Tid. Värdet bestämmer hur mycket tid som väntar, i sekunder, mellan varje fysikuppdatering eller steg. Du kan träna frekvensen i Hertz genom att dividera 1 till värdet (till exempel en 0,01 sekund vänt betyder 1 / 0.01 = 100 Hz). Ju oftare stegen, ju mer exakt och stabil simuleringen blir. Men inställningen av frekvensen högre än CPU: n kan hantera kommer att resultera i en väldigt instabil simulering. Försök hålla frekvensen Fast uppdatering mellan 30 Hz och 100 Hz.

Samtidigt som jag arbetade på en förstörbar tegelvägg, gick jag in i ett problem som orsakades av Instantiating tegelstenar efter att en bit av väggen hade förstörts. Jag fixade problemet genom att placera den problematiska koden i en Coroutine och placera följande rad innan du förstör objektet:

// Vänta en ramavkastningsavkastning null; // C # utbyte; // UnityScript

I väntan på en ram skulle det garantera att logiken synkroniserades i Uppdateringstid, snarare än FixedUpdate-tid. Detta verkar innebära att Destroy-funktionen körs i synkronisering med uppdateringsslingan.

Bonusenhetstips: Använd inte standardmaterialets fysikmaterial!

Fysikmaterialpaketet, som kommer som en del av Unity Standard Assets, är faktiskt nästan helt värdelös. Det finns fem fysikmaterial i paketet, och alla är orealistiska på något sätt. 

Varje material har identisk statisk och dynamisk friktion. I den verkliga världen har föremål som står stilla något mer friktion då de rör sig. Gummimaterialets friktionskoefficient är 1,0, vilket inte liknar något gummi som finns i den verkliga världen. Och om det inte låter dumt nog, har allt material 0 "bounciness" (exklusive "Bouncy" -materialet). Allt detta betyder att materialen inte ens är en närmare representation av deras verkliga motpart. 

Det är bäst att skapa egna fysikmaterial när det behövs. Det finns många webbplatser runt det som delar fysiska egenskaper hos material - de viktigaste är dynamisk friktion, statisk friktion och återställande eller brådskning.

Slutsats

Mycket få fysikrelaterade problem är faktiskt det svåra att fixa. Om det finns någon typ av fysikrelaterad bugg som verkar svår att spåra, försök sakta ner tiden för att se vad som händer. Om du märker att problemet börjar kring en viss kodkod, kan du använda Debug.Break för att pausa redigeraren och inspektera vad som händer. Gärna kommentera här om du har några frågor eller behöver hjälp.