Gemeenschappelijke fysica-problemen in je spel oplossen

Veel games gebruiken physics-engines om de manier waarop dingen bewegen en reageren te sturen. Het gebruik van een physics engine kan onderdompeling, eye candy en, het beste van alles, een opkomende gameplay toevoegen, maar kan ook, als het verkeerd wordt gebruikt, leiden tot onrealistische resultaten of spelbrekende problemen. In dit bericht leg ik uit hoe je veelvoorkomende problemen in games van vandaag kunt identificeren en oplossen. 

We zullen deze problemen onderzoeken en oplossen, zoals we die zien in Unity, met de nadruk op de ingebouwde 3D-fysica-engine Nvidia PhysX, maar de kernprincipes kunnen worden toegepast op elke andere platform- en fysica-engine.

Opmerking: u kunt een brede selectie 3D-modellen vinden om van start te gaan op Envato Market.

demonstratie

Deze demo toont de meeste fouten die in dit artikel worden genoemd in zowel een onjuiste als een gebroken staat en in een vaste staat:

Normale schaal

Dit is een eenvoudige scène met een bal die tegen een stapel vaten slaat. De alternatieve versie Onjuiste schaal (10x) laat zien hoe de scène verandert op 10x schaal (zie de schaalaanduidingen op de vloer van de demo). Merk op hoe het lijkt in slow motion, maar dit effect wordt simpelweg veroorzaakt door de schaal van de scène.

Teken controller

Dit toont een eenvoudig side-scroller-spel dat werkt zoals bedoeld. Het "slechte" alternatief; Rigidbody & Character Controller samen toont hetzelfde spel, maar met een Rigidbody-component gekoppeld aan het personage. Let op hoe de Rigidbody het gedrag van de Character Controller breekt.

Voorwerpen met springerigheid

Vaten worden vanaf de zijkant geschoten en in de lucht geslingerd. Terwijl ze instorten, stuiteren ze van de grond en bewegen ze zich op eenvoudige maar majestueuze manieren. De kapotte versie toont dezelfde scène zonder bounciness, en het ziet er in vergelijking veel saaier uit.

Niet direct de rigidbody-transformatie aanpassen

In dit scenario wordt een zware bal op een helling omhoog geduwd met Rigidbody.AddForce (). In het tweede scenario, in plaats van gebruiken Rigidbody.AddForce () om de bal de oprit op te rijden, Transform.position is gebruikt. Het resultaat van het gebruik Transform.position is dat de bal terug rolt, vanwege het feit dat het rigide lichaam niet goed rekening houdt met de snelheidsverandering van het stijve lichaam, maar dan zorgt de positie-aanpassing ervoor dat de bal op en neer schommelt op de oprit.

Veelgemaakte fouten

Onjuiste schaal

In de meeste spellen nemen spelers aan dat de schaal van de wereld vergelijkbaar is met de schaal van de aarde. Ze zouden bijvoorbeeld verwachten dat een vijand die van een wachttoren valt, in hetzelfde tempo valt als je op aarde zou waarnemen. Als de vijand te langzaam of te snel valt, kan dit afbreuk doen aan de onderdompeling, vooral als de vijand van menselijke maat is!

Nvidia PhysX in Unity is ingesteld om één eenheid per meter te gebruiken. U kunt deze eigenschap gebruiken om te controleren of de schaal van uw objecten juist is door simpelweg een Unity-primitieve kubus toe te voegen. De primitieve kubus is precies één kubieke meter. Als u bijvoorbeeld opmerkt dat een olievat in uw scène 2x groter is dan de kubus, betekent dit dat uw olievat twee meter lang is (6,56 voet)!

Het maken van de schaal is net zo eenvoudig als het schalen van elk object in de scène. Selecteer gewoon alle objecten in uw scène en gebruik de Schaal hulpmiddel om ze groter of kleiner te maken. Als u merkt dat uw objecten te snel bewegen, maakt u de objecten groter. Als u het tegenovergestelde opmerkt - dat de objecten te langzaam bewegen - moet u de objecten naar beneden schalen.

U kunt uw objecten met meer precisie schalen door ze in één nulobject te groeperen en dat ene object te schalen. U kunt bijvoorbeeld de schaal van het bovenliggende object instellen 1.2 op elke as verhoogt de grootte van elk object in het object met 20%. U kunt de objecten ook in stappen schalen met behulp van het schaalgereedschap door ingedrukt te houden Ctrl-LMB (Windows) of Cmd-LMB (OS X).

Samen een Rigidbody en een Character Controller gebruiken

