Platforma mecanică Platforme mobile

Ce veți crea

În acest tutorial veți învăța cum să creați platforme mobile și asigurați-vă că obiectele care le călăresc vor păstra poziția lor relativă. De asemenea, vom rezolva cazul de a fi zdrobit între o platformă și sol.

Cerințe preliminare

Acest tutorial se bazează pe seria Basic Platformer Physics. În mod specific, vom folosi codul bazat pe a opta parte a tutorialului ca punct de plecare, cu câteva modificări. Consultați seria tutorial, în special ultima parte. Principiile care stau la baza implementării vor sta în vigoare chiar dacă utilizați o soluție fizică diferită, dar codul va fi compatibil cu versiunea prezentată în seria tutorial.

Demo

Puteți descărca demo-ul din atașamentele tutorialului. Folosește WASD pentru a muta caracterul, Spaţiu să creeze un caracter de clonă și P să creeze o platformă în mișcare. Butonul drept al mouse-ului creează o țiglă. Puteți utiliza rotița de defilare sau tastele săgeți pentru a selecta o placă pe care doriți să o plasați. Glisoarele modifică dimensiunea personajului jucătorului.

Demo-ul a fost publicat sub Unitate 2017.2b4, iar codul sursă este, de asemenea, compatibil cu această versiune de Unity.

Punerea în aplicare

Platforme mobile

Mai întâi de toate, să creăm un script pentru o platformă în mișcare.

Inițializarea

Să începem prin crearea clasei obiectului.

clasa publica MovingPlatform: MovingObject 

Acum, să inițializăm câțiva parametri de bază ale obiectului în funcția init.

void public init () mAABB.HalfSize = nou Vector2 (32.0f, 8.0f); mSlopeWallHeight = 0; mMovingSpeed ​​= 100.0f; mIsKinematic = adevărat; mSpeed.x = mMovingSpeed; 

Am stabilit mărimea și viteza, iar noi facem cautatorul cinematic, ceea ce înseamnă că nu va fi mutat de obiecte obișnuite. Am setat și mSlopeWallHeight la 0, ceea ce înseamnă că platforma nu va urca pe pante - le va trata întotdeauna ca pereți.

Comportament

Comportamentul pentru această platformă în mișcare va fi doar acesta: începeți mișcarea corectă și ori de câte ori întâlniți un obstacol, schimbați direcția la 90 de grade în sensul acelor de ceasornic.

public void CustomUpdate () dacă (mPS.pushesRightTile &&! mPS.pushesBottomTile) mSpeed.y = -mMovingSpeed; altfel dacă (mPS.pushesBottomTile &&! mPS.pushesLeftTile) mSpeed.x = -mMovingSpeed; altfel dacă (mPS.pushesLeftTile &&! mPS.pushesTopTile) mSpeed.y = mMovingSpeed; altfel dacă (mPS.pushesTopTile &&! mPS.pushesRightTile) mSpeed.x = mMovingSpeed; UpdatePhysics (); 

Iată modelul vizualizat:

Lipirea caracterului pe platformă

Chiar acum, dacă un personaj se află pe o platformă, platforma va aluneca pur și simplu de sub ea, ca și cum nu ar exista o frecare între obiecte. Vom încerca să remediem asta, prin copierea offsetului platformei.

Determinați obiectul principal

În primul rând, vrem să fim conștienți de ce obiect, dacă există, este caracterul nostru permanent. Să declare o referință la acest obiect în MovingObject clasă.

public MovingObject mMountParent = null;

Acum, în UpdatePhysicsResponse, dacă detectăm că ne confruntăm cu un obiect de sub noi, putem să atribuim această referință. Să creați o funcție care va aloca mai întâi referința.

public void TryAutoMount (platforma MovingObject) if (mMountParent == null) mMountParent = platformă; 

Acum, să o folosim în locurile potrivite, adică oriunde spunem că obiectul nostru se ciocnește cu un alt obiect de dedesubt.

