In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Circle & Line collision calculation

Its all about the details, a circle & line collision for a physics engine ...
Get Adobe Flash player
by leichtgewicht 09 Jul 2012
/**
 * Copyright leichtgewicht ( http://wonderfl.net/user/leichtgewicht )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/lgDJ
 */

/**
 * User: Martin Heidegger
 */
package {
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.events.MouseEvent;

    public class Test extends Sprite {
        private var l:Gate;
        private var l2:Gate;
        private var c:Circle;
        private var s: int = 0;

        public function Test() {
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;
            scaleX = scaleY = 1.76;
            x = 50;
            y = 50;
            
            l = new Gate(60, 60, 180, 195);
            l2 = new Gate(180, 195, 200, 60);
            c = new Circle(10, new Velocity( -40, 80));
            
            change();
            
            addEventListener(Event.ENTER_FRAME, update);
            stage.addEventListener(MouseEvent.CLICK, change);
        }
        
        private function change(e: Event = null): void {
            if (s == 0) { 
                c.velocity.update( 10, 80 );
            } else if( s == 1 ) {
                c.velocity.update( -80, -40 );
            } else if ( s == 2 ) {
                c.velocity.update( 80, -10 );
                s = 0;
                return;
            }
            s++;
        }

        private function update(event:Event):void {
            c.x = mouseX;
            c.y = mouseY;
            graphics.clear();
            c.draw(graphics);
            l.draw(graphics, l.intersectCircle(c, graphics));
            l2.draw(graphics, l2.intersectCircle(c, graphics));
        }
    }
}

import flash.display.Graphics;

import spark.filters.ColorMatrixFilter;

class Velocity {
    public var x: Number = 0;
    public var y: Number = 0;
    public var d: Number = 0;
    public var yn:Number;
    public var xn:Number;

    public function Velocity(x: Number, y: Number) {
        update(x, y);
    }
    
    public function update(x: Number, y: Number ): void {
        this.x = x;
        this.y = y;
        this.d = Math.sqrt(x*x+y*y);
        xn = x/d;
        yn = y/d;
    }
}

class Circle {
    public var velocity: Velocity;
    public var x: Number;
    public var y: Number;
    public var r: Number;
    
    public function Circle(r: Number, velocity: Velocity ) {
        this.x = 0;
        this.y = 0;
        this.r = r;
        this.velocity = velocity;
    }
    
    public function draw( g: Graphics ): void {
        
        var xEnd: Number =  r * velocity.yn;
        var yEnd: Number = -r * velocity.xn;
        
        g.lineStyle( 1, 0xBCBCBC);
        g.moveTo(x+xEnd, y+yEnd);
        g.lineTo(x+velocity.x+xEnd, y+velocity.y+yEnd );
        g.moveTo(x-xEnd, y-yEnd);
        g.lineTo(x+velocity.x-xEnd, y+velocity.y-yEnd );

        g.lineStyle( 1, 0x000000);
        g.drawCircle( x, y, r );

        g.lineStyle( 1, 0x999999);
        g.drawCircle( x+velocity.x, y+velocity.y, r );

        g.lineStyle( 1, 0xAAAAAA);
        g.moveTo(x, y);
        g.lineTo(x+velocity.x, y+velocity.y );
    }
}

class Gate {
    
    private var startX: Number;
    private var startY: Number;
    private var endX: Number;
    private var endY: Number;
    private var a: Number;
    private var sin: Number;
    private var cos: Number;

    private var length: Number;

    private var distanceX: Number;
    private var distanceY: Number;
    private var slopeYNormalized: Number;
    private var slopeXNormalized: Number;

    public function Gate(startX: Number, startY: Number, endX: Number, endY: Number) {
        update(startX, startY, endX, endY);
    }

    private function update(startX: Number, startY: Number, endX: Number, endY: Number): void {        
        this.startX = startX;
        this.startY = startY;
        this.endX = endX;
        this.endY = endY;
        
        distanceX = endX - startX;
        distanceY = endY - startY;
        
        length = Math.sqrt( distanceX * distanceX + distanceY * distanceY );
        
        slopeXNormalized = distanceX / length;
        slopeYNormalized = distanceY / length;
        
        a = Math.atan2(distanceX, distanceY);
        sin = Math.sin(a);
        cos = Math.cos(a);
    }

