Swinging Physics pentru mișcarea jucătorilor (după cum se vede în Spider-Man 2 și Energy Hook)

Bună! Eu sunt Jamie Fristrom de la Happion Laboratories. Poți să-mi amintești de jocuri precum Die By the Sword, Spider-Man 2 și Schizoid ... toate acestea, într-o formă sau alta, au inclus și coarda. Am lucrat în ultimul timp la un joc numit Energy Hook - lansat recent pe Kickstarter - care este vorba despre coarda. (Ei bine, totul este despre gravitonul tău cu graifer, oricum.)


Voi discuta despre modul în care îmi place să pun în aplicare un mecanic de gameplay în roluri. Când am început să lucrez la Energy Hook, am făcut totul cu codul meu personalizat. Cred că este posibil să mergem pur și simplu în Unitate și să folosim Joint Joint pentru a face niște lucruri foarte asemănătoare, dar la acel moment nu era disponibil. Sunt destul de sigur că asta a fost chemarea corectă, oricum, pentru că îmi dă controlul asupra tuturor lucrurilor - și o pot împărtăși cu dvs..


Fundamentele de a face leagăn așa cum am făcut - folosind constrângeri - sunt de fapt destul de simple. (Sper că nu sunteți dezamăgit atunci când vedeți ce este sub capota.) Funcționează la fel dacă faceți un joc 2D sau joc 3D, este doar că vectorii sunt diferiți, așa că voi începe cu 2D și apoi discutați câteva riduri atunci când ajungeți la trei dimensiuni.

Acest articol presupune, de asemenea, că folosiți un motor de joc cum ar fi Unity care poate face o mulțime de lucru pentru dvs., cum ar fi raycasting împotriva geometriei și orientarea unui personaj, cu apeluri simple de funcții. Dacă utilizați propria dvs. motor, va trebui să faceți acest lucru matematic.



Simulări fizice față de mișcarea conservată

Există două moduri în care simulările jocului funcționează adesea. Cele mai multe jocuri de terțe persoane au conserve totul; animații conservate și mișcări conservate, astfel încât totul să arate perfect, picioarele personajului nu alunecă, direct de la programul animator al animatorului la noi. Alternativa este o simulare fizică mult mai simplă - simulezi fizica: accelerație, viteză, gravitate - multe jocuri de prima persoană fac acest lucru, dar jocurile de la a treia persoană tind să o evite, pentru că este mult mai ușor să ai picioarele personajului slide și materialele fizice care nu se potrivesc cu animația.

