Snelle tip botsingsreactie tussen een cirkel en een lijnsegment

In de vorige Snelle tips hebben we gekeken naar botsingen opsporing: in essentie, het detecteren dat twee vormen elkaar overlappen. Nu zijn we klaar om te kijken naar een botsing reactie: iets laten gebeuren door een botsing. In deze snelle tip kijken we naar de reacties van reflectie en glijden.


Eindresultaat voorbeeld

Laten we kijken naar het eindresultaat dat we aan het einde van deze tutorial zullen bereiken. Elke Flash-demo heeft een herstartknop; klik erop om de positie van de cirkels bovenaan het werkvlak opnieuw in te stellen.

De eerste demo pronkt reflectie:

De tweede shows glijdend:


Stap 1: De reflectieformule

Ik heb dit onderwerp verschillende rondes doorlopen met studenten, en de ervaring heeft me geleerd dat de directe benadering van het uitleggen van vector-wiskunde aan freshers resulteert in lege gezichten en verwarde gedachten. Dus in plaats van hier een Math-lezing te geven, zal ik degenen die geïnteresseerd zijn in het onderzoeken van dit onderwerp verder verwijzen naar Wolfram's pagina over reflectie.

Hier zal ik mijn uitleg vereenvoudigen met onderstaande diagrammen. Recall vector toevoeging:

Neem nu het onderstaande schema in acht. A is de snelheid van de cirkel vóór een botsing, en A 'is de snelheid na de botsing.

Het is duidelijk dat A '= A + 2 V (Ap), waar V (Ap) staat voor de vector met een magnitude van Ap, in de richting van de linker normaal. (U kunt dit zien door de stippellijnen te volgen.)

Om te verkrijgen V (Ap), we zullen A naar links projecteren.


Stap 2: Implementatie

Hier komt de ActionScript-implementatie van reflectie. Ik heb de belangrijke delen gemarkeerd. Regel 67 - 69 is om te berekenen V (Ap) (v_leftNormSeg2) en regel 70 implementeert de formule. U kunt verwijzen naar het volledige Actionscript onder Reaction1.as.

(Je zou de meeste code van de vorige Quick Tip moeten herkennen.)

 persoonlijke functie vernieuwen (e: Event): void for (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;  

Stap 3: een interactieve versie

Houd er rekening mee dat deze reflectieformule van toepassing is op de regel van een verloop. In feite kunt u uw lijn zodanig programmeren dat deze tijdens runtime kan worden aangepast en dat deze cirkels weerspiegelt zoals de Flash-presentatie hieronder. Klik en sleep gewoon aan het onderste uiteinde van de om het opnieuw te definiëren.


Stap 4: glijden langs de lijn

Het concept van glijden langs de lijn is bijna identiek aan reflectie. Bekijk het diagram hieronder.

De vector van dia is A '= A + V (Ap) met V (Ap) die een vector vertegenwoordigt met een magnitude van EENp. Nogmaals, om A te verkrijgenp we zullen A naar links projecteren.

Merk op dat terwijl de cirkel langs de lijn schuift, deze tegen de lijn botst. Uiteraard verschillen botsingspunten tussen cirkels die op lijn botsen, dus sommige overlappen de lijn terwijl ze langs de lijn bewegen. Dit ziet er niet goed uit, dus we moeten ze herpositioneren.


Stap 5: herdefinieer locatie

Laten we nu cirkels op de lijn verplaatsen en hun contact met de lijn behouden. Raadpleeg het onderstaande schema.

Een belangrijke te berekenen variabele is de projectie van A langs de lijn. De straal van de cirkel is direct beschikbaar en we hebben al B, dus we kunnen de vectoren van B en C vormen. Door de twee toe te voegen, krijgen we A, de exacte locatie om de cirkel te verplaatsen. Eenvoudig!

De onderstaande Flash-presentatie is gecodeerd volgens het genoemde idee. Maar er is één probleem: de cirkels gieren langs de lijn.

Er is nog een laatste detail dat we hebben gemist. Diagram hierboven laat zien dat de grootte van C gelijk moet zijn aan de straal van de cirkel. Dit plaatst de cirkel echter weer boven de lijn. Aangezien er daar geen botsing wordt gedetecteerd, valt de cirkel weer op de lijn, wat op zijn beurt de botsingsdetectie markeert en de cirkel opnieuw positioneert.

Deze cyclus herhaalt zich tot het einde van het lijnsegment voorbij is; het visuele resultaat van deze cyclus is het jittereffect.

De oplossing voor dit probleem is om de grootte van C in te stellen op iets minder dan de straal van de cirkel: (straal van cirkel - 1), zeggen. Bekijk de Flash-demo hieronder die dit idee gebruikt:


Stap 6: Implementatie

Dit is het belangrijke ActionScript-fragment om langs de lijn te schuiven. Ik heb de belangrijke delen gemarkeerd.

 persoonlijke functie vernieuwen (e: Event): void for (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;   

Conclusie

Ik hoop dat dit nuttig is. Bedankt voor het lezen. Vraag me of er vragen zijn en ik zie je de volgende Quick Tip.