Circle Collisions

September 22nd, 2008

First tutorial in 9 months, so bare with me. :P

We are going to make a script that will make circles collide with each other. This would be very hard to do with hitTest()’s so we are going to use a small amount of trigonometry. Don’t let the big word or its meaning scare you. All we are going to need is 13 lines of code. Here is what it should look like:

(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)

As always, open up flash and start a new flash file (CS3 users, make sure you select AS2. For AS3 code jump to the bottom of the tutorial). Select the oval tool and draw a circle whatever size you want on the stage. Make sure you hold the shift button when you draw the circle so it is perfectly round, otherwise this won’t work. Select the circle and hit F8 to convert it to a movieclip. Call it whatever you want. Make sure the registration point is in the center.

Converting to a MC

Drag another “circle” MC from the library and onto the stage. Give each MC an instance name of c0 and c1 (obviously make sure you don’t call them both c1). Now we are ready to get into the code.

onEnterFrame = function () {
	c0._x = _xmouse;
	c0._y = _ymouse;
 
	xdist = c1._x - c0._x;
	ydist = c1._y - c0._y;
	dist = Math.sqrt(xdist * xdist + ydist * ydist);
	angle = Math.atan2(ydist, xdist);
 
	if(dist < c0._width) {
		c1._x = c0._x + (c0._width * Math.cos(angle));
		c1._y = c0._y + (c0._width * Math.sin(angle));
	}
};

Paste that code onto the frame.

First of all, we put everything inside an onEnterFrame() funtion. This tells flash that we want this code to be run every frame.

c0._x = _xmouse sets the circle with the instance name c0’s x coordinate to whatever the mouses is that frame. The same goes for the next line, except with the y coordinates. This makes our MC follow the mouse around.

The next 3 lines all have to do with the Pythagorean theorem, or pythag. Pythag is used to get the length of the hypotenuse of a right angled triangle. What are we using it for then? This diagram should be able to explain it better than me:

So basically pythag tells us that if you square xdist and ydist, add them together and then get the square root of that you will have the distance of the red line above, which is handy to us because it tells us how far apart the circles are. Since circles are perfectly round, if they are closer than the half of the width of each circle (or the width of one circle if they are the same size) then they are touching.

Back to the code. We get xdist, then ydist, then do pythag and alakazam. We have the distance between the circles. The next line tells us the angle of the angles in the triangle. You don’t need to understand how this works, it just does :P. We will use this a bit later.