Ik heb dit een paar keer zien gebeuren en het is eigenlijk logisch hoe vaak dit voorkomt. De ontwikkelaar gaat ervan uit dat een karaktercontroller nodig is om hun avatar te besturen, maar ze willen dat de avatar wordt beïnvloed door de zwaartekracht en andere objecten in de omgeving.

Het probleem is dat een Teken controller is ontworpen voor meer klassieke besturingselementen, zoals die gewoonlijk worden gevonden in een platformgame of first person shooter. EEN star lichaam is gewoon een niet-vervormbaar object dat wordt beïnvloed door zwaartekracht en andere fysieke krachten (zoals andere objecten die ermee botsen). Dit zijn twee zeer afzonderlijke componenten, met verschillende beoogde toepassingen.

Kies alleen een tekencontroller als je controle wilt over hoe de speler beweegt. Aan de andere kant, als je wilt dat je personage wordt aangedreven door de physics engine, gebruik dan een Rigidbody. Bij het toevoegen van een Rigidbody aan een personage, wil je waarschijnlijk de rotatie beperken, zodat de speler niet omvalt.

Rechtstreeks de transformatie van een Rigidbody wijzigen

In tegenstelling tot een karaktercontroller, is het geen goede gewoonte om de positie of rotatie van een rigide lichaam in te stellen, of om een ​​rigidbody-object constant te schalen (voor spelerbesturing en dergelijke). Gebruik in plaats daarvan de methoden AddForce () en AddTorque () in de Rigidbody-klasse. Het is prima om de positie en rotatie van een Rigidbody direct in te stellen als u bijvoorbeeld voor het eerst in het object spawnt of de scène opnieuw instelt. In die situatie zal het goed zijn, zolang de Rigidbody geen andere objecten kruist.

Dit is van belang omdat, wanneer een rigide lichaam wordt verplaatst naar een exacte positie of rotatietoestand, het door een object kan gaan. De physics-engine moet dit probleem corrigeren en meestal loopt de physics-engine niet tegelijkertijd Unity's Bijwerken() bericht doet. Het eindresultaat is zenuwachtig gedrag wanneer er een kruispunt is, en het is mogelijk dat het rigide geheel volledig door objecten kan passeren.

Een ander slecht neveneffect dat kan optreden wanneer, bijvoorbeeld, het verplaatsen van een rigide lichaam langs een as voor spelerbeweging, is dat intern het rigide lichaam wordt gesimuleerd en vervolgens de positie ervan toepast. Het bijwerken van de positie verplaatst dan het rigide lichaam zonder rekening te houden met de snelheidsverandering en dergelijke. Als het stijve lichaam van een helling terugrolt, zal het het stijve lichaam naar achteren verplaatsen, terwijl uw positie veranderende code het rigide lichaam de helling weer op doet rijden.

Voorwerpen die voor altijd rollen

Laten we zeggen dat je een golfspel aan het ontwikkelen bent. Er is een probleem met hoe de golfbal niet ophoudt met rollen en op de een of andere manier erin slaagt voor eeuwig door te rollen zolang er geen soort van gat of greppel op zijn pad is. De reden waarom dit gebeurt is omdat in het echte leven de bal zou worden afgeremd door het gras (onder andere) over het gras, omdat het de kleine grassprieten omlaag moet duwen, het gras is in wezen als een constante hellingbaan. Dit heet rolweerstand. Eenheid kan dit gedrag niet nauwkeurig simuleren, dus moeten in plaats daarvan kunstmatige remkrachten worden gebruikt.

In Unity is de beste kracht om te gebruiken om te voorkomen dat een voorwerp voor eeuwig blijft rollen, "hoekige weerstand". Het wijzigen van de hoekweerstand op de golfbal is de manier om dit probleem op te lossen. De exacte waarde hangt echt af van het gedrag waarnaar u op zoek bent, maar u zult misschien merken dat een waarde van 1,0 hoekig slepen misschien zelfs niet genoeg is in sommige gevallen.

Objecten zonder springerigheid

Bijna elk voorwerp in de wereld botst na een botsing. Het interne, standaard natuurkundig materiaal van Unity heeft helemaal geen weerkaatsing. Dit betekent dat elk object niet terugkaatst tenzij je het standaard natuurkundig materiaal vervangt of een natuurkundig materiaal toepast op de objecten in je scène met een springvermogenwaarde hoger dan 0.

Een van de beste manieren om dit probleem op te lossen, is door een eigen standaard natuurkundig materiaal te maken en dit toe te wijzen in de Physics Manager gevonden door te klikken op Bewerken> Projectinstellingen> Natuurkunde.

