În sfaturile rapide anterioare, ne-am uitat la coliziune detectare: în esență, detectarea faptului că două forme s-au suprapus. Acum, suntem gata să privim la coliziune reacţie: a face ceva să se întâmple din cauza unei coliziuni. În acest sfat rapid, vom analiza reacțiile de reflecție și alunecare.
Să ne uităm la rezultatul final pe care îl vom realiza la sfârșitul acestui tutorial. Fiecare demo Flash are un buton de repornire; faceți clic pe acesta pentru a reseta poziția cercurilor din partea de sus a etapei.
Primul demo arată reflecţie:
Al doilea spectacol alunecare:
Am parcurs prin acest subiect mai multe runde cu studenții, iar experiența mi-a învățat că abordarea cap-on de a explica matematica vectorială la frezare are ca rezultat chipuri goale și minți confuze. Așadar, în loc să prezentăm aici o prelegere de matematică, voi îndruma pe cei care sunt interesați să investigheze acest subiect în continuare la pagina de reflecție a lui Wolfram.
Aici, îmi voi simplifica explicațiile prin diagramele de mai jos. Recall adactor vector:
Acum, respectați diagrama de mai jos. A este viteza cercului înainte de o coliziune, iar A 'este viteza sa după coliziune.
E evident că asta A '= A + 2 V (Ap)
, Unde V (Ap)
reprezintă vectorul cu o magnitudine de Ap, în direcția stânga normală. (Puteți vedea acest lucru urmând liniile întrerupte.)
Pentru a obtine V (Ap)
, vom proiecta A pe stânga normală.
Aici vine implementarea ActionScript a reflecției. Am subliniat părțile importante. Linia 67 - 69 este de a calcula V (Ap
) (v_leftNormSeg2
) și linia 70 implementează formula. Aveți dreptul să consultați versiunea completa a ActionScript sub Reaction1.as.
(Trebuie să recunoașteți majoritatea codului din Sfatul rapid anterior.)
actualizarea funcției private (e: Event): void pentru (var i: int = 0; i < circles.length; i++) //calculating line's perpendicular distance to ball var c1_circle:Vector2D = new Vector2D(circles[i].x - x1, circles[i].y - y1); var c1_circle_onNormal:Number = c1_circle.projectionOn(leftNormal); var c1_circle_onLine:Number = c1_circle.projectionOn(line); //if collision happened, undo movement if (Math.abs(c1_circle_onNormal) <= circles[i].radius && line.dotProduct(c1_circle) > 0 && c1_circle_onLine < line.getMagnitude()) //redefine velocity var v_leftNormSeg2:Vector2D = leftNormal.clone(); var leftNormSeg2_mag:Number = Math.abs(velos[i].projectionOn(leftNormal)) v_leftNormSeg2.setMagnitude(leftNormSeg2_mag); velos[i] = velos[i].add(v_leftNormSeg2.multiply(2)); circles[i].x += velos[i].x; circles[i].y += velos[i].y;
Luați act de faptul că această formulă de reflecție este aplicabilă liniei de orice gradient. De fapt, puteți programa linia dvs. să fie reglabilă în timpul rulării și să o vedeți reflectând cercuri precum prezentarea Flash de mai jos. Doar faceți clic și trageți în apropierea capătului inferior al acesteia pentru al redefini.
Conceptul de alunecare de-a lungul liniei este aproape identic cu reflecția. Respectați diagrama de mai jos.
Vectorul diapozitivului este A '= A + V (Ap)
cu V (Ap)
reprezentând un vector cu magnitudine de Ap
. Din nou, pentru a obține Ap vom proiecta A pe stânga normală.
Rețineți că, pe măsură ce cercul alunecă de-a lungul liniei, se ciocnește cu linia. Desigur, punctele de coliziune diferă între cercurile care se ciocnesc pe linie, astfel încât unele se suprapun linia în timp ce se deplasează de-a lungul ei. Nu arată bine, așa că trebuie să le repoziționăm.
Acum, să repoziționăm cercuri pe linie, menținând în același timp contactul cu linia. Consultați diagrama de mai jos.
O variabilă importantă pentru a calcula este proiecția lui A de-a lungul liniei. Raza de cerc este disponibilă imediat și avem deja B, astfel încât putem forma vectorii lui B și C. Adăugarea celor doi ne va da A, locația exactă pentru a repoziționa cercul. Simplu!
Prezentarea Flash de mai jos este codată în conformitate cu ideea menționată. Dar există o problemă: cercurile se mișcă de-a lungul liniei.
Există un ultim detaliu pe care l-am pierdut. Diagrama de mai sus arată că magnitudinea lui C ar trebui să fie echivalentă cu raza cercului. Cu toate acestea, aceasta va pozitiona cercul inapoi deasupra liniei. Deoarece nu există o coliziune detectată acolo, cercul va cădea din nou pe linie, care, la rândul său, va semnaliza detectarea coliziunii și va provoca repoziționarea cercului.
Acest ciclu se va repeta până când va trece de sfârșitul segmentului de linie; rezultatul vizual al acestui ciclu este efectul de jitter.
Soluția la această problemă este de a stabili magnitudinea lui C la puțin mai mică decât raza cercului: (raza cercului - 1)
, Spune. Observați demo-ul Flash de mai jos, care folosește această idee:
Deci, aici este fragmentul important ActionScript pentru alunecarea de-a lungul liniei. Am subliniat părțile importante.
actualizarea funcției private (e: Event): void pentru (var i: int = 0; i < circles.length; i++) //calculating line's perpendicular distance to ball var c1_circle:Vector2D = new Vector2D(circles[i].x - x1, circles[i].y - y1); var c1_circle_onNormal:Number = c1_circle.projectionOn(leftNormal); var c1_circle_onLine:Number = c1_circle.projectionOn(line); //check for collision if (Math.abs(c1_circle_onNormal) <= circles[i].radius) //check if within segment //if within segment, reposition and recalculate velocity if (line.dotProduct(c1_circle) > 0 && c1_circle_onLine < line.getMagnitude()) //repostion circle var v_lineSeg:Vector2D = line.clone(); v_lineSeg.setMagnitude(c1_circle_onLine); var v_leftNormSeg1:Vector2D = leftNormal.clone(); v_leftNormSeg1.setMagnitude(circles[i].radius - 1); //v_leftNormSeg1.setMagnitude(circles[i].radius); //uncomment this to check out the error: jittering effect var reposition:Vector2D = v_lineSeg.add(v_leftNormSeg1) circles[i].x = x1+reposition.x; circles[i].y = y1+reposition.y; //redefine velocity var v_leftNormSeg2:Vector2D = leftNormal.clone(); var leftNormSeg2_mag:Number = Math.abs(velos[i].projectionOn(leftNormal)) v_leftNormSeg2.setMagnitude(leftNormSeg2_mag); var veloAlongLine:Vector2D = velos[i].add(v_leftNormSeg2); circles[i].x += veloAlongLine.x; circles[i].y += veloAlongLine.y; //if not in segment (e.g. slide out of segment), continue to fall down else circles[i].x += velos[i].x; circles[i].y += velos[i].y; //No collision in the first place, fall down else circles[i].x += velos[i].x; circles[i].y += velos[i].y;
Sper că acest lucru este de ajutor. Vă mulțumim pentru lectură. Promiți-mi dacă există întrebări și vă voi vedea următorul Tip rapid.