 Computer Science Canada Programming C, C++, Java, PHP, Ruby, Turing, VB   Username:   Password: Wiki Blog Search Turing Chat Room Members
Collision Detection        Author Message
Andy Posted: Thu Oct 19, 2006 2:59 am   Post subject: (No subject)

I've just never used basic collision detection for my programs, i was taught to use whatdotcolour, and what is what i use to this day. i prefer to use what i allready know (even if it does suck) instead of learning something else, when they both serve the same purpose (depending on useage). one day ill learn normal collision detection, and this conversation would be pointless...

that is the dumbest justification you could've possibly gave. if that is your attitude, then we dont need your input. your job, as a student is to learn, and we are here to help you learn how to complete your tasks the most efficient way.

and cervantes, whatdotcolor is superior in every situation. i'd like to see your math detect collision in the situation you mentioned with convex polygons    Cervantes  Posted: Thu Oct 19, 2006 9:00 am   Post subject: (No subject)

Cervantes wrote:
and cervantes, whatdotcolor is superior in every situation. i'd like to see your math detect collision in the situation you mentioned with convex polygons

I doubt I could do it, but I believe it can be done. I'd like to see whatdotcolour do the collision detection in that situation. Or even in the situation using circles instead of convex polygons. And remember, maintaining a good execution speed is important here. blaster009 Posted: Sat Oct 28, 2006 6:44 pm   Post subject: (No subject)

God forbid you should be able to use decent looking pictures in your program with various different colours. I mean, thinking that far outside of the box would completely nullify whatdotcolour! [Gandalf]  Posted: Sat Oct 28, 2006 6:52 pm   Post subject: (No subject)

blaster009 wrote:
God forbid you should be able to use decent looking pictures in your program with various different colours. I mean, thinking that far outside of the box would completely nullify whatdotcolour!

Ah but it's you who are not thinking outside the box. What if there was a collision detection layer, underneath your colourful pictures, which you used whatdotcolour on? I'm sure there's tons of other tricky stuff that can be done with whatdotcolour. Cervantes  Posted: Sat Oct 28, 2006 10:51 pm   Post subject: (No subject)

[Gandalf] wrote:
Ah but it's you who are not thinking outside the box. What if there was a collision detection layer, underneath your colourful pictures, which you used whatdotcolour on?

Then you'd be doing far more drawing than necessary, and your code would be that much slower. Drawing is a hefty task. [Gandalf]  Posted: Sat Oct 28, 2006 11:09 pm   Post subject: (No subject)

Cervantes wrote:
Then you'd be doing far more drawing than necessary, and your code would be that much slower. Drawing is a hefty task.

The point is that using multi-coloured pictures doesn't "completely nullify" whatdotcolour. Indeed, using math is almost always faster and more flexible, but it's not the only way. Andy Posted: Sun Oct 29, 2006 4:55 am   Post subject: (No subject)

cervantes, i am not suggesting a pure whatdotcolor approach. more like a combined effort between wdc and math.

With whatdotcolour detection, you only need to traverse through the outer perimeter of the given shape. and when lines cross, you get a different colored pixel than you expect, thus signifying a collision. the perimeter of anyshape can be expressed as a first degree function, so your algorithm would be O(n), its really not that slow.

blaster009, no offence, but who the hell do you think you're talking to? vertozia Posted: Fri Dec 29, 2006 12:06 am   Post subject: (No subject)

I frankly understand the picture/rectangle collision. How is colour to picture collision performed.

e.g. I'm making a Mario game, Mario is a pic, the pipe is a color? How?    Cervantes  Posted: Fri Dec 29, 2006 5:27 pm   Post subject: (No subject)

Did you read the whatdotcolour tutorial? That would be a good place to start. richcash Posted: Fri Mar 16, 2007 9:40 pm   Post subject: Re: Collision Detection

To get the most out of this tutorial, you will need to understand the following :
if and for loop constructs
types
records
functions
circular collision detection
rectangular collision detection

Circle vs Rectangle

Assume that :
(x1, y1) is the lower left corner of the rectangle
(x2, y2) is the upper right corner of the rectangle
(x, y) is the center of the circle
r is the radius of the circle

The first way we can check if the circle and rectangle are intersecting is to check if any of the rectangle's four corners are inside of the circle. We already have two of the rectangle's corners (x1, y1) and (x2, y2). The other two corners will obviously be (x1, y2) and (x2, y1).
if (x1 - x)^2 + (y1 - y)^2 <= r^2 or (x1 - x)^2 + (y2 - y)^2 <= r^2 or (x2 - x)^2 + (y1 - y)^2 <= r^2 or (x2 - x)^2 + (y2 - y)^2 <= r^2
then we know we have a collision between the circle and the rectangle

But the circle and rectangle can intersect in such a way that none of the rectangle's corners are inside of the circle. Just imagine the circle on one of the rectangle's edges. First, let's think of this type of scenario happenning on one of the rectangle's horizontal edges. If this is the case, then either the highest point on the circle or the lowest point on the circle is inside of the rectangle. Similarly, for the vertical edges, the furthest left or furthest right point on the circle must be inside of the rectangle. So, we just check these four points to be in the rectangle. These four points on a circle are obvious :
highest : (x, y + r)
lowest : (x, y - r)
furthest right : (x + r, y)
furthest left : (x - r, y)

This is one long expression, and we can even pin it on to the last one using an or. But, to keep it neat, you might want to separate them. For example, I separated them in horizontal edge collisions and vertical edge collisions :