Dacă vrei să faci o lovitură de coardă necondiționată (spre deosebire de un leagăn cu coardă conservat, așa cum se vede în prima Piatră de Piatră sau jocurile Spider-Man devreme, cum ar fi Neversoft's pe PSX), o lovitură de coardă, care este de fapt un fizic simulare și poate, prin urmare, poate avea libertate și nuanță și senzația viscerală că gravitatea și impulsul real vă pot da, atunci veți dori să o faceți a doua cale - să aveți totul o simulare fizică și să evitați să faceți lucruri conservate care ucid ritmul personajului. Apoi, totul va curge.

Așa fac eu cu Energy Hook.


Există o mulțime de articole despre cum să simulezi fizica - aici este una cu un demo flash Flash construit înăuntru. Poți să faci integrarea Euler sau integrarea Verlet, nu contează. (Nu te voi învăța eu despre Euler vs. Verlet aici, dar permiteți-mi să spun că conceptele nu sunt la fel de înfricoșătoare ca ele.)

Să presupunem că facem o integrare olară simplă a lui Euler. Caracterul jocului personajului nostru ar putea arăta astfel, unde accelerația este determinată de gravitate și cum împingeți pe stick:

 avatar.velocity = avatar.velocity + avatar.acceleration * deltaT; avatar.position = avatar.position + avatar.velocity * deltaT;

(Notă laterală: aceasta este de fapt o aproximare dificilă - puteți obține o aproximare mai bună, mai puțin framerată-dependentă avatar.position = avatar.position + (avatar.oldvelocity + avatar.velocity) * deltaT / 2.0f, și puteți obține o simulare aproape perfectă cu ceva de genul acesta - dar jucătorii dvs. probabil că nu vor observa.)

postări asemănatoare
  • Simulați cârpele și rulourile care se împovărează cu o integrare simplă a Verlet
  • Cum se creează un motor de fizică 2D personalizat

Constrânge-o

Jocul dvs. are probabil un sistem de coliziune cu geometria lumii. Probabil arată astfel:

 Vector testPosition = avatar.position + avatar.velocity * deltaT; Intersecția vectorului dacă (RayCast (poziția, testPosition, intersecția)) // am trecut printr-un perete, să tragem caracterul înapoi, // folosind normalul peretelui // cu un spațiu de 1 unitate pentru camera de respirație testPosition = intersecție + intersecție. normală; 

Ce se întâmplă cu viteza avatarului tău când a lovit un obstacol? Nu are sens ca avatarul tău să mențină aceeași viteză prin perete. Unele jocuri te-ar putea sări, folosind normalul de unde te-ai intersectat pentru a reflecta viteza ta; alte jocuri ar putea să vă lase să alunecați de-a lungul peretelui; altele vor fi undeva între ele. Să ne uităm la codul de alunecare de-a lungul unui perete:

 avatar.velocity = (testPosition - avatar.position) / deltaT; avatar.position = testPosition;

(Dacă faci integrare Verlet, în cazul în care fiecare cadru deja determină viteza prin vizualizarea datelor de poziție anterioare, acest pas este deja făcut pentru dvs.)

De asemenea, dacă jocurile video sunt lucrurile greoaie, probabil veți găsi adesea că poziția personajului dvs. se blochează brusc de la un cadru la altul în anumite cazuri de colț. Când se întâmplă acest lucru, viteza lor va trece prin acoperiș. Soluția mea pentru asta este pur și simplu o hack: verificați dacă viteza lor devine prea mare și reparați-o dacă se întâmplă.

Ce face acest cod când atingi un zid dintr-un unghi? Primul cadru, vă schimbă dramatic viteza în timp ce loviți peretele, dar încă vă împinge prin perete. Următorul cadru, avatarul tău devine din nou actualizat în perete și apoi împins din nou, dar acum viteza este noua poziție a avionului, alunecată de-a lungul peretelui, minus poziția sa veche, de perete, deci este paralelă cu peretele.

Aceasta este o supradimensionare imensă a ceea ce se întâmplă în lumea reală atunci când un obiect se ciocnește cu altul, dar majoritatea jucătorilor dvs. nu vor observa sau îi vor îngriji.

În acest moment, totuși, am limitat cu succes poziția și viteza avatarului nostru cu pereții și etajele jocului nostru. Deci, acum suntem gata.

Constrângerea cu Tethers în loc de Pereți

Deci, acum imaginați-vă că avatarul dvs. este deja atașat de un coardă virtuală la un punct virtual. În ceea ce ne privește, putem pur și simplu să considerăm un zid circular sau invers. Putem testa coliziunea prin a vedea dacă ați ajuns prea departe de centrul cercului și trageți înapoi avatarul.

 dacă (amITethered) if (testPosition - tetherPoint) .Length ()> tetherLength) // am trecut de sfârșitul coardei noastre // trageți avatarul înapoi testPosition = (testPosition - tetherPoint) .Normalized () tetherLength; 

Acum, aceeași ajustare a vitezei care ne-a făcut să alunecăm de-a lungul pereților ne va face să alunecăm de-a lungul interiorului acestui cerc sau sferă virtuală.


Swinging Physics: Falling with a Tether - Cadru 1
Swinging Physics: Falling cu un Tether - Cadrul 2
Swinging Physics: Falling cu un Tether - Cadrul 3

Unele subtilitate și nuanță

În acest moment, aveți un joc swinging. Dar probabil că va fi vorba de câteva lucruri despre asta, care îi fac pe jucătorii tăi să se distreze și asta este în cazul în care un pic de hacking poate face lucrurile mai bine.

Slack, Springiness

În funcție de jocul dvs. și dacă se presupune că se simulează o lungime de frânghie sau o țesătură elastică sau un fascicul de grapple, este posibil să aveți abordări diferite în ceea ce privește greutatea și elasticitatea. Puteți simula o mulțime de lucruri prin tweaking tetherLength. Dacă doriți să vă retrageți din panza elastică sau fasciculul graifer, puteți scurta tetherLength deoarece jucătorul se apropie de punctul de legătură:

 tetherLength = (avatar.position - tetherPoint); lungime ();

Dar dacă eo coardă neelastică, ai lăsa-o tetherLength neatins.

Pentru izvoare, puteți avea a desiredLength că este fix și a currentLength care încearcă continuu să se apropie desiredLength - acest lucru va fi, de asemenea, util pentru următorul nostru pas:

Dar nu vreau să lovesc terenul!

Ce se întâmplă dacă avatarul dvs. începe într-un loc scăzut și încearcă să leagă? E destul de evident că nu vor ajunge prea departe. O reparație rapidă pentru acest lucru este de a verifica cât de înalte deasupra solului punctul pe care doresc să leagă de este, și scurta lungimea de legare lor, astfel încât acestea vor curata solul.

Nu poți să-l scurtezi deasupra unui singur cadru, pentru că atunci vor cădea brusc în aer - deci aici, având un a desiredLength este suficient de scurt pentru a nu atinge solul și a currentLength care se apropie rapid desiredLength vă va oferi clearance-ul dorit.

Avatarul este sus