altfel dacă (overlap.y == 0.0f) if (other.mAABB.Center.y> mAABB.Center.y) mPS.pushesTopObject = true; mSpeed.y = Mathf.Min (mSpeed.y, 0.0f);  altceva TryAutoMount (altul); mPS.pushesBottomObject = adevărat; mSpeed.y = Mathf.Max (mSpeed.y, 0.0f);  continua; 

Primul loc este atunci când verificăm dacă obiectele se ating.

dacă (suprapun < 0.0f)  mPS.pushesTopObject = true; mSpeed.y = Mathf.Min(mSpeed.y, 0.0f);  else  TryAutoMount(other); mPS.pushesBottomObject = true; mSpeed.y = Mathf.Max(mSpeed.y, 0.0f); 

Al doilea loc este când se suprapun.

Acum că avem acest lucru acoperit, să ne ocupăm de mișcarea obiectului nostru. Să modificăm UpdatePhysics din tutorialul anterior.

Să declarăm o variabilă de clasă pentru offsetul de care trebuie să ne mutăm caracterul.

public Vector2 mOffset;

Acum să înlocuim vechea compensare locală cu clasa unu.

mOffset = mSpeed ​​* Time.deltaTime;

În cazul în care obiectul este pe o platformă, să adăugăm mișcarea platformei la offset.

mOffset = mSpeed ​​* Time.deltaTime; dacă (mMountParent! = null) if (HasCollisionDataFor (mMountParent)) mOffset + = mMountParent.mPozitiv - mMountParent.mOldPosition; altul mMountParent = null; 

Rețineți că verificăm și aici dacă încă suntem în legătură cu obiectul. Dacă nu este cazul, atunci setăm mMountParent la nul, pentru a marca că acest obiect nu mai călări pe nimeni altul.

Apoi, hai să mutăm poziția obiectului nostru prin această compensare. Nu o să ne folosim Mișcare funcția, dar schimba pur și simplu poziția. Deci, în verificarea de coliziune între obiecte, care are loc imediat după UpdatePhysics, vom obține rezultatul pentru pozițiile din acest cadru în locul celei anterioare.

mOffset = mSpeed ​​* Time.deltaTime; dacă (mMountParent! = null) if (HasCollisionDataFor (mMountParent)) mOffset + = mMountParent.mPozitiv - mMountParent.mOldPosition; altul mMountParent = null;  mPoziția + = RoundVector (mOffset + mReminder); mAABB.Center = mPoziție;

Acum hai să ne mutăm la UpdatePhysicsP2, care se numește după ce au fost rezolvate coliziunile dintre obiecte. Aici ne anulam mișcarea anterioară, care nu a fost verificată dacă este valabilă sau nu.

public void UpdatePhysicsP2 () mPoziția = = RoundVector (mOffset + mReminder); mAABB.Center = mPoziție;

Apoi continuăm UpdatePhysicsResponse pentru a aplica o mișcare de suprapunere cu alte obiecte. Aici, anterior am modificat poziția direct, dar acum, să modificăm mOffset, astfel încât această schimbare de poziție se rezolvă mai târziu atunci când ne folosim Mișcare funcţie.

dacă (cel mai micOverlap == Mathf.Abs (overlap.x)) float offsetX = overlap.x * speedRatioX; mOffset.x + = offsetX; offsetSum.x + = offsetX; dacă (overlap.x < 0.0f)  mPS.pushesRightObject = true; mSpeed.x = Mathf.Min(mSpeed.x, 0.0f);  else  mPS.pushesLeftObject = true; mSpeed.x = Mathf.Max(mSpeed.x, 0.0f);   else  float offsetY = overlap.y * speedRatioY; mOffset.y += offsetY; offsetSum.y += offsetY; if (overlap.y < 0.0f)  mPS.pushesTopObject = true; mSpeed.y = Mathf.Min(mSpeed.y, 0.0f);  else  TryAutoMount(other); mPS.pushesBottomObject = true; mSpeed.y = Mathf.Max(mSpeed.y, 0.0f);  

Acum ne putem întoarce la UpdatePhysicsP2, unde pur și simplu sunăm UpdatePhysicsResponse și Mișcare funcționează așa cum am făcut mai devreme, pentru a obține starea corectă a poziției.