if x > x1 and x < x2 and (y + r > y1 and y + r < y2 or y - r > y1 and y - r < y2)
then there is an intersection
if y > y1 and y < y2 and (x + r > x1 and x + r < x2 or x - r > x1 and x - r < x2)
then there is an intersection

These cases above do not cover all intersections of a circle and a rectangle, though. Can you think of a scenario where none of the four corners of the rectangle are inside of the circle and the highest, lowest, furthest left, or furthest right points of the circle are not inside the rectangle?

Imagine a circle and a square with the same center and the square's corners sticking out of the circle. If this is happening, then the center of the circle must be inside of the rectangle, so we can check for that last condition.
if x > x1 and x < x2 and y > y1 and y < y2
then the rectangle and circle are intersecting

So, we have created four expressions (that can all be combined into one expression using or if we really want to). If any of these expressions are true, then there is an intersection. If none of them are true, then there is no collision between the rectangle and the circle.

 code: View.Set ("offscreenonly") var x1, y1, x2, y2, x, y, b, r : int x1 := 100 y1 := 100 x2 := 200 y2 := 200 r := 60 fcn circleRectangle (x, y, r, x1, y1, x2, y2 : real) : boolean     if x > x1 and x < x2 and (y + r > y1 and y + r < y2 or y - r > y1 and y - r < y2) then         result true     end if     if y > y1 and y < y2 and (x + r > x1 and x + r < x2 or x - r > x1 and x - r < x2) then         result true     end if     if (x1 - x) ** 2 + (y1 - y) ** 2 <= r ** 2 or (x1 - x) ** 2 + (y2 - y) ** 2 <= r ** 2 or (x2 - x) ** 2 + (y1 - y) ** 2 <= r ** 2 or (x2 - x) ** 2 + (y2 - y) ** 2 <= r ** 2 then         result true     end if     result x > x1 and x < x2 and y > y1 and y < y2 end circleRectangle loop     Mouse.Where (x, y, b)     Draw.Box (x1, y1, x2, y2, black)     Draw.Oval (x, y, r, r, blue)     put circleRectangle (x, y, r, x1, y1, x2, y2)     View.Update     delay (10)     cls end loop

Point on Ellipse

The formula for a point (x, y) on an ellipse is :
((e.x - x)/rx)^2 + ((e.y - y)/ry)^2 = 1
where (e.x, e.y) is the center of the ellipse

e.rx is the x-radius (the distance from the center to the outside of the ellipse along the x-axis)

e.ry is the y-radius (the distance from the center to the outside of the ellipse along the y-axis)

Let's write the expression for determining if a point (x, y) is inside of a circle :
(c.x - x)^2 + (c.y - y)^2 <= r^2
this can be rewritten as :
((c.x - x)/r)^2 + ((c.y - y)/r)^2 <= 1
Do you see the similarity to the ellipse equation? It just so happens that for the ellipse, the expression is similar to the circle one except it uses the x-radius and y-radius :

((e.x - x)/rx)^2 + ((e.y - y)/ry)^2 <= 1
If the above expression evaluates to true, then the point is on or inside the ellipse. Otherwise, the point is outside of the ellipse.

 code: View.Set ("offscreenonly") type ellipse :     record         x, y, rx, ry : real         clr : int     end record var e : ellipse var x, y, button : int e.x := 100 e.y := 100 e.rx := 85 e.ry := 32 e.clr := green fcn pointEllipse (e : ellipse, x, y : real) : boolean     result ((e.x - x) / e.rx) ** 2 + ((e.y - y) / e.ry) ** 2 <= 1 end pointEllipse loop     Mouse.Where (x, y, button)     Draw.Oval (round (e.x), round (e.y), round (e.rx), round (e.ry), e.clr)     put pointEllipse (e, x, y)     View.Update     delay (10)     cls end loop

Math Review : Finding the point of intersection of two lines

The equation of a line is :
y = mx + b OR

where m is the slope and b is the y-intercept
y - y0 = m * (x - x0)

where m is the slope and (x0, y0) is a known point on the line

Suppose we are given two points on two different lines and we want to find the point of intersection of these two lines
(x1, y1) and (x2, y2) are on the first line
(x3, y3) and (x4, y4) are on the second line

then, we have to first find the slopes of both lines so we can write the equation of each line :
m1 = (y2 - y1) / (x2 - x1) slope of the first line
m2 = (y4 - y3) / (x4 - x3) slope of the second line

Now, we write the equations of both lines :
y - y1 = m1 * (x - x1)
y - y3 = m2 * (x - x3)

To solve for the point of intersection, we solve for x and y in this system of equations.
y = m1*x - m1*x1 + y1
y = m2*x - m1*x3 + y3

m1*x - m1*x1 + y1 = m2*x - m2*x3 + y3
m1*x - m2*x = -m2*x3 + y3 + m1*x1 - y1
(m1 - m2) * x = -m2*x3 + y3 + m1*x1 - y1

x = (-m2*x3 + y3 + m1*x1 - y1) / (m1 - m2)
y = m1*(x - x1) + y1
<-we substitute x which we computed above into this equation to get y

And (x, y) will be the point of intersection.

Line Segment vs. Line Segment

Lines extend infinitely (have an infinite length), while line segments have two endpoints and a finite length. When dealing with graphics, line segments are usually more relevant. Any two non-parallel lines are intersecting, but this can not be said for line segments.

Suppose the first line segment has endpoints (x1, y1) and (x2, y2).
Suppose the second line segment has endpoints (x3, y3) and (x4, y4).

To determine whether or not two line segments are intersecting, we first treat them as lines. We find the slope of each line and calculate the intersection point.