Stijve lichamen die deels in de geometrie zinken

De meeste physics-engines hebben een soort parameter die bepaalt hoeveel twee objecten elkaar kunnen doordringen of elkaar kruisen totdat ze van elkaar worden weggeduwd. Deze parameter wordt Min Penetration For Penalty in Unity genoemd. Standaard is deze waarde 0,01 (meter), wat betekent dat objecten standaard tot 1 centimeter (bijna 0,4 inch) elkaar kunnen snijden voordat ze worden geduwd.

Je zou moeten instellen Min penetratie voor straf tot een waarde waar het nauwelijks opvalt dat objecten elkaar kruisen. De waarde instellen op iets kleins, zoals 0,0001, kan resulteren in schokkerige rigidbodies.

Hoe fouten te voorkomen

Schrijfcode voor rigidbodies (voor programmeurs)

Als u geen programmeur bent, hoeft u zich geen zorgen te maken over het volgende scenario. Bij het schrijven van code die rigidbodies verplaatst, roteert of schaaft, is het belangrijk om deze in de FixedUpdate-lus te houden. Deze code schrijven in de Bijwerken loop zal mogelijk tot onstabiele resultaten leiden, aangezien de Bijwerken functie kan worden aangeroepen op 1000 Hz, terwijl de physics engine en de FixedUpdate De functies worden elk standaard 50 Hz genoemd. 

U kunt de frequentie van natuurkundige stappen wijzigen door de parameter te wijzigen Vaste tijdbepaling, gevonden in Bewerken> Projectinstellingen> Tijd. De waarde bepaalt hoeveel tijd wordt gewacht, in seconden, tussen elke fysica-update of -stap. U kunt de frequentie in Hertz berekenen door 1 te delen door de waarde (een 0,01 seconde wacht betekent bijvoorbeeld 1 / 0,01 = 100 Hz). Hoe frequenter de stappen, hoe nauwkeuriger en stabieler de simulatie zal zijn. Als u echter de frequentie hoger instelt dan de CPU aankan, resulteert dit in een zeer onstabiele simulatie. Probeer de vaste updatefrequentie tussen 30 Hz en 100 Hz te houden.

Terwijl ik aan een vernietigbare bakstenen muur werkte, kwam ik een probleem tegen dat werd veroorzaakt door Instantiating-stenen nadat een stuk van de muur was vernietigd. Ik heb dit probleem verholpen door de problematische code in een Coroutine te plaatsen en de volgende regel te plaatsen voordat het object wordt vernietigd:

// Wacht een frame-opbrengst return null; // C # opbrengst; // UnityScript

Door te wachten op een frame, zou het garanderen dat de logica werd gesynchroniseerd in Updatetijd in plaats van FixedUpdate-tijd. Dit lijkt te betekenen dat de functie Vernietigen synchroon met de updatelus wordt uitgevoerd.

Bonuseenheidentip: Gebruik de standaardactiva natuurkundematerialen niet!

Het pakket Physics Materials, dat deel uitmaakt van de Unity Standard Assets, is eigenlijk bijna volledig nutteloos. Er zijn vijf natuurkundematerialen in het pakket en ze zijn allemaal op een of andere manier onrealistisch. 

Elk materiaal heeft een identieke statische en dynamische wrijving. In de echte wereld hebben objecten die stilstaan ​​iets meer wrijving dan wanneer ze bewegen. De wrijvingscoëfficiënt van het rubbermateriaal is 1.0, die niet lijkt op enig rubber dat in de echte wereld wordt gevonden. En als dat niet gek genoeg klinkt, heeft elk materiaal 0 "bounciness" (exclusief het "Bouncy" -materiaal). Dit alles betekent dat de materialen niet eens een directe weergave zijn van hun tegenhanger in de praktijk. 

Het is het beste om, indien nodig, je eigen fysische materialen te maken. Er zijn veel websites in de buurt die fysieke eigenschappen van materialen delen - de belangrijkste zijn dynamische wrijving, statische wrijving en restitutie of bounciness..

Conclusie

Heel weinig fysica-gerelateerde problemen zijn eigenlijk zo moeilijk te repareren. Als er een fysica-gerelateerde bug is die moeilijk op te sporen lijkt, probeer dan de tijd te vertragen om te zien wat er aan de hand is. Als je merkt dat het probleem begint rond een bepaalde coderegel, kun je Debug.Break gebruiken om de editor te pauzeren en te inspecteren wat er aan de hand is. Voel je vrij om hier commentaar te geven als je vragen hebt of hulp nodig hebt.