Slik løser du vanlige fysikkproblemer i spillet ditt

Mange spill bruker fysikk motorer til å kjøre måten ting beveger seg og reagerer på. Ved å bruke en fysikkmotor kan du legge til nedsenkning, øyeffis og, best av alt, fremvoksende spill, men kan også, hvis det brukes feil, føre til urealistiske resultater eller spillproblemer. I dette innlegget vil jeg forklare hvordan du identifiserer og løser vanlige problemer i dagens spill. 

Vi vil undersøke og løse disse problemene som sett i Unity, med fokus på den innebygde 3D-fysikkmotor Nvidia PhysX, men kjerneprinsippene kan brukes til enhver annen plattform og fysikkmotor.

Merk: Du kan finne et bredt utvalg av 3D-modeller for å komme i gang på Envato Market.

Demo

Denne demoen viser de fleste feilene som er nevnt i denne artikkelen, både i feil eller ødelagt tilstand, og i fast tilstand:

Normal skala

Dette er en enkel scene med en ball som treffer i en bunke fat. Den alternative versjonen Feil skala (10x) viser hvordan scenen endres på 10x skala (se skala markeringene på gulvet i demoen). Legg merke til hvordan det ser ut til å være i sakte bevegelse, men denne effekten er bare forårsaket av skalaen av scenen.

Character Controller

Dette viser et enkelt side-scroller-spill som virker som ønsket. Det "dårlige" alternativet; Rigidbody & Character Controller Sammen viser det samme spillet, men med en Rigidbody-komponent festet til tegnet. Legg merke til hvordan Rigidbody bryter opp betegnelsen til Character Controller.

Objekter med bounciness

Tønner er skutt fra siden av scenen og kastes inn i luften. Når de kommer krasjer ned, spretter de av bakken og beveger seg på enkle, men majestetiske måter. Den ødelagte versjonen viser den samme scenen uten bounciness, og det ser så mye kjedelig ut i sammenligning.

Ikke direkte endring av en Rigidbody's Transform

I dette scenariet skyves en tung ball opp med en rampe Rigidbody.AddForce (). I det andre scenariet, i stedet for å bruke Rigidbody.AddForce () å flytte ballen opp på rampen, Transform.position benyttes. Resultatet av å bruke Transform.position er det at ballen ruller ned igjen, på grunn av at den stive kroppen ikke tar riktig hensyn til den stive kroppens hastighetsendring, men så stiller posisjonsendringen ballen til å jittere opp og ned rampen.

Vanlige feil

Feil skala

I de fleste spill vil spillere anta at verdens skala er relatert til jordens skala. De forventer for eksempel en fiende som faller fra et uretårn for å falle i samme takt som du oppfatter på jorden. Hvis fienden faller for sakte eller for fort, kan det forringe nedsenking - spesielt hvis fienden er menneskelig størrelse!

Nvidia PhysX i Unity er satt opp for å bruke en enhet per meter. Du kan bruke denne egenskapen til å sjekke om skalaen av objektene dine er korrekte ved å bare legge til i en Unity-primitiv terning. Den primitive terningen er nøyaktig en kubikkmeter. Hvis du for eksempel ser at en oljefat i din scene er 2x større enn kuben, betyr det at oljebeholderen er to meter høy (6,56 fot)!

Å fikse skalaen er like enkelt som å skalere hvert objekt i scenen. Bare velg alle objektene i scenen din og bruk Scale verktøy for å gjøre dem større eller mindre. Hvis du merker at objektene dine beveger seg for fort, må du gjøre objektene større. Hvis du merker det motsatte - at gjenstandene beveger seg for sakte - skal du skalere objekterne nedover.

Du kan skalere objektene dine med mer presisjon ved å gruppere dem i ett null objekt, og skalere det ene objektet. For eksempel setter du skalaen til foreldreobjektet til 1.2 På hver akse øker størrelsen på hvert objekt i objektet med 20%. Du kan også skalere objektene i trinn ved hjelp av skalaverktøyet ved å holde nede Ctrl-LMB (Windows) eller Cmd-LMB (OS X).

Bruke en Rigidbody og en Character Controller sammen