m1 = (y2 - y1) / (x2 - x1)
m2 = (y4 - y3) / (x4 - x3)
intX = (-m2 * x3 + y3 + m1 * x1 - y1) / (m1 - m2)
intY = (m1 * (intX - x1) + y1)

Now we have the intersection point (intX, intY) of the two lines, but remember, we have line segments. So, we check if this point of intersection is on BOTH line segments. If it is, then the line segments are intersecting. If it's not on one or both of the line segments, then there is no intersection.

To check if this point is on the line segment, we just check if its x-coordinates are between the x coordinates of the endpoints of the first and second line. We do the same with its y coordinate. After some logic, it can be shortened to :
intX >= max (min (x1, x2), min (x3, x4)) and intX <= min (max (x1, x2), max (x3, x4)) and
intY >= max (min (y1, y2), min (y3, y4)) and intY <= min (max (y1, y2), max (y3, y4))

if the above expression is true, then the line segments are intersecting.

 code: View.Set ("offscreenonly") var x1, y1, x2, y2, x3, y3, x4, y4, angle : real var x, y, button : int angle := 90 x1 := 100 y1 := 100 x2 := 200 y2 := 200 fcn lineLine (x1, y1, x2, y2, x3, y3, x4, y4 : real) : boolean     var m1 := (y2 - y1) / (x2 - x1 + 1e-5)     var m2 := (y4 - y3) / (x4 - x3 + 1e-5)     var intX := round ((-m2 * x3 + y3 + m1 * x1 - y1) / (m1 - m2))     var intY := round ((m1 * (intX - x1) + y1))     result intX >= max (min (x1, x2), min (x3, x4)) and intX <= min (max (x1, x2), max (x3, x4)) and         intY >= max (min (y1, y2), min (y3, y4)) and intY <= min (max (y1, y2), max (y3, y4)) end lineLine loop     Mouse.Where (x, y, button)     x3 := x     y3 := y     if button = 1 then         angle += 1     end if     x4 := x + 70 * cosd (angle)     y4 := y + 70 * sind (angle)     Draw.Line (round (x1), round (y1), round (x2), round (y2), blue)     Draw.Line (round (x3), round (y3), round (x4), round (y4), red)     put lineLine (x1, y1, x2, y2, x3, y3, x4, y4)     View.Update     delay (10)     cls end loop

Line Segment vs. Circle

We know by know that if the distance from the line to the center of the circle is less than the radius of the circle, then the line segment must be intersecting with the circle. But, we can do even better, the closest point on this line segment to the center of the circle must be inside the circle for an intersection to occur. So now the problem becomes finding the point on the line segment that is the closest to the center of the circle.

Let :
(x, y) be the center of the circle
r be the radius of the circle
(x1, y1) and (x2, y2) be the endpoints of the line segment

Now, first let's treat the line segment as a line and find the point on the line closest to the center of the circle. We'll call the line (l).
For this, we assume the geometric property that the shortest path from a point to a line is the path perpendicular to the line.
Assuming this, we now have a second line and we know its slope will be perpendicular to the original line (l) and it will go through the center of the circle. We find the intersection point of the original line (l) and the new perpendicular line.

m = (y2 - y1) / (x2 - x1)
M = -1 / m
X = (m * x1 - y1 - M * x + y) / (m - M)
Y = m * (X - x1) + y1

where m is the slope of the original line (l)

M is the slope of the new perpendicular line

(X, Y) is the point of intersection between the two lines

Now we have the point on the line that is the shortest distance away from the center of the circle. But wait, we have a line segment to start with, so we have to check if this point of intersection is actually even on our line segment.

if X >= min (x1, x2) and X <= max (x1, x2) and Y >= min (y1, y2) and Y <= max (y1, y2)
then the point of intersection is on the line segment. Now, we check if this point is inside the circle using circular collision.
(px - X) ** 2 + (py - Y) ** 2 <= r ** 2
If that expression is true then the closest point on the line segment is inside of the circle and there is an intersection between the line segment and the circle.

But what if the point of intersection was not on our line segment (the first if statement evaluated to false)? Then we conclude that the closest point on the line segment to the center of the circle must be one of the endpoints (whichever one is closer).

Since our general circular collision compares if the distance squared is less than or equal to the radius squared, we can check which distance from endpoint to center squared is less and then see if it less than or equal to the radius squared.
min ((px - x1) ** 2 + (py - y1) ** 2, (px - x2) ** 2 + (py - y2) ** 2) <= r ** 2
If the above expression evaluates to true, then you have an intersection between the circle and the line segment. If it evaluates to false, then there is no intersection.

Bringing our two conditions together, we get pseudocode like this :
if X >= min (x1, x2) and X <= max (x1, x2) and Y >= min (y1, y2) and Y <= max (y1, y2) then

result (x - X) ** 2 + (y - Y) ** 2 <= r ** 2
else

result min ((x - x1) ** 2 + (y - y1) ** 2, (x - x2) ** 2 + (y - y2) ** 2) <= r ** 2

 code: View.Set ("offscreenonly") var x, y, button, x1, y1, x2, y2, r : int x1 := 100 y1 := 100 x2 := 100 y2 := 200 r := 25 fcn circleLine (px, py, r, x1, y1, x2, y2 : real) : boolean     var m := (y2 - y1) / (x2 - x1 + 1e-8)     var M := -1 / m     var X := (m * x1 - y1 - M * px + py) / (m - M)     var Y := m * (X - x1) + y1     if round (X) >= min (x1, x2) and round (X) <= max (x1, x2)             and round (Y) >= min (y1, y2) and round (Y) <= max (y1, y2) then         result (px - X) ** 2 + (py - Y) ** 2 <= r ** 2     else         result min ((px - x1) ** 2 + (py - y1) ** 2, (px - x2) ** 2 + (py - y2) ** 2) <= r ** 2     end if end circleLine loop     Mouse.Where (x, y, button)     put circleLine (x, y, r, x1, y1, x2, y2)     Draw.Line (x1, y1, x2, y2, black)     Draw.Oval (x, y, r, r, blue)     View.Update     delay (30)     cls end loop