În cazul în care avatarul dvs. este o figură umană, nu prea are sens să apară în mod constant pe verticală pe măsură ce acestea se învârt. Orientându-le astfel încât să pară că sunt agățate de funie - așa că sunt cu capul în jos dacă fac o buclă, de exemplu - ar putea arăta astfel în Unitate:

 Vector myUp = (avatar.position - tetherPoint); avatar.rotation = Quaternion.LookRotation (avatar.ro.ro.forward, myUp);

Acest lucru va lăsa avatul să se învârtă înapoi. De asemenea, ați putea folosi viteza avatarei pentru a le transmite (asta este ceea ce fac) - sau lăsați-i să se rotească nebun ...

Înfășurarea în jurul lucrurilor

În lumea reală, funiile se înfășoară în jurul lucrurilor. O modalitate rapidă de a simula faptul că în codul dvs. este de a raspândi de-a lungul coardei virtuale în fiecare cadru și dacă atinge ceva, faceți un nou punct de atașament în care se intersectează. Acest lucru nu va părea corect dacă avatul se leagă înapoi pe o frânghie nonsticulară, dar este bine pentru o bandă lipicioasă, o limbă sau un fascicul de grapple.

Ajustați modul în care coarda vă poate avea un impact mare asupra distracției. Dintr-o dată, înfășurarea în jurul unei ieșiri poate duce jucătorul prin surprindere și îi face frustrați. Am avut o soluție în trei pași în Spider-Man 2: dacă erați prea apropiați de extracție, web-ul s-ar rupe; dacă ați fi într-o distanță de mijloc, webul ar înfășura; și dacă ai fi fost departe, internetul trebuia să treacă.


Considerații pentru 3D

Cel mai greu lucru pentru a aduce acest mecanism 2D la 3D ia în considerare interfața pentru jucător - cum își aleg punctele din lume pentru a leșina. Jocurile diferite folosesc metode diferite pentru alegerea unui astfel de punct. Ratchet & Clank are puncte fixe în lume pe care le puteți lupta; cu modul de coborâre Quake și Bionic Commando: Rearmed, îndreptați camera spre ceea ce doriți să atașați; Spider-Man 2 și Energy Hook se expun în raport cu caracterul și unde razele se intersectează cu geometria fizică, adică punctul în care atașați.


Aproape toate aceste metode implică difuzarea de raze în fața geometriei fizice a lumii, indiferent dacă este de-a lungul liniei camerei sau de la caracter la punctul de clic al mouse-ului - intersecția radicast determină noul dvs. punct.

De exemplu, iată un raster cu aspect de mouse care ar putea fi bun pentru un joc de prima persoană:

 RaycastHit wallData; dacă (Physics.Raycast (camera.position, camera.forward, outDataData, maximumTetherLength)) amITethered = true; tetherPoint = wallData.point; tetherLength = Vector3.Distanță (pereteDatum, avatar.position); 

Bumping Into Stuff

Bumping în pereți și similare, de asemenea, tinde să se întâmple mult mai des într-un joc 3D decât un joc 2D, mai ales atunci când sunt pereții cu care vă faceți legătura. Există o varietate de lucruri pe care le puteți face pentru a face acest lucru mai puțin enervant.

  • Lăsați jucătorul să se îndrepte în aer: fizica nu are multe de spus despre asta, dar se simte cumva cum trebuie. Acesta este unul din lucrurile pe care le-am făcut în Spider-Man 2 și de ce ați primit un jetpack în Energy Hook.
  • Redați o animație se răcească: trebuie ca avatarul să facă un fel de flip sau spin atunci când lovește un perete și apoi se simte mai puțin ca o greșeală și mai mult ca "M-am gândit să fac asta!"
  • Păstrează-le de pe perete: Ultimul Spider-Man a făcut asta - dacă te-ai apropiat prea mult de un perete, te-ar împinge ușor de la el. Arăta puțin ciudat dacă ați lăsat bastonul și doar lăsați avatarul dvs. să stea acolo - ar pluti departe de zid într-un unghi ciudat - dar pentru restul jocului a fost o îmbunătățire. (Ați putea avea cele mai bune rezultate din ambele lumi, împingându-vă numai dacă personajul merge cu o anumită viteză?)
  • Răsplătește-le pentru că nu lovesc peretele, în primul rând: aceasta este strategia Energy Hook - învățați jucătorul pentru a evita lovirea zidurilor, recompensându-le pentru leagăni curate. Pe de o parte, îi încurajează să lege destul; pe de alta parte, atunci cand se lovesc de perete este mult mai frustrant, pentru ca isi pierd punctele de stil.


Deci ce mai aștepți?

Duceți-vă afară și faceți propriile dvs. jocuri swinging, și spuneți-mi ce veniți! Nu pot obține destul de multe jocuri swinging.

Sper că ați găsit acest articol util. Dacă aveți, vă rugăm să sprijiniți Energy Hook Kickstarter sau să o voteze pe Steam Greenlight. Mulțumiri!