Circle-Line Collision + reflection

Started by
4 comments, last by Crehl 15 years, 11 months ago
I'm currently writing a ball game, but have no idea how to cause the ball to reflect off lines. The line consists of two points; the circle of a center point, a radius, and a velocity vector (I definitely don't want to use angles). I was wondering if someone could explain how to go about this, as the only code I have doesn't work. All I really need to know is how to detect the collision and calculate the new vector for the ball - I already have a Vector class with methods such as calculating the normal, addition, subtraction, etc. On a side note, could someone explain what the dot product of two vectors is supposed to represent? Thanks - I've tried googling and looking through the articles here on GD.net, but I'm not exactly sure what I'm looking for in the first place. --Crehl.
Advertisement
You should be able to do a sphere-plane collision test for this (but in 2 dimensions, of course). Basically for any sphere and any plane, you can tell whether they're intersecting or which side of the plane the sphere is on. This means that if your circle intersects with a line or is going so fast it ends up on the wrong side of it, you can calculate the reflection by using the normal of the plane.

Something like this might work for you.
Thank you, MJP. The collision detection works great, and I think I've managed to get reflection code mostly working, I just need to get it properly finished (Taking into account I need to reflect the ball from where it first intersects the line, not where it currently is).

Once again, thanks.
if you are still unsure about dot products;

basically, if u,v are vectors, then

u.v = |u||v|cos(theta)

where |u| is the modulus (length) of vector u, so the square root of the sum of its components each squared

and theta is the angle between the two vectors, I think (although it is a long time since i did any Real geometry) that it should always be the acute angle, (so the one smaller than Pi/2 (90deg))

It is normally used (bad pun not intended) to find out whether two vectors are normal (at right angles) to each other, as in that case it is 0.
(and it being zero implies that they are perpendicular or both zero)
Quote:Original post by Crehl
On a side note, could someone explain what the dot product of two vectors is supposed to represent?
--Crehl.


The dot product can be found two ways. If you know the length of each vector (this is helpful if you use unit vectors) and the angle between (always less than 180°), then the dot product is the product of all of those. Mathmo wrote the equation. U·V = |U| * |V| * cos(angle_in_between).

Also, you can multiply the corresponding components, then sum them up.
So if vector U has components u.x and u.y; and vector V has components v.x and v.y, then the dot product is: U·V= (u.x * v.x) + (u.y * v.y)

EX: If you have a vector <3,2> and a vector <5,6>, then the dot product is:
(3*5) + (2*6) = 15 + 12 = 27

Interestingly, if you know the components, then you can find the angle between.

Also, the dot product applies to the 3rd dimension.
U·V = (u.x * v.x) + (u.y * v.y) + (u.z * v.z)

EX: IF you have a vector <7,3,5> and <12, 14, 2>, what is the angle in between?
U · V = |U|*|V| * cos(theta)
cos(theta) = U·V / |U| * |V|
cos(theta) = [(7*12) + (3 * 14) + (5 * 2)] / [√(7²+3²+5²) * √(12² + 14² + 2²)]
cos(theta) = (84 + 42 + 10) / ( √(49 + 9 + 25) * √(144 + 196 + 4) )
cos(theta) = 136 / ( √(83) * √(344))
theta = arccos(136 / ( √(83) * √(344))
theta ≈ 36.4°, or .635 radians
Thanks Mathmo, Mitchell314, that information about angles and the normal is interesting (Of course, cos(pi/2) == 0), and now I'm not clueless about what the dot product is.

However, I do in fact have a slight problem regarding the collision detection between the circle and the line. It's only accurate to where the center of the circle is - half the circle passes through the line before it detects the collision.

As MJP suggested, I'm using: this sweep test.

I think I know why this is - the formula requires 'any point on the plane' (In this case, just a line), and so I can only tell when the circle has passed from one side to the other - and not get an accurate distance.

Am I doing something wrong, or do I need to alter the formula?

		private double getDistance(Point P)		{			Vector C = new Vector(P);			return n.DotProduct(C) + D;		}		public bool CricleSweepTest(Point P0, Point P1, double r, Vector V, out ReflectionInfo Result)		{			//http://www.gamasutra.com/features/19991018/Gomez_1.htm			//Previous Distance			double D0 = getDistance(P0);			//Current Distance			double D1 = getDistance(P1);			Vector C0 = new Vector(P0);			Vector C1 = new Vector(P1);			Vector C;			double u = (D0 - r) / (D0 - D1);			//Point of intersection			C = C0 * (1 - u) + C1 * u;			bool inSegment = true;			//Check circle is within line segment			if (C.X <= (minX - r) || C.X >= (maxX + r))				inSegment = false;			if (C.Y <= (minY - r) || C.Y >= (maxY + r))				inSegment = false;						if (D0 > r && D1 < r && inSegment)			{				Result = new ReflectionInfo(Reflect(V), new PointF((float)C.X,(float)C.Y));				return true;			}			else			{				Result = new ReflectionInfo(V,P1);				return false;			}		}

ReflectionInfo is just a class containing the new location Point and velocity Vector. 'n' and 'D' are defined the same way as in the article.

[Update]I've hacked around it by testing against a line whose distance to the actual line is the radius, offset in the direction of the normal. There's problems with slow velocities and either lines with only a small gradient or two lines intersection (To form a cup), but I think it'll be fine for it's purpose.

[Edited by - Crehl on May 10, 2008 2:29:10 PM]

This topic is closed to new replies.

Advertisement