Jeg har sett dette skje et par ganger, og det gir faktisk mening hvor ofte dette skjer. Utvikleren forutsetter at en tegnkontroller er nødvendig for å kontrollere deres avatar, men de vil at avataren skal bli påvirket av tyngdekraften og andre objekter i miljøet.

Problemet er at a Character Controller er designet for mer klassiske kontroller, som de som vanligvis finnes i en plattformspiller eller første personskytter. EN Stiv kropp er ganske enkelt et ikke-deformerbart objekt som påvirkes av tyngdekraft og andre fysiske krefter (som andre gjenstander som kolliderer med det). Disse er to svært separate komponenter, med forskjellige tilsiktede bruksområder.

Velg bare en tegnkontroll når du vil fullføre kontroll over hvordan spilleren beveger seg. På den annen side, hvis du vil at karakteren din skal drives av fysikkmotoren, bruk en Rigidbody. Når du legger til en Rigidbody til et tegn, vil du sannsynligvis vil begrense rotasjonen slik at spilleren ikke vælter over.

Direkte modifisering av en Rigidbody's Transform

I motsetning til en karakterkontroller er det ikke god praksis å sette stillingen eller rotasjonen av en stiv kropp, eller mållegge en stivbody gjenstand hele tiden (for spillerens kontroll og slikt). I stedet bør du bruke AddForce () og AddTorque () metodene som finnes i Rigidbody-klassen. Det er greit å angi posisjon og rotasjon av en Rigidbody direkte hvis du for eksempel gyter i objektet for første gang, eller tilbakestiller scenen. I den situasjonen vil det være bra, så lenge Rigidbody ikke krysser andre gjenstander.

Dette betyr at når en stivbody flyttes til en eksakt posisjon eller rotasjonsstatus, kan den passere gjennom en gjenstand. Fysikkmotoren må da rette opp på dette problemet, og mesteparten av tiden går ikke fysikkmotoren i gang. Oppdater() meldingen gjør det. Sluttresultatet er jittery atferd når det er et kryss, og det er mulig at den stive kroppen kan passere gjennom objekter helt.

En annen dårlig bivirkning som kan oppstå når man sier at man beveger en fast kropp langs en akse for spillerbevegelse, er at den stive kroppen er internt simulert og deretter gjelder den posisjonen. Oppdatere posisjonen beveger deretter den stive leggen uten å ta hensyn til hastighetsendringen og slikt. Hvis den stive kroppen ruller tilbake nedover en skråning, vil den bevege den stive leggen bakover, mens posisjonens endringskode beveger den stive leggen tilbake oppover skråningen.

Objekter Rolling Forever

La oss si at du utvikler et golfspill. Det er et problem med hvordan golfballen ikke slutter å rulle og på en eller annen måte klarer å fortsette å rulle på for alltid så lenge det ikke er noen form for hull eller grøft i banen. Årsaken til at dette skjer, er at ballen i virkeligheten vil bli redusert av gresset som går over (blant annet), siden det må presse de små gressbladene ned, er gresset i hovedsak som en konstant rampe. Dette kalles rullende motstand. Enhet kan ikke simulere denne oppførselen nøyaktig, så i stedet må kunstige stoppekrefter brukes.

I enhet er den beste kraften til å stoppe et objekt fra å rulle for alltid, "vinkelmotstand". Å endre vinkeltrekk på golfballen er måten å fikse dette problemet på. Den nøyaktige verdien avhenger virkelig av oppførselen du leter etter, men du kan legge merke til at en verdi på 1,0 kantet dra kanskje ikke engang er nok i noen tilfeller.

Objekter Uten Bounciness

Nesten hvert objekt i verden spretter etter en innvirkning. Enhetens interne, standardfysikkmateriale har ingen sprette i det hele tatt. Betydning av hvert objekt vil ikke hoppe med mindre du tilsidesetter standardfysikkmaterialet eller bruker et fysikkmateriale til objektene i scenen din med en bounciness-verdi høyere enn 0.

En av de beste måtene for å fikse dette problemet er å opprette en egen standardfysikkmateriale og tildele den i Fysikkbehandling funnet ved å klikke Rediger> Prosjektinnstillinger> Fysikk.