mPoziția - = RoundVector (mOffset + mReminder); mAABB.Center = mPoziție; UpdatePhysicsResponse (); dacă (mOffset! = Vector2.zero) mișcați (mOffset, mSpeed, ref mPozi, ref mReminder, mAABB, ref mPS);

Corectați Ordinul de actualizare

Din cauza modului în care ordonăm actualizările fizicii, dacă obiectul copil este actualizat înaintea părintelui, copilul va pierde în mod constant contactul cu platforma atunci când călătorește în sus / în jos.

Pentru a rezolva acest lucru, ori de câte ori setăm mMountParent, dacă platforma se află în spatele copilului în coada de actualizare, vom schimba cele două, astfel încât obiectul mamă se actualizează întotdeauna mai întâi. Să facem această modificare în TryAutoMount funcţie.

public void TryAutoMount (platforma MovingObject) if (mMountParent == null) mMountParent = platformă; dacă (platform.mUpdateId> mUpdateId) mGame.SwapUpdateIds (această platformă); 

După cum puteți vedea, dacă id-ul de actualizare al obiectului platformei este mai mare decât copilul, comanda de actualizare a obiectelor este înlocuită, eliminând problema.

Asta e destul de mult atunci când vine vorba de lipirea personajului pe platforma în mișcare.

Detectați fiind zdrobit

Detectarea distrugerii este destul de simplă. În UpdatePhysicsResponse, trebuie să vedem dacă suprapunerea împotriva unui obiect cinematic ne mută într-un zid. 

Să ne ocupăm mai întâi de axa X:

dacă (cel mai micOverlap == Mathf.Abs (overlap.x)) float offsetX = overlap.x * speedRatioX; mOffset.x + = offsetX; offsetSum.x + = offsetX; dacă (overlap.x < 0.0f)  mPS.pushesRightObject = true; mSpeed.x = Mathf.Min(mSpeed.x, 0.0f);  else  mPS.pushesLeftObject = true; mSpeed.x = Mathf.Max(mSpeed.x, 0.0f);  

Dacă obiectul este în partea dreaptă și deja împingem un perete stâng, atunci să sunăm a Zdrobi funcție, pe care o vom implementa mai târziu. Faceți același lucru și pentru cealaltă parte.

dacă (overlap.x < 0.0f)  if (other.mIsKinematic && mPS.pushesLeftTile) Crush(); mPS.pushesRightObject = true; mSpeed.x = Mathf.Min(mSpeed.x, 0.0f);  else  if (other.mIsKinematic && mPS.pushesRightTile) Crush(); mPS.pushesLeftObject = true; mSpeed.x = Mathf.Max(mSpeed.x, 0.0f); 

Să repetăm ​​asta pentru axa Y.

dacă (suprapun < 0.0f)  if (other.mIsKinematic && mPS.pushesBottomTile) Crush(); mPS.pushesTopObject = true; mSpeed.y = Mathf.Min(mSpeed.y, 0.0f);  else  if (other.mIsKinematic && mPS.pushesTopTile) Crush(); TryAutoMount(other); mPS.pushesBottomObject = true; mSpeed.y = Mathf.Max(mSpeed.y, 0.0f); 

Zdrobi funcția va muta pur și simplu personajul în centrul hărții pentru demo.

public void Crush () mPoziție = mMap.mPoziție + Vector3 nou (mMap.mWidth / 2 * Map.cTileSize, mMap.mHeight / 2 * Map.cTileSize); 

Rezultatul este caracterul teleportat atunci când este zdrobit de o platformă.

rezumat

Acesta a fost un tutorial scurt deoarece adăugarea de platforme în mișcare nu reprezintă o mare provocare, mai ales dacă știți bine sistemul fizic. Împrumutând de la tot codul din seria tutorialului de fizică, a fost de fapt un proces foarte neted. 

Acest tutorial a fost solicitat de câteva ori, așa că sper că vă este util! Vă mulțumim pentru lectură și vă vom vedea data viitoare!