A Flash Developer Resource Site

Results 1 to 10 of 10

Thread: [HELP] Circle/Line Collision & Reaction

  1. #1
    Professional Air Guitarist Frag's Avatar
    Join Date
    Dec 2002
    Location
    Brain, Body, Clothes, Computer Chair, Room, House, Neighborhood, City, State, Country, Continent, World, Galaxy, Universe, and on?
    Posts
    811

    [HELP] Circle/Line Collision & Reaction

    I can do it when testing several points along the line, but there has to be a better way.

    Raigan, I've read through your tutorials several times, and examined your code, but it's more like a lecture for geniuses than average programmers looking for help with collision

    Any help would be greatly appreciated. Once I have this down there is nothing stopping me from making a killer track for the bike with super physics!

  2. #2
    ism BlinkOk's Avatar
    Join Date
    Aug 2001
    Location
    , location, location
    Posts
    5,002
    you can test for ball/line collision using localtoglobal if you want. just try the following;
    1. create an mc that contains a horizontal line. the lines y pos must be 0
    2. place it on the stage (you can rotate it if you want)
    3. when you move the ball add the following code (within the actions for the ball);
    Code:
    var p = { x: 0, y: 0 };
    localToGlobal(p);
    _root.line.globalToLocal(p);
    if (p.y < 0) {
     // the ball has collided with the line
    }
    Last edited by BlinkOk; 12-27-2004 at 07:58 PM.
    Graphics Attract, Motion Engages, Gameplay Addicts
    XP Pro | P4 2.8Ghz | 2Gb | 80Gb,40Gb | 128Mb DDR ATI Radeon 9800 Pro

  3. #3
    Professional Air Guitarist Frag's Avatar
    Join Date
    Dec 2002
    Location
    Brain, Body, Clothes, Computer Chair, Room, House, Neighborhood, City, State, Country, Continent, World, Galaxy, Universe, and on?
    Posts
    811
    Thanks, but I'm looking for a more mathematic approach, one that could be used in other languages.

  4. #4
    Untitled-2.fla
    Join Date
    Jul 2002
    Posts
    391
    ~yarr Frag - check your pm box

  5. #5
    Feeling adventurous? T1ger's Avatar
    Join Date
    Mar 2004
    Posts
    850
    Originally posted by token 3
    ~yarr Frag - check your pm box
    Please post it here if it's something about this thread. I'm interested too! =)

  6. #6
    Senior Member
    Join Date
    Jul 2004
    Posts
    153
    hey,
    well.. i didn't know if you needed vs. line, lineseg, or one-sided line, so.. here's all three

    Code:
    
    //circle (x,y,r) vs. two-sided line ([x0,y0]->[x1,y1])
    function CircleVsLine(x,y,r,x0,y0,x1,y1)
    {
    	var lx = x1 - x0;//lx,ly is a vector parallel to the line
    	var ly = y1 - y0;
    	
    	var nx = -ly;//nx,ny is a vector perpendicular to the line
    	var ny = lx;
    	var len = Math.sqrt(nx*nx + ny*ny);
    	if(len == 0)
    	{
    		return;
    	}
    	nx /= len;//nx,ny is now the unit (righthand) normal of the line
    	ny /= len;
    	
    	var dx = x - x0;//dx,dy is the vector from the line to the circle
    	var dy = y - y0;
    	
    	var dp = dx*nx + dy*ny;//dp is length of dx,dy when measured/projected onto the line's normal
    	
    	var pen = Math.abs(dp) - r;
    	if(pen < 0)
    	{
    		//circle is inside the line; project it out along the normal
    		if(0 < dp)
    		{
    			//circle is on the RHside of the line, should be projected out the +ve normal
    			pen *= -1;		
    		}
    
    		var px = nx*pen;//px,py is the penetration vector which pushes the circle out of the line
    		var py = ny*pen;
    
    		//DEBUG
    		_root.lineStyle(0, 0x882222, 100);
    		_root.moveTo(x,y);
    		_root.lineTo(x+px, y+py);
    
    	}	
    }
    
    //circle (x,y,r) vs. one-sided line ([x0,y0]->[x1,y1])
    function CircleVsHalfspace(x,y,r,x0,y0,x1,y1)
    {
    	var lx = x1 - x0;//lx,ly is a vector parallel to the line
    	var ly = y1 - y0;
    	
    	var nx = -ly;//nx,ny is a vector perpendicular to the line
    	var ny = lx;
    	var len = Math.sqrt(nx*nx + ny*ny);
    	if(len == 0)
    	{
    		return;
    	}
    	nx /= len;//nx,ny is now the unit (righthand) normal of the line
    	ny /= len;
    	
    	var dx = x - x0;//dx,dy is the vector from the line to the circle
    	var dy = y - y0;
    	
    	var dp = dx*nx + dy*ny;//dp is length of dx,dy when measured/projected onto the line's normal
    	
    	var pen = dp - r;
    	if(pen < 0)
    	{
    		//circle is on the RHside of the line, should be projected out the +ve normal
    		pen *= -1;		
    
    		var px = nx*pen;//px,py is the penetration vector which pushes the circle out of the line
    		var py = ny*pen;
    
    		//DEBUG
    		_root.lineStyle(0, 0x882222, 100);
    		_root.moveTo(x,y);
    		_root.lineTo(x+px, y+py);
    
    	}	
    }
    
    //circle (x,y,r) vs. lineseg ([x0,y0]->[x1,y1])
    function CircleVsLineSeg(x,y,r,x0,y0,x1,y1)
    {
    	var lx = x1 - x0;//lx,ly is a vector parallel to the line
    	var ly = y1 - y0;
    	var len = Math.sqrt(lx*lx + ly*ly);
    	if(len == 0)
    	{
    		return;
    	}
    	var rx = lx/len;//rx,ry is the unit direction vector of the lineseg
    	var ry = ly/len;
    	
    	var nx = -ry;//nx,ny is a vector perpendicular to the line
    	var ny = rx;
    	
    	var dx = x - x0;//dx,dy is the vector from x0,y0 to the circle
    	var dy = y - y0;
    	
    	var dpPerp = dx*rx + dy*ry;//length of dx,dy projected onto the lineseg's direction
    	if(dpPerp < 0)
    	{
    		//circle is closer to the endpoint x0,y0 than the line, project out of point x0,y0
    		var len = Math.sqrt(dx*dx + dy*dy);
    		var pen = r - len;
    		if(0 < pen)
    		{
    			//project out of the endpoint
    			dx /= len;
    			dy /= len;
    			
    			var px = dx*pen;
    			var py = dy*pen;			
    		}
    	}
    	else
    	{
    		if(len < dpPerp)
    		{
    			//circle is closer to the endpoint x1,y1 than the line, project out of point x1,y1
    			dx -= lx;//dx,dy is now the vector from x1,y1 to the circle
    			dy -= ly;
    
    			var len = Math.sqrt(dx*dx + dy*dy);
    			var pen = r - len;
    			if(0 < pen)
    			{
    				//project out of the endpoint
    				dx /= len;
    				dy /= len;
    				
    				var px = dx*pen;
    				var py = dy*pen;			
    			}
    			
    		}
    		else
    		{
    			//circle is closer to the lineseg; project out of it
    			var dp = dx*nx + dy*ny;//dp is length of dx,dy when measured/projected onto the line's normal
    			
    			var pen = Math.abs(dp) - r;
    			if(pen < 0)
    			{
    				//circle is inside the line; project it out along the normal
    				if(0 < dp)
    				{
    					//circle is on the RHside of the line, should be projected out the +ve normal
    					pen *= -1;		
    				}
    		
    				var px = nx*pen;//px,py is the penetration vector which pushes the circle out of the line
    				var py = ny*pen;
    			}					
    		}
    	}
    
    	//DEBUG
    	_root.lineStyle(0, 0x882222, 100);
    	_root.moveTo(x,y);
    	_root.lineTo(x+px, y+py);
    		
    }
    
    
    
    
    //------------- test code -----------------
    lineX0 = 100;
    lineX1 = 250;
    lineY0 = 100;
    lineY1 = 300;
    
    colTest = CircleVsLine;
    
    
    function TickTest()
    {
    	//toggle between collision functions
    	if(Key.isDown(49))
    	{
    		colTest = CircleVsLine;
    	}
    	else if(Key.isDown(50))
    	{
    		colTest = CircleVsHalfspace;
    	}
    	else if(Key.isDown(51))
    	{
    		colTest = CircleVsLineseg;
    	}
    	
    	_root.clear();
    	
    	//draw the line
    	_root.lineStyle(0, 0x222288, 100);
    	_root.moveTo(lineX0, lineY0);
    	_root.lineTo(lineX1, lineY1);
    	
    	//collide the mouse vs the line
    	colTest(_root._xmouse, _root._ymouse, 30, lineX0, lineY0, lineX1, lineY1);
    }
    _root.onEnterFrame = TickTest;
    press 1/2/3 to toggle between line, onesided line, and lineseg.
    in all the cases, px,py is the projection vector; for bounce/etc. you'll also need to unit normal, which differs, but you should be able to figure it out (i.e for vs. lienseg endpoints it's dx,dy, sometimes it's nx,ny.. basically it's the vector that's multiplied by the penetration to get the projection vector).

    raigan
    p.s - if you look at CircleVsLine(), this is a perfect example of what we're doing in the tutorial: the distance from one object to another (dx,dy) is measured along a potential seperating direction -- lines only have one of these, the direction perpendicular to the line. anyway, if the length of (dx,dy) when measurd along this axis is less than the radius, the circle is colliding with the line. does this make sense? it's important to understand the concept of seperating axes becausee they're very simple and fast, and a really powerful tool!

  7. #7
    Professional Air Guitarist Frag's Avatar
    Join Date
    Dec 2002
    Location
    Brain, Body, Clothes, Computer Chair, Room, House, Neighborhood, City, State, Country, Continent, World, Galaxy, Universe, and on?
    Posts
    811
    YAY! I owe you one...more

    Ohh! I get it! I think

  8. #8
    Professional Air Guitarist Frag's Avatar
    Join Date
    Dec 2002
    Location
    Brain, Body, Clothes, Computer Chair, Room, House, Neighborhood, City, State, Country, Continent, World, Galaxy, Universe, and on?
    Posts
    811
    http://www.gotcool.com/flash/?title=...ovieHeight=400

    Now I just need to figure out Line Segment vs Line Segment.

  9. #9
    Senior Member
    Join Date
    Jul 2004
    Posts
    153
    hey,
    i've never tried lineseg-lineseg myself using the "seperating axes" method, i've always used intersection-based code. the reason is that you need the position of the point of intersection; you _can_ get this out of the seperating axes, but it involves some extra work.

    also, what do you need lineseg-lineseg for? most of those games don't model the body of the bike, just the wheels and the head of the player.. it seems like a lot of extra work

    perhaps try using a box for the bike frame? this will speed things up, and probably have better results (all of the lineseg-lineseg stuff i've tried has problems -- it pushes the linesegs apart, but it's not always the way you WANT it to be. for instance your bike frame (if it's made up of linesegs): if you find a lineseg colliding with a segment of the bike frame, you don't just want to push them apart -- you specifically want to push the lineseg "out" of the bike frame. since linesegs don't generally have sides, this gets messy -- better to use a convex shape to model the bike frame, as it's much faster than a bunch of linesegs, and behaves better.

    really though, it seems that you should be able to design the game so that you donn't need a good model for the bike's body -- maybe even a couple circles would do.

    raigan
    p.s - i forget, did you already explain how you were doing the braking? if not, please explain! i'm still stuck on that..

  10. #10
    Professional Air Guitarist Frag's Avatar
    Join Date
    Dec 2002
    Location
    Brain, Body, Clothes, Computer Chair, Room, House, Neighborhood, City, State, Country, Continent, World, Galaxy, Universe, and on?
    Posts
    811
    code:

    function rW(p, nx, ny) {
    w = p.w;
    if (Key.isDown(Key.DOWN) && w == pL[0].w) {
    w.ox = w.x;
    w.oy = w.y;
    p.ox = p.x;
    p.oy = p.y;
    w.s = 0;
    } else {
    rx = -w.y;
    ry = w.x;
    len = Math.sqrt(rx*rx+ry*ry);
    rx /= len;
    ry /= len;
    sx = rx*w.s;
    sy = ry*w.s;
    tx = p.x-p.ox;
    ty = p.y-p.oy;
    vx = tx+sx;
    vy = ty+sy;
    dp = -ny*vx+nx*vy;
    w.ox = w.x-dp*rx;
    w.oy = w.y-dp*ry;
    w0 = 1-w.w;
    p.x += w0*w.s*-ny;
    p.y += w0*w.s*nx;
    w.s *= w.w;
    }
    }


    Sorry I can't explain it right now, I'm leaving in 10 minutes! I'm sure you can figure it out, p is the point and w is the wheel (I think you used rim).

    Good luck

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center