Similar Ellipse vs Similar Ellipse

Well, if you use the circle again, let's write the expression that determines whether or not two circles are intersecting :
(c1.x - c2.x)^2 + (c1.y - c2.y)^2 <= (c1.r + c2.r)^2 OR
(c1.x - c2.x)^2 / (c1.r + c2.r)^2 + (c1.y - c2.y)/r)^2 / (c1.r + c2.r)^2 <= 1

Well, if we plug in the sum of the ellipses' x-radii for the first r and the sum of the ellipses' y-radii for the second r, then we have :
(e1.x - e2.x) ** 2 / (e1.rx + e2.rx) ** 2 + (e1.y - e2.y) ** 2 / (e1.ry + e2.ry) ** 2 <= 1

Unfortunately, that does not work for all ellipses. It only works for what I call similar ellipses (probably not the right mathematical term!). When I say the ellipses are similar, I mean that their x and y radii are proportional. So,
e1.rx / e1.ry = e2.rx / e2.ry

For example, if an ellipse has an x-radius of 25 and a y-radius of 40, then a similar ellipse might have an x-radius of 50 and a y-radius of 80.

I have yet to attempt to geometrically prove this, but the reason has something to do with the point of intersection of similar ellipses always being on the vector joining the two centers of the ellipses. So, if the expression we declared above is true, then the similar ellipses intersect. If that expression is false, then there is no collision.

 code: View.Set ("offscreenonly") type ellipse :     record         x, y, rx, ry, clr : int     end record var e1, e2 : ellipse var x, y, b : int e1.x := 100 e1.y := 100 e1.rx := 90 e1.ry := 50 e1.clr := red e2.rx := 45 e2.ry := 25 e2.clr := blue fcn ellipseEllipse (e1, e2 : ellipse) : boolean     result ((e2.x - e1.x) / (e1.rx + e2.rx)) ** 2 + ((e2.y - e1.y) / (e1.ry + e2.ry)) ** 2 <= 1 end ellipseEllipse loop     Mouse.Where (x, y, b)     e2.x := x     e2.y := y     Draw.Oval (e1.x, e1.y, e1.rx, e1.ry, e1.clr)     Draw.Oval (e2.x, e2.y, e2.rx, e2.ry, e2.clr)     put ellipseEllipse (e1, e2)     View.Update     delay (15)     cls end loop

Math Lesson : Determining which side of a vector a point is on (left or right?)

If you have a vector in 2 dimensions v with a tip of (x1, y1) and a tail of (x2, y2) and a point p (x, y), and you want to determine if the point is to the left or to the right of the vector, you use a cross product.

First, we construct two new vectors. One will go from the point p to the tail (start) of the vector, and the other will go from the point p to the tip (end) of the vector.
The first vector (tail to point) :
(x - x1, y - y1, 0)
The second vector (tip to point) :
(x - x2, y - y2, 0)
Note that the z component of the vectors will be 0 because we're dealing in 2 dimensions.