if(dist < c0._width) { checks if the circles are colliding like I explained above. If the are it runs the following code.

c1._x = c0._x + (c0._width * Math.cos(angle));
c1._y = c0._y + (c0._width * Math.sin(angle));

The trig.

This relates back to a right angled triangle. Cosine (cos) and Sine (sin) are both trig functions that tell us a certain side of the right angled triangle if we give it the angle. The answer it gives us is on a triangle with a hypotenuse with the length of 1.

STOP! Diagram time.

As you (probably) can(’t) see from this (crappy) diagram c0._width * Math.cos(angle) returns the x distance the circle needs to move until they aren’t colliding. Same goes for the c0._width * Math.sin(angle) and the y distance. We simply make c1 move those distances from c0 and they shouldn’t be colliding anymore.

If you haven’t already gotten bored from me taking over 9000 lines to explain 13 lines of code, press Ctrl+Enter to test out this nifty little script.

AS3 code thanks to Corey:

addEventListener(Event.ENTER_FRAME, circleCollision);
 
function circleCollision(event:Event):void {
c0.x = mouseX;
c0.y = mouseY;
 
var xdist:Number = c1.x - c0.x;
var ydist:Number = c1.y - c0.y;
var dist:Number = Math.sqrt(xdist * xdist + ydist * ydist);
var angle:Number = Math.atan2(ydist, xdist);
 
if (dist < c0.width) {
c1.x = c0.x + (c0.width * Math.cos(angle));
c1.y = c0.y + (c0.width * Math.sin(angle));
}

(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Google
  • description
  • Furl
  • Slashdot
  • StumbleUpon
  • Technorati

32 Responses to “Circle Collisions”

  1. Daniel Says:

    Thanks for the tutorial, as A beginner I find all information very helpful. :

  2. David Says:

    Actually this isn’t really THAT hard to do with hitTest, you can just use it plus the radius but this is much simpler I guess! Thanks! :D

  3. admin Says:

    If you added the radius to the hitTest, you would only be testing 1 point on the circle. To do this with hitTest effectively, you would need to make a loop to run through each point around the circle (the bigger the circle the more loops needed). That could mean you need to check for a collision 360 times a frame, instead of just once like in the tutorial.

  4. David Says:

    True, that’s not good in 2 circles, but 1 circle and a line should work good. However. This code gives me an error, prob. just something that the website did to it, anyway

    unexpected ‘if’ encountered if(dist < c0._width) { at line 10

    unexpected ‘}’ encountered at line 13. Hmmm

  5. awesty Says:

    Oh, change &lt; to <

  6. Kurt Says:

    Nice tutorial :D i finally got back into flash :P. but some stuff I don’t understand like;

    dist = Math.sqrt(xdist * xdist + ydist * ydist);
    angle = Math.atan2(ydist, xdist);
    c1._x = c0._x + (c0._width * Math.cos(angle));
    c1._y = c0._y + (c0._width * Math.sin(angle));

    I just don’t get the math thing because I have no idea what it does.

  7. awesty Says:

    It’s just some trigonometry. You don’t really need to know how it works, just that it does. :P

  8. CoreySteel Says:

    Hey.

    Here is ActionScript 3.0 code, if anyone is interested :)

    addEventListener(Event.ENTER_FRAME, circleCollision);

    function circleCollision(event:Event):void {
    c0.x = mouseX;
    c0.y = mouseY;

    var xdist:Number = c1.x - c0.x;
    var ydist:Number = c1.y - c0.y;
    var dist:Number = Math.sqrt(xdist * xdist + ydist * ydist);
    var angle:Number = Math.atan2(ydist, xdist);

    if (dist < c0.width) {
    c1.x = c0.x + (c0.width * Math.cos(angle));
    c1.y = c0.y + (c0.width * Math.sin(angle));
    }

  9. awesty Says:

    Thanks Corey, I’ll add that to the post.

  10. Jotte Says:

    Thanks a ton! I’ve been looking for something similar for quite a while now. But this is more than enough for my needs.
    You’re awesome!

  11. Terrence Says:

    Nice tutorial.
    Is there any way to keep the circle on the stage?

  12. NOEL Says:

    Very clear, usefull for many things.
    Thanks

  13. Muovimuki Says:

    Very helpful tutorial (for me and for my purposes). I’m very pleased someone really explain something like that.. i don’t really understand math and… it’s frustrating.

    So. Thanks for this tutorial!

  14. LT Squirrel Says:

    why doesn’t the ball stay inside the stage when i hit it out?

  15. nono Says:

    hello and thanks for the tutorial,
    how would I add to xpeed and yspeed(speed variables) of the circle not _x and _y
    at the end of the onEnterFrame I add the xspeed and yspeed to the circles _x and _y
    I do not mind about the power you hit it with.

  16. How?!?! Says:

    Hey, i think this tut i great, but there is something i really need answered.
    How can i (in AC3 or AC2) make the circle in motion puch away the other one instead of only one circle puching the other one away?
    I just made some sort of game thingy in ac3, and i need to have the circles puch each other away!
    THX! :D

  17. Mike Says:

    Great tutorial, but I was unable to get the AS 3.0 code to work (rather new to 3.0, so not sure where the problem is). Also, just a note, the AS 2.0 uses the HTML code for the less than symbol on line 10… took a little troubleshooting to figure it out, but once I found that, worked great! Thanks!

  18. gotoandlearnflash.com » Blog Archive » Flash Tutorial: Circle collisions Says:

    [...] View Tutorial: Flash Tutorial: Circle Collisons [...]

  19. Brian Says:

    **Error** Scene=Scene 1, layer=Layer 2, frame=1:Line 10: Unexpected ‘lt’ encountered
    if(dist < c0._width) {

    **Error** Scene=Scene 1, layer=Layer 2, frame=1:Line 13: Unexpected ‘}’ encountered

    ?
    I used this code
    onEnterFrame = function () {
    c0._x = _xmouse;
    c0._y = _ymouse;

    xdist = c1._x - c0._x;
    ydist = c1._y - c0._y;
    dist = Math.sqrt(xdist * xdist + ydist * ydist);
    angle = Math.atan2(ydist, xdist);

    if(dist < c0._width) {
    c1._x = c0._x + (c0._width * Math.cos(angle));
    c1._y = c0._y + (c0._width * Math.sin(angle));
    }
    };

    but whenever I use it I get the errors, help please?

  20. Kurt Says:

    Awesty, how did you put the box things around the code?

  21. lincoln Says:

    this website is the best!

  22. 30 Hand-picked Flash and Essential Actionscript 3.0 Tutorials | Noupe Says:

    [...] - Circle Collisions [...]

  23. 克兰印象 » 30个FLASH Actionscript 3.0教程 Says:

    [...] - Circle Collisions [...]

  24. andikurnia Says:

    wew, its fun…

  25. ilike2flash Says:

    very interesting tutorial, thanks.

  26. Dyben Says:

    i have a question. After a while moving the ball around it starts to lagg more and more. why is this? anyone have a solution for this problem?
    cheers

  27. SlowX Says:

    slight error in AS3 code (missing last close brackets):

    addEventListener(Event.ENTER_FRAME, circleCollision);

    function circleCollision(event:Event):void {
    c0.x=mouseX;
    c0.y=mouseY;
    trace(c1.x - c0.x + ” ” + xdist);

    var xdist:Number=c1.x-c0.x;
    var ydist:Number=c1.y-c0.y;
    var dist:Number=Math.sqrt(xdist*xdist+ydist*ydist);
    var angle:Number=Math.atan2(ydist,xdist);

    if (dist<c0.width) {
    c1.x = c0.x + (c0.width * Math.cos(angle));
    c1.y = c0.y + (c0.width * Math.sin(angle));
    }
    }

  28. 30 Hand-picked Flash and Essential Actionscript 3.0 Tutorials | www.my2tech.com Says:

    [...] - Circle Collisions [...]

  29. anonymous Says:

    that’s gay

    balls are touching

  30. Star Bastet Says:

    Not sure if anyone is interested, but I like to take things full tilt! This may help How?!?!’s question by making both balls operational, and may also resolve Dyben’s concern as I don’t have an EnterFrame event constantly running. This is AS3 & is intended to be a Document Class - if you make this the Document Class then you don’t need any Library items or anything at all in the Flash IDE (except the link to the Doc class) - the circles are dynamically generated.

    package
    {
    import flash.display.MovieClip;
    import flash.display.Sprite;
    import flash.events.MouseEvent;
    import flash.utils.Timer;
    import flash.events.TimerEvent;

    public class CirclePusher extends MovieClip
    {
    private var _circColor:Number = 0×006600;
    private var _circ1:Sprite;
    private var _circ2:Sprite;
    private var _timer:Timer;
    private var _currCirc:Sprite;
    private var _otherCirc:Sprite;
    private var _startX:Number = 100;
    private var _startY:Number = 100;

    public function CirclePusher ():void
    {
    init();
    }

    private function init():void
    {
    _circ1 = makeCirc(_circ1);
    _circ2 = makeCirc(_circ2);
    }

    private function makeCirc(c:Sprite):Sprite
    {
    c = new Sprite();
    c.graphics.lineStyle(1,0×000000,1);
    c.graphics.beginFill(_circColor,1);
    c.graphics.drawCircle(0,0,20);
    c.graphics.endFill();
    c.addEventListener(MouseEvent.MOUSE_DOWN,initDrag);
    addChild(c);
    c.x = _startX;
    c.y = _startY;
    _startX = _startY += 50;
    return c;
    }

    private function initDrag(e:MouseEvent):void
    {
    var t = e.currentTarget;
    t.removeEventListener(MouseEvent.MOUSE_DOWN,initDrag);
    t.addEventListener(MouseEvent.MOUSE_UP,denyDrag);
    t.startDrag();
    _currCirc = t;
    if (_currCirc == _circ1)
    {
    _otherCirc = _circ2;
    }
    else
    {
    _otherCirc = _circ1;
    }
    startTimer();
    }

    private function denyDrag(e:MouseEvent):void
    {
    var t = e.currentTarget;
    t.removeEventListener(MouseEvent.MOUSE_UP,denyDrag);
    t.addEventListener(MouseEvent.MOUSE_DOWN,initDrag);
    t.stopDrag();
    stopTimer();
    }

    private function startTimer():void
    {
    _timer = new Timer(30);
    _timer.addEventListener(TimerEvent.TIMER,checkCollide);
    _timer.start();
    }

    private function stopTimer():void
    {
    _timer.stop();
    _timer.removeEventListener(TimerEvent.TIMER,checkCollide);
    _timer = null;
    }

    private function checkCollide(e:TimerEvent):void
    {
    _currCirc.x = mouseX;
    _currCirc.y = mouseY;
    var array:Array = pythag();
    if (array[0] < _currCirc.width)
    {
    _otherCirc.x = _currCirc.x + (_currCirc.width * Math.cos(array[1]));
    _otherCirc.y = _currCirc.y + (_currCirc.height * Math.sin(array[1]));
    }
    }

    private function pythag():Array
    {
    var distX:Number = _otherCirc.x - _currCirc.x;
    var distY:Number = _otherCirc.y - _currCirc.y;
    var dist:Number = Math.sqrt((distX*distX)+(distY*distY));
    var angle = Math.atan2(distY,distX);
    var tempArray:Array = new Array(dist,angle);
    return tempArray;
    }
    }
    }

  31. fun-D Says:

    Brian, try this one….
    this use AS2

    onEnterFrame = function () {
    c0._x = _xmouse;
    c0._y = _ymouse;
    xdist = c1._x-c0._x;
    ydist = c1._y-c0._y;
    dist = Math.sqrt(xdist*xdist+ydist*ydist);
    angle = Math.atan2(ydist, xdist);
    if (dist<c0._width) {
    c1._x = c0._x+(c0._width*Math.cos(angle));
    c1._y = c0._y+(c0._width*Math.sin(angle));
    }
    };

    addEventListener(event,circleCollision);

    function circleCollision(event) {
    c0.x = mouseX;
    c0.y = mouseY;

    var xdist:Number = c1.x-c0.x;
    var ydist:Number = c1.y-c0.y;
    var dist:Number = Math.sqrt(xdist*xdist+ydist*ydist);
    var angle:Number = Math.atan2(ydist, xdist);

    if (dist<c0.width) {
    c1.x = c0.x+(c0.width*Math.cos(angle));
    c1.y = c0.y+(c0.width*Math.sin(angle));
    }
    };

  32. Best Photoshop, html, javascript and php tutorials » Pixel Perfect Circle Collisions Says:

    [...] Click here for this Tutorial! Previously Posted Tutorial: Optics Simulation w/ Flash [...]

Leave a Reply