    public function intersectCircle( circle: Circle, g: Graphics ): Number {
        const distanceVectorX: Number = circle.velocity.x;
        const distanceVectorY: Number = circle.velocity.y;
        const newSlopeX: Number = circle.velocity.xn*cos - circle.velocity.yn*sin;
        const newSlopeY: Number = circle.velocity.yn*cos + circle.velocity.xn*sin;
        const xRel: Number = circle.x - startX;
        const yRel: Number = circle.y - startY;
        const newX: Number = xRel*cos - yRel*sin;
        const newY: Number = yRel*cos + xRel*sin;
        const cutY: Number = newY - newSlopeY / newSlopeX * newX;
        const newEndX: Number = newX + newSlopeX * circle.velocity.d;
        const newEndY: Number = newY + newSlopeY * circle.velocity.d;
        if (  newX < -circle.r || newEndX > circle.r ) {
            return NaN;
        }

        var cutStartX: Number = 0;
        var cutStartY: Number = cutY;
        var cutEndX: Number = 0;
        var cutEndY: Number = 0;
        const alpha1: Number = Math.PI / 2 - Math.atan2(newSlopeX, newSlopeY);
        const limit: Number = circle.r * Math.sin(alpha1) / Math.cos(alpha1);
        
        var beta: Number;
        var alpha: Number;
        var alpha2: Number;
        var a2: Number;
        var a: Number;
        var b: Number;
        var x: Number;
        if ( cutY < -limit ) {
            cutPart = cutY;
            a = cutPart;
            b = circle.r;
            if( alpha1 <  Math.PI ) {
                beta = Math.PI / 2 + alpha1;
                alpha = Math.asin((Math.sin(beta) * a / b));
                if(!isNaN(alpha)) {
                    alpha2 = alpha - alpha1;
                    a2 = b * Math.sin(alpha2);
                    x = Math.sqrt(b * b - a2 * a2);
                    if( cutPart < -circle.r ) {
                        x *= -1;
                    }
                    cutStartX = 0;
                    cutStartY = 0;
                    cutEndX = x;
                    cutEndY = a2;
                } else {
                    return NaN;
                }
            } else {
                return NaN;
            }
        } else {
            if( cutY > -limit ) {
                var cutPart: Number = cutY - length;
                if ( cutPart < -limit) {
                    alpha = Math.atan2(newSlopeX, newSlopeY);
                    cutStartY = cutY + circle.r / Math.sin(alpha) * Math.sin(Math.PI/2-alpha);
                    cutStartX = 0;
                    cutEndX = circle.r;
                    cutEndY = cutStartY;
                } else {
                    if( alpha1 > 0 ) {
                        a = cutPart;
                        b = circle.r;
                        beta = Math.PI / 2 - alpha1;
                        alpha = Math.asin((Math.sin(beta) * a / b));
                        if(!isNaN(alpha)) {
                            alpha2 = alpha - alpha1;
                            a2 = b * Math.sin(alpha2);
                            x = Math.sqrt(b * b - a2 * a2);
                            if( cutPart >= circle.r ) {
                                x *= -1;
                            }
                            cutStartX = 0;
                            cutStartY = length;
                            cutEndX = x;
                            cutEndY = length + a2;
                        } else {
                            return NaN;
                        }
                    } else {
                        return NaN;
                    }
                }
            } else {
                return NaN;
            }
        }
        
        var dt: Number = 1 / (newX - newEndX) * (newX - cutEndX);
        if ( dt < 0 ) {
            return NaN;
        }

        g.lineStyle(1, 0);
        g.moveTo(0, 0);
        g.lineTo(0, length);
        g.lineStyle(1, 0x00FFFF);
        g.moveTo(newX,newY);
        g.lineTo(newX+newSlopeX*circle.velocity.d, newY+newSlopeY*circle.velocity.d);
        g.drawCircle(newEndX, newEndY, circle.r);
        g.drawCircle(newX,newY,circle.r);
        g.lineStyle(1, 0xFF0000);
        g.drawCircle(0,cutY,2);
        g.moveTo(cutStartX,cutStartY);
        g.lineTo(cutEndX, cutEndY);
        g.drawCircle(cutEndX, cutEndY, circle.r);
        return dt;
    }

    public function draw( g: Graphics, i: Number ): void {
        g.lineStyle( 1, !isNaN(i) ? 0xFF0000 : 0x00FF00 );
        g.moveTo( startX, startY );
        g.lineTo( endX, endY );
    }
}