Now, if the point p is to the right of the original vector v, then the cross product of our two constructed vectors will be pointing out of the screen (if you know the right-hand rule, you can confirm this). If the point p is to the left, the cross product will be going into the screen. Well, if the cross product is coming out of the screen, then the z-component will be negative; and if the cross product is going into the screen then the z-component will be positive. (Note, if the point is right on the line, then the two constructed vectors' cross product would obviously be 0.)

So, we just have to check the sign of the z-component of the cross product. The z-component of the cross product can be computed like this :
(y - y1) * (x2 - x1) - (x - x1) * (y2 - y1)

So, if the sign of the above calculation is negative, then the point is to the right of the vector. If the sign is positive, then the point is to the left of the vector. If the above calculation is 0, then the point is on the vector.

Point in Convex Polygon

Let's say the array that represents the convex polygon's x coordinates is px and the array that represents the convex polygon's y coordinates is py. Let's call our point we are testing p (x, y).

In order to use the Draw.Polygon procedure, you must have your coordinates in your arrays in order. Well, since we're dealing with a convex polygon, the points must go in a clockwise or counter-clockwise direction. Now, imagine each edge of the polygon as a vector so that the polygon creates either a clockwise or counter-clockwise path. If your path is clockwise, then all points inside of the polygon are to the right of each edge vector. If your path is counterclockwise, then all points inside the polygon are to the left of each edge vector. All points outside of the polygon are to the left of some edge vectors and to the right of others regardless if the path is clockwise or counter-clockwise.

Now, all we do is check if our point p is to the right of all the edges of the polygon or to the left of all the edges of our polygon using the method learned in the above section.

for each edge of the polygon

z-com = (y - y1) * (x2 - x1) - (x - x1) * (y2 - y1)
where (x1, y1) is the start point (tail) of the edge vector and (x2, y2) is the ending point (tip) of the edge vector.

We check if all the z-components are the same sign (or 0; if we include a point on the polygon as inside). If all of the z-components are the same sign then the point is inside of the polygon. If at least one of them is not the same sign, then the point is outside of the convex polygon.

 code: View.Set ("offscreenonly") var px : array 1 .. 8 of int := init (100, 80, 80, 100, 120, 140, 140, 120) var py : array 1 .. 8 of int := init (100, 120, 140, 160, 160, 140, 120, 100) var x, y, button : int fcn pointPolygon (px, py : array 1 .. * of int, x, y : real) : boolean     var n := upper (px)     var z : array 1 .. n of real     for i : 1 .. n - 1         z (i) := (y - py (i)) * (px (i + 1) - px (i)) - (x - px (i)) * (py (i + 1) - py (i))     end for     z (n) := (y - py (n)) * (px (1) - px (n)) - (x - px (n)) * (py (1) - py (n))     for i : 2 .. n         if sign (z (i)) not= sign (z (1)) and sign (z (i)) not= 0 then             result false         end if     end for     result true end pointPolygon loop     Mouse.Where (x, y, button)     Draw.Polygon (px, py, 8, blue)     put pointPolygon (px, py, x, y)     View.Update     delay (10)     cls end loop

Math Lesson : Projecting a point onto a line going through the origin

If we want to project a point p (x, y) onto a line going through (0, 0) called v(vX, vY), we can use this formula :

proj.x = [(x * vx + y * vy) / (vx **2 + vy ** 2)] * vx
proj.y = [(x * vx + y * vy) / (vx **2 + vy ** 2)] * vy

Note that what's in the square brackets is the same for both proj.x and proj.y, and can be said as the dot product of the position vector of the point p with the vector v, divided by v dot v.

Convex Polygon vs. Convex Polygon

If two polygons are not intersecting, there is always a line (with infinite length) that can be drawn between them. In fact, a line can be drawn between the polygons will actually be parallel to one edge of one of the polygons. If they are intersecting, then no such line can be drawn.

So, how do we test if a line parallel to one of the 2 polygons' edges will be able to separate the polygons? Well, let's start with the first edge of the first polygon. We take a line perpendicular to this and, for simplicity, let's have this line going through (0, 0). This line will act as an axis. If we project both polygons onto this axis and the projections of the polygons are not overlapping, then the first edge of the first polygon has a line parallel to it that can separate the polygons. Simply put, there is no intersection between the polygons.

We do this for every edge of both polygons. The instant that the projections of both polygons onto a perpendicular axis are not overlapping, then we know we have no collision between the two convex polygons. If the projections overlap on every perpendicular to every edge of both polygons, then there is an intersection between the polygons.

We have one more problem which you may or may have not figured out. What is meant by projecting a polygon onto a line (axis)? By this, I just mean project every point of the polygon onto the axis and join them with a line.

So, in psuedocode :
for each edge of the polygon

find perpendicular axis going through (0, 0)

project polygon 1 onto this axis

project polygon 2 onto this axis

check if the two projection lines are overlapping

 code: View.Set ("offscreenonly") var x1 : array 1 .. 6 of int := init (100, 70, 100, 130, 160, 130) var y1 : array 1 .. 6 of int := init (100, 130, 160, 160, 130, 100) var a : array 1 .. 8 of int := init (0, -30, -30, 0, 30, 60, 60, 30) var b : array 1 .. 8 of int := init (0, 30, 60, 90, 90, 60, 30, 0) var x2, y2 : array 1 .. upper (a) of int var x, y, button : int fcn Min (arr : array 1 .. *, 1 .. * of real, n : int) : real     var minimum := arr (n, 1)     for i : 2 .. upper (arr, 2)         if arr (n, i) < minimum then             minimum := arr (n, i)         end if     end for     result minimum end Min fcn Max (arr : array 1 .. *, 1 .. * of real, n : int) : real     var maximum := arr (n, 1)     for i : 2 .. upper (arr, 2)         if arr (n, i) > maximum then             maximum := arr (n, i)         end if     end for     result maximum end Max fcn polygonPolygon (x1, y1, x2, y2 : array 1 .. * of int) : boolean     var X11 : array 1 .. upper (x1), 1 .. upper (x1) of real     var X12 : array 1 .. upper (x1), 1 .. upper (x2) of real     var X21 : array 1 .. upper (x2), 1 .. upper (x1) of real     var X22 : array 1 .. upper (x2), 1 .. upper (x2) of real     for i : 1 .. upper (x1)         var nx1, ny1 : real         if i = upper (x1) then             nx1 := -1 / (x1 (1) - x1 (upper (x1)) + 1e-8)             ny1 := -1 / (y1 (1) - y1 (upper (y1)) + 1e-8)         else             nx1 := -1 / (x1 (i + 1) - x1 (i) + 1e-8)             ny1 := -1 / (y1 (i + 1) - y1 (i) + 1e-8)         end if         for j : 1 .. upper (x1)             X11 (i, j) := ((x1 (j) * nx1 + y1 (j) * ny1) / (nx1 ** 2 + ny1 ** 2)) * nx1         end for         for j : 1 .. upper (x2)             X12 (i, j) := ((x2 (j) * nx1 + y2 (j) * ny1) / (nx1 ** 2 + ny1 ** 2)) * nx1         end for     end for     for i : 1 .. upper (x1)         if Max (X11, i) < Min (X12, i) or Max (X12, i) < Min (X11, i) then             result false         end if     end for     for i : 1 .. upper (x2)         var nx, ny : real         if i = upper (x2) then             nx := -1 / (x2 (1) - x2 (upper (x2)) + 1e-8)             ny := -1 / (y2 (1) - y2 (upper (y2)) + 1e-8)         else             nx := -1 / (x2 (i + 1) - x2 (i) + 1e-8)             ny := -1 / (y2 (i + 1) - y2 (i) + 1e-8)         end if         for j : 1 .. upper (x1)             X21 (i, j) := ((x1 (j) * nx + y1 (j) * ny) / (nx ** 2 + ny ** 2)) * nx         end for         for j : 1 .. upper (x2)             X22 (i, j) := ((x2 (j) * nx + y2 (j) * ny) / (nx ** 2 + ny ** 2)) * nx         end for     end for     for i : 1 .. upper (x2)         if Max (X21, i) <= Min (X22, i) or Max (X22, i) <= Min (X21, i) then             result false         end if     end for     result true end polygonPolygon loop     Mouse.Where (x, y, button)     for i : 1 .. upper (a)         x2 (i) := a (i) + x         y2 (i) := b (i) + y     end for     Draw.Polygon (x1, y1, upper (x1), red)     Draw.Polygon (x2, y2, upper (x2), blue)     put polygonPolygon (x1, y1, x2, y2)     View.Update     delay (10)     cls end loop richcash Posted: Fri Mar 16, 2007 9:53 pm   Post subject: Re: Collision Detection

I would like to apologize to anyone who has been waiting for this tutorial. I was supposed to do it in January and forgot all about it!

I've been working on the second part of my collision detection tutorial for about a week now. I think I've gotten quite far with it. I have a tendancy to overexplain things, so in this tutorial I tried to keep it straight to the point.

This is a work in progress. I plan on fixing up the format, adding 2 or 3 more sections, and I might still edit the polygon stuff if anyone doesn't get what I'm saying. I'm also still debating over whether or not to keep some of the math stuff in separate sections. I also forgot to provide a link to zylum's very excellent tutorial on time-based collision.

Any comments or suggestions for impovements are appreciated. If anyone wants anything else included, I'll see if I can do it. Clayton  Posted: Fri Mar 16, 2007 11:37 pm   Post subject: Re: Collision Detection

This is excellent! Until I get a look at it, I'll start off with a good +100 bits. Suggestions to come. =) zylum  Posted: Fri Mar 16, 2007 11:40 pm   Post subject: RE:Collision Detection

wow that looks like a lot of work. and it looks like you covered a lot of topics. so far i have read from the bottom (convex polygon) up to similar elipses and it looks pretty solid so far!

+Karma and 300 bits for the hard work if you manage to get elipse vs elipse to work for any arbitrary elipses i will add an additional 500 bits  richcash Posted: Sat Mar 17, 2007 2:29 am   Post subject: Re: Collision Detection

Whoa, thanks to both of you for the bits+karma!! zylum wrote:
if you manage to get elipse vs elipse to work for any arbitrary elipses

hmm... I shall try my best to get a solution. Hopefully it won't mean computing the discriminant of some quartic every frame (which would be far too costly).

Edit :

My tutorial wrote:
(c.x - x)^2 + (c.y - y)^2 <= r^2 OR
((c.x - x)/r)^2 + ((c.y - y)/r)^2 <= 1

The above is in the Similar Ellipse vs. Similar Ellipse section as the collision detection expression for two circles. This should obviously be :

(c1.x - c2.x)^2 + (c1.y - c2.y)^2 <= (c1.r + c2.r)^2 OR
(c1.x - c2.x)^2 / (c1.r + c2.r)^2 + (c1.y - c2.y)/r)^2 / (c1.r + c2.r)^2 <= 1

