In mijn vorige Quick Tip hebben we gekeken naar het idee van botsingsdetectie in het algemeen en specifiek naar het detecteren van botsingen tussen een paar cirkels. In deze Snelle tip bekijken we het detecteren van een botsing tussen een cirkel en een lijn.
Dit is het resultaat waar we aan zullen werken. Klik op de knop Opnieuw opstarten om alle cirkels boven in het werkgebied te verplaatsen en ze te zien vallen.
Merk op dat de cirkels tegen de lijn botsen, zelfs buiten het segment dat wordt getekend. Mijn volgende Quick Tip laat zien hoe dit te verhelpen.
Om te controleren of een cirkel is gebotst met een lijn, moeten we de loodrechte lengte van de lijn naar de cirkel. Bekijk het diagram hieronder.
Uit het bovenstaande diagram blijkt dat de gevallen 3 en 4 een botsing tussen de cirkel en de lijn moeten detecteren. Dus we concluderen dat als de loodrechte lengte (rood gemarkeerd) gelijk is aan of kleiner is dan de straal van de cirkel, er een botsing plaatsvond doordat de cirkel de lijn raakte of overlapt. De vraag is, hoe berekenen we deze loodrechte lengte? Welnu, Vectors kan ons probleem helpen vereenvoudigen.
Om een lijn op het podium te tekenen, hebben we twee coördinaten nodig (c1 en c2). De lijn van c1 tot c2 vormt een vector die naar c2 wijst (let op de richting van de pijl).
Vervolgens moeten we de regels vinden normaal. De normale lijn van de lijn is een andere lijn die 90 ° maakt met de oorspronkelijke lijn en deze op een bepaald punt snijdt. Ondanks dat de lijn normaal is en nog een andere regel is, kan de vectorvorm van de normaal verder worden geïdentificeerd als de links of rechts normaal ten opzichte van de lijnvector. De linker normaal is de lijnvector zelf, geroteerd -90 °. De juiste normaal is hetzelfde, maar 90 ° gedraaid. Onthoud dat de y-as in de coördineerruimte van Flash is omgekeerd in vergelijking met de y-as in een typische grafiek - dus positieve rotatie is met de klok mee en negatieve rotatie is tegen de klok in.
De linker normaal wordt gebruikt in onze poging om de loodrechte lengte tussen de cirkel en de lijn te berekenen. Details zijn te vinden in het onderstaande schema. EEN verwijst naar een vector die wijst van c1 naar de cirkel. De loodrechte lengte verwijst eigenlijk naar vector A's projectie aan de linkerkant normaal. We leiden deze projectie af met behulp van trigonometrie: dat is het | A | Cosine (theta)
, waar | A |
verwijst naar de grootte van de vector EEN.
De eenvoudigste benadering is om gebruik te maken van vectorbewerkingen, met name het puntproduct. Uitgaande van de vergelijking van het puntproduct, herschikken we de termen zodat we bij de tweede uitdrukking komen die hieronder wordt getoond. Merk op dat de rechterkant van de tweede vergelijking de projectie is die we wilden berekenen!
Merk ook op dat de linker- en rechterkant van de vergelijking uiteindelijk hetzelfde resultaat zullen opleveren, hoewel ze anders zijn in hun benadering. Dus in plaats van de rechterkant van de vergelijking te gebruiken, kunnen we kiezen voor de linkerkant van de vergelijking. Om gemakkelijk aan het eindresultaat te komen, is het gunstig om links te gebruiken omdat variabelen eenvoudig kunnen worden opgelost. Als we erop staan het recht van vergelijking te gebruiken, zouden we ActionScript door rigoureus wiskundig werk moeten duwen bij het berekenen van de hoektheta. We besluiten met het onderstaande schema.
(* Aanvullende opmerking: als de cirkel onder de lijnvector valt, zal de loodrechte lengte berekend met de formule in het bovenstaande diagram een negatieve waarde produceren.)
Nu we de benadering wiskundig hebben begrepen, gaan we door met de implementatie in ActionScript. Let in dit eerste gedeelte op dat de vector van de lijn wordt geroteerd -90 ° om de linker normaal te vormen.
// declarerende coördinaten x1 = 50; y1 = 100; x2 = 250; y2 = 150; // drawing line graphics.lineStyle (3); graphics.moveTo (x1, y1); graphics.lineTo (x2, y2) // regelvectoren vormen line = new Vector2D (x2 - x1, y2 - y1); leftNormal = line.rotate (Math.PI * -0.5);
In dit tweede gedeelte heb ik de genoemde berekeningen en de voorwaarde om te controleren op een botsing tussen cirkel en lijn 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); circles[i].y += 2; //if collision happened, undo movement if (Math.abs(c1_circle_onNormal) <= circles[i].radius) circles[i].y -= 2;
Voor degenen die verder willen onderzoeken, zijn de volgende fragmenten van methoden die in Vector.as
/ ** * Methode om de projectie van de huidige vector op een gegeven as te verkrijgen * @param-as Een as waar vector wordt geprojecteerd op * @return De projectieafstand van de huidige vector op de gegeven as * / public function projectionOn (axis: Vector2D): Nummer retourneer dit.dotProduct (axis.normalise ())
/ ** * Methode om een puntproduct met een andere vector uit te voeren * @param vector2 Een vector om een puntproduct met de huidige vector uit te voeren * @return Een scalair aantal puntproduct * / public function dotProduct (vector2: Vector2D): Number var componentX: Number = this._vecX * vector2.x; var componentY: Number = this._vecY * vector2.y; return componentX + componentY;
/ ** * Methode om een vectoreenheid van de huidige vector te verkrijgen * @return Een kopie van de genormaliseerde vector * / public function normalize (): Vector2D retourneer nieuwe Vector2D (this._vecX / this.getMagnitude (), this._veCY / this. getMagnitude ())
/ ** * Methode om de huidige vectorgrootte te verkrijgen * @return Magnitude van het type Number * / public function getMagnitude (): Number return Math.sqrt (_vecX * _vecX + _vecY * _vecY);
Druk op de knop Opnieuw opstarten om alle cirkels bovenaan het werkgebied te verplaatsen. Merk op dat de botsing zich tussen de geheel lijn (inclusief de sectie niet getekend) en de cirkels. Om de botsing alleen te beperken tot het lijnsegment, blijf op de hoogte voor de volgende Quick Tip.
Bedankt voor het lezen. Blijf op de hoogte voor de volgende tip.