Multe jocuri folosesc motoarele fizicii pentru a conduce modul în care lucrurile se mișcă și reacționează. Folosind un motor de fizică pot adăuga imersiune, bomboane ochi și, mai presus de toate, gameplay-ul emergent, dar poate, de asemenea, dacă este utilizat incorect, să ducă la rezultate nerealiste sau probleme de rupere a jocului. În acest post, vă voi explica cum să identificați și să remediați problemele comune văzute în jocurile de astăzi.
Vom examina și rezolva aceste probleme, așa cum se vede în Unitate, concentrându-se pe motorul fizic 3D Nvidia PhysX încorporat, dar principiile de bază pot fi aplicate la orice altă platformă și motor de fizică.
Notă: Puteți găsi o gamă largă de modele 3D pentru a vă începe activitatea pe Envato Market.
Acest demo arată cele mai multe dintre greșelile menționate în acest articol, atât în stare incorectă, cât și în stare defectă, și într-o stare fixă:
Aceasta este o scenă simplă cu o minge care lovește într-o grămadă de butoaie. Versiunea alternativă Scala incorectă (10x) arată modul în care scena se schimbă la scara de 10x (vedeți marcajele scării de pe podeaua demo-ului). Observați cum pare să se afle în mișcare lentă, dar acest efect este pur și simplu cauzat de amploarea scenei.
Acest lucru arată un simplu joc side-scroller care funcționează conform destinației. Alternativa "rea"; Corpul robust și controlerul de caractere împreună arată același joc, dar cu o componentă Rigidbody atașată personajului. Observați cum Rigidbody sparge comportamentul Controlorului de caractere.
Butoaiele sunt împușcați din partea laterală a scenei și sunt aruncate în aer. Pe măsură ce se prăbușesc, se zbură de la sol și se mișcă în moduri simple, dar maiestuoase. Varianta ruptă arată aceeași scenă fără sărăcie, și pare mult mai plictisitoare în comparație.
În acest scenariu, o minge greu este împins pe o rampă folosind Rigidbody.AddForce ()
. În al doilea scenariu, în loc de a utiliza Rigidbody.AddForce ()
pentru a muta mingea pe rampă, Transform.position
este folosit. Rezultatul utilizării Transform.position
este că mingea se învârte înapoi, datorită faptului că carcasa rigidă nu ține cont în mod corespunzător de modificarea vitezei caroseriei rigide, dar apoi modificarea poziției determină mișcarea bilei în sus și în jos pe rampă.
În majoritatea jocurilor, jucătorii ar presupune că scara lumii este relativă la scara Pământului. Se așteaptă, de exemplu, ca un dușman care cade dintr-un turn de veghe să cadă la aceeași viteză pe care o veți percepe pe Pământ. Dacă vrăjmașul cade prea lent sau prea repede, el poate scădea de la scufundare - mai ales dacă inamicul este de dimensiuni umane!
Nvidia PhysX în unitate este configurată să utilizeze o unitate pe metru. Puteți utiliza această trăsătură pentru a verifica dacă scara obiectelor dvs. este corectă prin simpla adăugare într-un cub primitiv Unity. Cubul primitiv este exact un metru cub. Dacă observați, de exemplu, că un butoi de ulei în scena dvs. este de 2 ori mai mare decât cubul, ceea ce înseamnă că barza dvs. de petrol este de doi metri înălțime (6,56 picioare)!
Fixarea scalei este la fel de ușoară ca scalarea fiecărui obiect din scenă. Doar selectați toate obiectele din scenă și utilizați Scară pentru a le face mai mari sau mai mici. Dacă observați că obiectele se mișcă prea repede, faceți obiectele mai mari. Dacă observați opusul - că obiectele se mișcă prea lent - ar trebui să scalați obiectele în jos.
Puteți să vă scalați obiectele cu mai multă precizie, grupându-le într-un obiect nul și diminuând acel obiect. De exemplu, setarea scării obiectului părinte la 1.2
pe fiecare axă va crește dimensiunea fiecărui obiect din interiorul obiectului cu 20%. De asemenea, puteți scala obiectele în trepte utilizând instrumentul de scalare ținând apăsat Ctrl-LMB (Windows) sau Cmd-LMB (OS X).
Am văzut acest lucru de câteva ori, și de fapt are sens cât de des se întâmplă acest lucru. Dezvoltatorul presupune că un controler de caractere este necesar pentru a controla avatarul, dar dorește ca acesta să fie afectat de gravitație și alte obiecte din mediul înconjurător.
Problema este că a Controler de caractere este proiectat pentru mai multe controale clasice, cum ar fi cele găsite în mod obișnuit într-un platformer sau în primul person shooter. A Corp rigid este pur și simplu un obiect nedeformabil care este afectat de gravitație și alte forțe fizice (cum ar fi alte obiecte care se ciocnesc cu el). Acestea sunt două componente foarte separate, cu destinații diferite.
Alegeți numai un controler de caractere atunci când doriți să finalizați controlul asupra modului în care se mișcă playerul. Pe de altă parte, dacă doriți ca caracterul dvs. să fie condus de motorul fizicii, utilizați un corp rigid. În adăugarea unui Rigidbody la un personaj, probabil că veți dori să constrângeți rotația, astfel încât jucătorul să nu se răstoarne.
Spre deosebire de controlerul de caractere, nu este o practică bună să setați poziția sau rotația unui corp rigid sau să scalați constant un obiect rigid al corpului (pentru controlul jucătorului și altele asemenea). În schimb, ar trebui să utilizați metodele AddForce () și AddTorque () găsite în clasa Rigidbody. Este bine să setați direct poziția și rotația unui corp rigid dacă, de exemplu, faceți o reproducere în obiect pentru prima dată sau resetați scena. În această situație va fi bine, atâta timp cât Corpul Rigid nu se intersectează cu alte obiecte.
Acest lucru contează deoarece, atunci când un corp rigid este mutat într-o poziție exactă sau într-o stare de rotație, el poate trece printr-un obiect. Motorul fizicii va trebui apoi să corecteze această problemă și, de cele mai multe ori, motorul de fizică nu rulează în același timp Unitatea Actualizați()
mesajul. Rezultatul final este comportamentul jignitor ori de câte ori există o intersecție și este posibil ca corpul rigid să treacă prin obiecte în întregime.
Un alt efect secundar care poate apărea atunci când, de exemplu, se deplasează o carcasă rigidă de-a lungul unei axe pentru mișcarea jucătorului, este că, pe plan intern, corpul rigid este simulat și apoi se aplică poziția acestuia. Actualizarea pozitiei muta apoi corpul rigid fara a lua in considerare schimbarea vitezei si altele asemenea. Dacă corpul rigid se răsucește în jos pe o pantă, acesta va mișca corpul rigid înapoi, în timp ce codul dvs. de modificare a poziției va deplasa corpul rigid înapoi pe panta.
Să presupunem că dezvolți un joc de golf. Există o problemă cu modul în care mingea de golf nu se oprește de rulare, și cumva reușește să continue să se rostogolească pentru totdeauna, atâta timp cât nu există nici un fel de gaură sau șanț în calea sa. Motivul pentru care se întâmplă acest lucru se datorează faptului că, în viața reală, mingea va fi încetinită de iarba pe care o depășește (printre altele), deoarece trebuie să împingă palele mici de iarbă în jos, iarba în esență este ca o rampă constantă. Aceasta se numește rezistență la rostogolire. Unitatea nu poate simula acest comportament cu exactitate, deci trebuie folosite forțe de oprire artificială.
În Unitate, forța cea mai bună de a folosi pentru a opri un obiect de la rulare pentru totdeauna este "dragul unghiular". Schimbarea tragerii unghiulare pe bilele de golf este modalitatea de a rezolva această problemă. Valoarea exactă depinde într-adevăr de comportamentul pe care îl căutați, totuși este posibil să observați că o valoare de 1,0 unghiular poate să nu fie chiar suficientă în unele cazuri.
Aproape fiecare obiect din lume revine după un impact. Materialul fizic intern, fizic implicit al Unității nu are niciun efect. Semnificația fiecărui obiect nu va dispărea dacă nu suprascrieți materialul fizic implicit sau dacă aplicați un material fizic obiectelor din scenă cu o valoare de bounciness mai mare de 0.
Una dintre cele mai bune căi de rezolvare a acestei probleme este crearea unui material care să creeze propriul material fizic implicit și să îl atribuiți în Manager de fizică găsite făcând clic Editați> Setări proiect> Fizică.
Cele mai multe motoare de fizică au un fel de parametru care dictează cât de multe obiecte pot fi interpenetrate sau intersectate până când sunt împinse una de cealaltă. Acest parametru se numește Penetrarea Min pentru penalizare în unitate. Implicit, această valoare este de 0,01 (metri), ceea ce înseamnă că, în mod prestabilit, obiectele pot fi intersectate până la 1 centimetru (aproape 0,4 inchi) înainte de a fi împinse.
Ar trebui să setați Min penetrarea pentru penalizare la o valoare în care abia se observă că obiectele se intersectează. Stabiliți valoarea la ceva mic, cum ar fi 0,0001
, poate duce la rigidbodies nervozitate.
Dacă nu sunteți un programator, nu trebuie să vă faceți griji în legătură cu următorul scenariu. Când scrieți un cod care mișcă, rotește sau scade rigidbodies, este important să păstrați acest lucru în buclă FixedUpdate. Scrierea acestui cod în Actualizați
buclă va duce la rezultate instabile, deoarece Actualizați
funcția poate fi apelată la 1000 Hz, în timp ce motorul fizicii și FixedUpdate
sunt apelate fiecare la 50 Hz în mod implicit.
Puteți schimba frecvența pe etapele fizicii schimbând parametrul Timestep fixat, gasit in Editați> Setări proiect> Timp. Valoarea determină cât de mult timp este așteptat, în secunde, între fiecare actualizare fizică sau pas. Puteți determina frecvența în Hertz împărțind 1 la valoarea (de exemplu, o așteptare de 0,01 secunde înseamnă 1 / 0,01 = 100 Hz). Cu cât sunt mai dese pașii, cu atât simularea va fi mai precisă și mai stabilă. Cu toate acestea, setarea frecvenței mai mare decât CPU-ul se poate ocupa va duce la o simulare foarte instabilă. Încercați să păstrați frecvența actualizată fixă între 30 Hz și 100 Hz.
În timp ce lucram pe un perete de cărămidă distrubil, am intrat într-o problemă cauzată de cărămizi instante, după ce o bucată de zid a fost distrusă. Am rezolvat această problemă prin plasarea codului problematic într-un Coroutine și plasând următoarea linie înainte de Distrugerea obiectului:
// Așteptați o întoarcere a randamentului cadrului nul; // randamentul C #; // UnityScript
În așteptarea unui cadru, aceasta ar garanta că logica a fost sincronizată în timpul Actualizare, mai degrabă decât timpul FixedUpdate. Aceasta pare să însemne că funcția Destroy este executată în sincronizare cu buclă de actualizare.
Pachetul Materiale Fizice, care vine ca parte a Standardului Unității, este de fapt aproape inutil. Există cinci materiale de fizică conținute în pachet și toate acestea sunt nerealiste într-un fel.
Fiecare material are o frecare statică și dinamică identică. În lumea reală, obiectele care stau în picioare au puțin mai multă frecare atunci când se mișcă. Coeficientul de frecare al materialului cauciucului este 1.0
, care nu este similar cu orice cauciuc găsit în lumea reală. Și dacă nu sună suficient de stupid, fiecare material are 0 "bounciness" (excluzând materialul "Bouncy"). Acest lucru înseamnă că materialele nu reprezintă nici măcar o reprezentare apropiată a omologului lor din viața reală.
Cel mai bine este să vă creați propriile materiale fizice atunci când este necesar. Există o mulțime de site-uri în jurul valorii de aceleași proprietăți fizice ale materialelor - cele mai importante fiind frecare dinamică, frecare statică și restituire sau bounciness.
Foarte puține probleme legate de fizică sunt de fapt greu de rezolvat. Dacă există vreun fel de eroare legată de fizică care pare dificil de urmărit, încearcă încetinirea timpului pentru a vedea ce se întâmplă. Dacă observați că problema începe în jurul unei anumite linii de cod, puteți utiliza Debug.Break pentru a întrerupe editorul și pentru a inspecta ce se întâmplă. Nu ezitați să comentați aici dacă aveți întrebări sau aveți nevoie de ajutor.