where c1 and c2 are two circles each with :
(x, y) as the center

Freakman Edit: I've added that in there for you, any other changes, just post here and I'll add them in.

Unfortunately, I can't edit my above post. richcash Posted: Thu Mar 22, 2007 4:14 pm   Post subject: Re: Collision Detection

I think I have finally found a solution to zylum's challenge!! My function works for any 2 ellipses that can be drawn uses Turing's Draw.Oval command (have their major and minor axes on the x and y axes and can be defined using rx and ry).

((x-x1)/a)^2 + ((y-y1)/b)^2 = 1
((x-x2)/c)^2 + ((y-y2)/d)^2 = 1

The intersection of two ellipses results in a quartic with 4 roots (2 real, 2 complex; 4 real; or 4 complex). So, someone plugged in the above two equations and found that quartic for me using Maple (algebra software). Here is the resulting ugly quartic :

Quote:
(c^4*b^4+a^4*d^4-2*c^2*b^2*a^2*d^2)*x^4

+(4*c^2*b^2*
a^2*d^2*x2+4*c^2*b^2*x1*a^2*d^2-4*a^4*d^4*x2-4*c^4*b^4*x1)*x^3

+(6*a^4*d^
4*x2^2-2*c^2*b^2*a^2*d^2*x2^2+2*c^2*a^4*d^2*y2^2-2*c^4*b^4*a^2+2*c^4*b^2
*a^2*y1^2-4*c^4*y2*a^2*y1*b^2+2*c^4*b^2*a^2*d^2+6*c^4*b^4*x1^2+2*c^2*a^4
*y1^2*d^2-2*c^2*b^2*x1^2*a^2*d^2+2*c^2*a^4*d^2*b^2-4*c^2*y2*a^4*y1*d^2-2
*c^2*a^4*d^4+2*c^4*b^2*a^2*y2^2-8*c^2*b^2*x1*a^2*d^2*x2)*x^2