Rigidbodies Delvis Sinking Into Geometry

De fleste fysikkmotorer har en slags parameter som dikterer hvor mye to objekter kan interpenetreres eller krysses inntil de skyves vekk fra hverandre. Denne parameteren kalles Min penetrasjon for straff i enhet. Som standard er denne verdien 0,01 (meter), noe som betyr at objekter som standard kan skjære opp til 1 centimeter (nesten 0,4 tommer) før de skyves fra hverandre.

Du bør sette Min penetrasjon for straff til en verdi der det er knapt merkbart at objekter skjærer. Setter verdien til noe lite, for eksempel 0,0001, kan føre til jittery rigidbodies.

Slik forebygger du feil

Skrivekode for Rigidbodies (for programmerere)

Hvis du ikke er programmerer, trenger du ikke å bekymre deg for følgende scenario. Når du skriver kode som beveger, roterer eller skalerer stive legemer, er det viktig å beholde dette i FastedUpdate-sløyfen. Skriver denne koden i Oppdater loop vil potensielt føre til ustabile resultater, siden Oppdater funksjonen kan kalles ved 1000 Hz, mens fysikkmotor og FixedUpdate funksjonen kalles som standard ved 50 Hz. 

Du kan endre frekvensen på fysikkstrinnene ved å endre parameteren Fast Timestep, funnet i Rediger> Prosjektinnstillinger> Tid. Verdien bestemmer hvor mye tid som ventes, i sekunder, mellom hver fysikkoppdatering eller -trinn. Du kan trene frekvensen i Hertz ved å dele 1 med verdien (for eksempel en 0,01 sekunders vent betyr 1 / 0.01 = 100 Hz). Jo hyppigere trinnene, desto mer nøyaktige og stabile blir simuleringen. Imidlertid kan innstillingen av frekvensen høyere enn CPU'en håndtere resultere i en svært ustabil simulering. Prøv å holde fast oppdateringsfrekvensen mellom 30 Hz og 100 Hz.

Mens jeg jobbet på en ødeleggende murvegg, løp jeg inn i et problem som skyldes Instantiating murstein etter at en del av veggen hadde blitt ødelagt. Jeg løste dette problemet ved å plassere den problematiske koden i en Coroutine, og plassere følgende linje før du ødelegger objektet:

// Vent en rammeavkastningsavkastning null; // C # utbytte; // UnityScript

I venter på en ramme, vil det garantere at logikken ble synkronisert i oppdateringstid, i stedet for fasttidspunktstid. Dette synes å bety at Destroy-funksjonen utføres i synkronisering med oppdateringssløyfen.

Bonus Unity Tip: Ikke bruk Standard Assets Physics Materials!

Fysikkmaterialepakken, som kommer som en del av Unity Standard Assets, er faktisk nesten helt ubrukelig. Det finnes fem fysikkmaterialer i pakken, og alle er urealistiske på en eller annen måte. 

Hvert materiale har identisk statisk og dynamisk friksjon. I den virkelige verden har gjenstander som står stille fortsatt litt mer friksjon da de beveger seg. Gummimaterialets friksjonskoeffisient er 1.0, som ikke ligner på noe gummi som finnes i den virkelige verden. Og hvis det ikke høres dumt nok, har hvert materiale 0 "bounciness" (unntatt "Bouncy" -materialet). Alt dette betyr at materialene ikke engang er et nært preg av deres virkelige livsvarige. 

Det er best å lage dine egne fysikkmaterialer når det er nødvendig. Det er mange nettsteder rundt som deler fysiske egenskaper av materialer - de viktigste er dynamisk friksjon, statisk friksjon og restitusjon eller bounciness.

Konklusjon

Svært få fysikkrelaterte problemer er faktisk så vanskelig å fikse. Hvis det er noen form for fysikkrelatert feil som synes vanskelig å spore opp, prøv å senke tiden for å se hva som skjer. Hvis du merker at problemet starter rundt en bestemt linje med kode, kan du bruke Debug.Break til å pause redaktøren og kontrollere hva som skjer. Du er velkommen til å kommentere her hvis du har spørsmål eller trenger hjelp.