Circle Collisions
September 22nd, 2008
First tutorial in 9 months, so bare with me.
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:
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.
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)); }












September 23rd, 2008 at 11:12 am
Thanks for the tutorial, as A beginner I find all information very helpful. :
September 25th, 2008 at 9:17 pm
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!
September 25th, 2008 at 9:55 pm
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.
September 26th, 2008 at 12:31 am
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
September 26th, 2008 at 10:40 am
Oh, change < to <
October 3rd, 2008 at 12:20 pm
Nice tutorial
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.
October 3rd, 2008 at 1:39 pm
It’s just some trigonometry. You don’t really need to know how it works, just that it does.
October 3rd, 2008 at 10:17 pm
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));
}
October 3rd, 2008 at 11:01 pm
Thanks Corey, I’ll add that to the post.
October 6th, 2008 at 11:00 pm
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!
October 8th, 2008 at 9:16 am
Nice tutorial.
Is there any way to keep the circle on the stage?
November 23rd, 2008 at 3:32 am
Very clear, usefull for many things.
Thanks
December 6th, 2008 at 8:59 am
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!
December 19th, 2008 at 12:55 am
why doesn’t the ball stay inside the stage when i hit it out?
February 11th, 2009 at 5:14 pm
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.
February 16th, 2009 at 2:11 am
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!
March 17th, 2009 at 5:03 am
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!
March 17th, 2009 at 5:05 am
[...] View Tutorial: Flash Tutorial: Circle Collisons [...]
March 27th, 2009 at 4:08 am
**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?
March 30th, 2009 at 2:14 am
Awesty, how did you put the box things around the code?
April 15th, 2009 at 5:47 pm
this website is the best!
April 28th, 2009 at 5:24 am
[...] - Circle Collisions [...]
April 28th, 2009 at 1:30 pm
[...] - Circle Collisions [...]
May 21st, 2009 at 3:45 pm
wew, its fun…
June 7th, 2009 at 7:58 am
very interesting tutorial, thanks.
June 11th, 2009 at 9:34 pm
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
June 16th, 2009 at 4:52 am
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));
}
}
June 30th, 2009 at 5:21 pm
[...] - Circle Collisions [...]
July 9th, 2009 at 8:35 am
that’s gay
balls are touching
August 8th, 2009 at 4:45 am
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;
}
}
}
December 7th, 2009 at 6:18 pm
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));
}
};
February 23rd, 2010 at 6:39 am
[...] Click here for this Tutorial! Previously Posted Tutorial: Optics Simulation w/ Flash [...]