+(-4*c^4*b^2
*x1*a^2*d^2+4*c^4*b^4*x1*a^2+4*c^2*b^2*x1*a^2*d^2*x2^2+8*c^4*y2*a^2*y1*b
^2*x1-4*c^2*a^4*d^2*x2*y2^2-4*c^2*a^4*d^2*x2*y1^2-4*a^4*d^4*x2^3-4*c^4*b
^2*x1*a^2*y1^2+4*c^2*b^2*x1^2*a^2*d^2*x2-4*c^4*b^4*x1^3-4*c^4*b^2*x1*a^2
*y2^2+4*c^2*a^4*d^4*x2+8*c^2*y2*a^4*y1*d^2*x2-4*c^2*a^4*d^2*x2*b^2)*x

+a^4*c^4*y2^4+a^4*d^4*x2^4+a^4*c^4*d^4+c^4*b^4*x1^4+c^4*a^4*y1^4+c^4*a^4
*b^4-2*c^4*b^4*x1^2*a^2-2*c^4*a^4*y1^2*b^2-2*c^4*a^4*y1^2*d^2+6*c^4*a^4*
y1^2*y2^2-2*c^4*a^4*b^2*d^2-2*c^4*a^4*b^2*y2^2-2*a^4*c^2*d^4*x2^2-2*a^4*
c^4*d^2*y2^2-4*c^4*y2*a^4*y1^3-4*c^4*y2^3*a^4*y1+2*c^4*b^2*x1^2*a^2*y1^2
+2*c^4*b^2*x1^2*a^2*d^2-2*c^2*b^2*x1^2*a^2*d^2*x2^2+2*c^4*b^2*x1^2*a^2*y
2^2+2*c^2*a^4*y1^2*d^2*x2^2+2*c^2*a^4*b^2*d^2*x2^2+2*c^2*a^4*d^2*x2^2*y2
^2-4*c^4*y2*a^2*y1*b^2*x1^2+4*c^4*y2*a^4*y1*b^2+4*c^4*y2*a^4*y1*d^2-4*c^
2*y2*a^4*y1*d^2*x2^2

That is awful, but it's still manageable. I calculated the coeffiecents and the constant at the end of the quartic and then calculated the discriminant. If the discriminant is less than 0, then there are two complex and two real roots. But we still have to find out whether or not when the discriminant is above 0 if the ellipses are intersecting in 4 points or in 0 points. For this you can try to see what I'm doing in my commented code.

Basically, if one ellipse has its right and left ends on separate sides of the other ellipse's center, then they are intersecting in 4 points or in none. So you have to move the ellipse to a point where a new discriminant will be less than 0 if the original position of the ellipse had 4 intersection points. I can't explain anymore than that without going into all of the details.

Because there are so many calculations going on in the computing of the coefficients, constant, and discriminant, any roundoff errors will be magnified. You'll notice that for really skinny ellipses, the accuracy is completely lost. I might write this in java to verify that it is only because of a roundoff error. To minimize the number of these errors, I use the collision expression for similar ellipse - similar ellipse (because although this function doesn't aways return true when it's supposed to, it will never return true when it's not supposed to. Therefore it can't make the collision detection worse).

I'll write a tutorial section on this soon, but until then here's my code. Enjoy!

 Turing: View.Set ("offscreenonly") var x1, y1, rx1, ry1, x2, y2, rx2, ry2, x, y, button : int x1 := 100 y1 := 100 rx1 := 50 ry1 := 180 rx2 := 200 ry2 := 40 %(X1, Y1) and (X2, Y2) are centers of ellipses %a and c are x-radii of each ellipse; b and d are y-radii of each ellipse fcn ellipseEllipse (X1, Y1, a, b, X2, Y2, c, d : real) : boolean     var x1, y1, x2, y2 : real     x1 := X1     x2 := X2     y1 := Y1     y2 := Y2 for i : 1 .. 2 %rectangular collision among the ellipses' rectangles first     if x1 + a < x2 - c or x1 - a > x2 + c or y1 + b < y2 - d or y1 - b > y2 + d then         result false     end if %if the original discriminant failed, check if it was because there 4 real intersection %points among the two ellipses by moving one so that it will ensure to have two intersection %points if it previously had 4, and still have 0 if it previously had 0     if x2 - c < x1 and x2 + c > x1 and i = 2 then         x2 := x1 + c     end if     if x1 - a < x2 and x1 + a > x2 and i = 2 then         x1 := x2 + a     end if %the constant at the end of the quartic var a0 :=a**4*c**4*y2**4+a**4*d**4*x2**4+a**4*c**4*d**4+c**4*b**4*x1**4+c**4*a**4*y1**4+c**4*a**4 *b**4-2*c**4*b**4*x1**2*a**2-2*c**4*a**4*y1**2*b**2-2*c**4*a**4*y1**2*d**2+6*c**4*a**4* y1**2*y2**2-2*c**4*a**4*b**2*d**2-2*c**4*a**4*b**2*y2**2-2*a**4*c**2*d**4*x2**2-2*a**4* c**4*d**2*y2**2-4*c**4*y2*a**4*y1**3-4*c**4*y2**3*a**4*y1+2*c**4*b**2*x1**2*a**2*y1**2 +2*c**4*b**2*x1**2*a**2*d**2-2*c**2*b**2*x1**2*a**2*d**2*x2**2+2*c**4*b**2*x1**2*a**2*y2 **2+2*c**2*a**4*y1**2*d**2*x2**2+2*c**2*a**4*b**2*d**2*x2**2+2*c**2*a**4*d**2*x2**2*y2 **2-4*c**4*y2*a**2*y1*b**2*x1**2+4*c**4*y2*a**4*y1*b**2+4*c**4*y2*a**4*y1*d**2-4*c** 2*y2*a**4*y1*d**2*x2**2 %the coefficient of the x^4 term in the quartic var a4 := c**4*b**4+a**4*d**4-2*c**2*b**2*a**2*d**2 %the coefficient of the x^3 term var a3 := 4*c**2*b**2* a**2*d**2*x2+4*c**2*b**2*x1*a**2*d**2-4*a**4*d**4*x2-4*c**4*b**4*x1 %the coefficient of the x^2 term var a2 := 6*a**4*d** 4*x2**2-2*c**2*b**2*a**2*d**2*x2**2+2*c**2*a**4*d**2*y2**2-2*c**4*b**4*a**2+2*c**4*b**2 *a**2*y1**2-4*c**4*y2*a**2*y1*b**2+2*c**4*b**2*a**2*d**2+6*c**4*b**4*x1**2+2*c**2*a**4 *y1**2*d**2-2*c**2*b**2*x1**2*a**2*d**2+2*c**2*a**4*d**2*b**2-4*c**2*y2*a**4*y1*d**2-2 *c**2*a**4*d**4+2*c**4*b**2*a**2*y2**2-8*c**2*b**2*x1*a**2*d**2*x2 %the coefficient of the x term var a1 := -4*c**4*b**2 *x1*a**2*d**2+4*c**4*b**4*x1*a**2+4*c**2*b**2*x1*a**2*d**2*x2**2+8*c**4*y2*a**2*y1*b **2*x1-4*c**2*a**4*d**2*x2*y2**2-4*c**2*a**4*d**2*x2*y1**2-4*a**4*d**4*x2**3-4*c**4*b **2*x1*a**2*y1**2+4*c**2*b**2*x1**2*a**2*d**2*x2-4*c**4*b**4*x1**3-4*c**4*b**2*x1*a**2 *y2**2+4*c**2*a**4*d**4*x2+8*c**2*y2*a**4*y1*d**2*x2-4*c**2*a**4*d**2*x2*b**2 %the discriminant of the quartic; will be negative if there are exactly two roots var D := ((a1*a2*a3)**2 - 4*(a1*a3)**3 - 4*a1**2*a2**3*a4 + 18*a1**3*a2*a3*a4 - 27*a1**4*a4**2 + 256*(a0*a4)**3) + a0*(-4*a2**3*a3**2 + 18*a1*a2*a3**3 + 16*a2**4*a4 - 80*a1*a2**2*a3*a4 - 6*a1**2*a3**2*a4 + 144 * a1**2 * a2 * a4**2) + a0**2*(-27*a3**4 + 144*a2*a3**2*a4 - 128*(a2*a4)**2 - 192*a1*a3*a4**2) %check if the discriminant is less than 0 %also check for trivial intersections that the discriminant may not pick up %due to rounding errors using the similar ellipse - similar ellipse expression     if D < 0 or ((x2 - x1) / (a + c)) ** 2 + ((y2 - y1) / (b + d)) ** 2 <= 1 then         result true     elsif i = 2 then         result D < 0 or ((x2 - x1) / (a + c)) ** 2 + ((y2 - y1) / (b + d)) ** 2 <= 1     end if end for end ellipseEllipse loop     Mouse.Where (x, y, button)     x2 := x     y2 := y     Draw.Oval (x1, y1, rx1, ry1, blue)     Draw.Oval (x2, y2, rx2, ry2, red)     put ellipseEllipse (x1, y1, rx1, ry1, x2, y2, rx2, ry2)     View.Update     delay (20)     cls end loop Display posts from previous: All Posts1 Day7 Days2 Weeks1 Month3 Months6 Months1 Year Oldest FirstNewest First         Page 2 of 3  [ 36 Posts ]
Goto page Previous  1, 2, 3  Next
 Jump to:  Select a forum  CompSci.ca ------------ - Network News - General Discussion     General Forums   -----------------   - Hello World   - Featured Poll   - Contests     Contest Forums   -----------------   - DWITE   - [FP] Contest 2006/2008   - [FP] 2005/2006 Archive   - [FP] 2004/2005 Archive   - Off Topic     Lounges   ---------   - User Lounge   - VIP Lounge     Programming -------------- - General Programming     General Programming Forums   --------------------------------   - Functional Programming   - Logical Programming   - C     C   --   - C Help   - C Tutorials   - C Submissions   - C++     C++   ----   - C++ Help   - C++ Tutorials   - C++ Submissions   - Java     Java   -----   - Java Help   - Java Tutorials   - Java Submissions   - Ruby     Ruby   -----   - Ruby Help   - Ruby Tutorials   - Ruby Submissions   - Turing     Turing   --------   - Turing Help   - Turing Tutorials   - Turing Submissions   - PHP     PHP   ----   - PHP Help   - PHP Tutorials   - PHP Submissions   - Python     Python   --------   - Python Help   - Python Tutorials   - Python Submissions   - Visual Basic and Other Basics     VB   ---   - Visual Basic Help   - Visual Basic Tutorials   - Visual Basic Submissions     Education ----------- - Student Life   Graphics and Design ----------------------- - Web Design     Web Design Forums   ---------------------   - (X)HTML Help   - (X)HTML Tutorials   - Flash MX Help   - Flash MX Tutorials   - Graphics     Graphics Forums   ------------------   - Photoshop Tutorials   - The Showroom   - 2D Graphics   - 3D Graphics     Teams ------ - dTeam Public

 Style: Appalachia blueSilver eMJay subAppalachia subBlue subCanvas subEmjay subGrey subSilver subVereor Search: