Computer Science Canada

[Module] Collision

Author:  Aange10 [ Mon Jan 16, 2012 12:54 am ]
Post subject:  [Module] Collision

Features

This module does collision, so you don't have to! It takes all the stress out of collision, by allowing you to simply input the co-ordinates, and that's it. *Relatively no math involved.
Specifically, checking rectangular collisions becomes easier because this module checks 14 points, increasing accuracy, and keeping you from running needless perimeterfors. *Shutters*

How it Works

Here's a simple breakdown:

CircleToCircle : The module finds the distance between the centers of the two circles and compares it the the sum of the radii.
RectangeToRectangle : The module distinguishes a plane for the Rectangle, and detects 14 key points and looks for plane interception.
RectangleToCircle : The module fabricates a box to represent the Circle, and detects its 14 points along with the Rectangles.

Syntax


The syntax is super simple. [See The Turing Walkthrough for importing modules]

After importing the module you can call it by these parameters:

Turing:


Collision.circleToCircle (Ball_1_x, Ball_1_y, Ball_1_xr, Ball_1_yr, Ball_2_x, Ball_2_y, Ball_2_xr, Ball_2_yr)

Collision.rectangleToRectangle (Rect_1_x1, Rect_1_y1, Rect_1_x2, Rect_1_y2, Rect_2_x1, Rect_2_y1, Rect_2_x2, Rect_2_y2)

Collision.rectangleToCircle (Rect_x1, Rect_y1, Rect_x2, Rect_y2, Ball_x, Ball_y, Ball_xr, Ball_yr)


The syntax is very self explanatory, and all of the functions output a Boolean that indicates collision.

The parameters are also all integers.

Instructions


1) Import Collision.tu
2) Call the functions with their appropriate syntaxs.
3) Done!

The Module

Just copy and paste this in a Turing File, and name it "Collision.tu"!
Turing:

unit
% David H


module Collision
    export circleToCircle, rectangleToCircle, rectangleToRectangle
   
    var distance : real
   
    %==========================================================================%
    % = == = == = == = == = == = == Circle To Circle == = == = == = == = == = =%
    %==========================================================================%
    fcn circleToCircle (x1, y1, xr1, yr1, x2, y2, xr2, yr2 : int) : boolean
        distance := sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
        if distance <= xr1 + xr2 then
            result true
        elsif distance <= xr1 + yr2 then
            result true
        elsif distance <= yr1 + yr2 then
            result true
        elsif distance <= yr1 + xr2 then
            result true
        else
            result false
        end if
    end circleToCircle





    %============================================================================%
    % = == = == = == = = == Rectangle To Rectangle = == = == = == = == = == = == %
    %============================================================================%
    fcn CheckPointInBox (toCheckX, toCheckY, x1, y1, x2, y2 : int) : boolean
        % See if an x,y point is within a plane (x1, y1, x2, y2)
        if toCheckX >= x1 then
            if toCheckY >= y1 then
                if toCheckX <= x2 then
                    if toCheckY <= y2 then
                        result true
                    else
                        result false
                    end if
                else
                    result false
                end if
            else
                result false
            end if
        else
            result false
        end if
    end CheckPointInBox

    %   Rectangle to Rectangle
    fcn rectangleToRectangle (x1_1, y1_1, x2_1, y2_1, x1_2, y1_2, x2_2, y2_2 : int) : boolean
        var toCheckX : int := x1_1 % Far Left
        var toCheckY : int := y1_1 % Bottom
        var width : int := x2_1 - x1_1
        var height : int := y2_1 - y1_1

        % Bottom Left
        if CheckPointInBox (toCheckX, toCheckY, x1_2, y1_2, x2_2, y2_2) then
            result true
        else
            toCheckX := x2_1     % Far Right
            % Bottom right
            if CheckPointInBox (toCheckX, toCheckY, x1_2, y1_2, x2_2, y2_2) then
                result true
            else
                % Top Right
                toCheckY := y2_1 % Top
                if CheckPointInBox (toCheckX, toCheckY, x1_2, y1_2, x2_2, y2_2) then
                    result true
                else
                    % Top Left
                    toCheckX := x1_1 % Left
                    if CheckPointInBox (toCheckX, toCheckY, x1_2, y1_2, x2_2, y2_2) then
                        result true
                    else
                        % Top .25
                        toCheckX := round (width * .25) + x1_1 % .25 in
                        if CheckPointInBox (toCheckX, toCheckY, x1_2, y1_2, x2_2, y2_2) then
                            result true
                        else
                            % Top .50
                            toCheckX := round (width * .50) + x1_1 % half
                            if CheckPointInBox (toCheckX, toCheckY, x1_2, y1_2, x2_2, y2_2) then
                                result true
                            else
                                % Top . 75
                                toCheckX := round (width * .75) + x1_1 % 3/4
                                if CheckPointInBox (toCheckX, toCheckY, x1_2, y1_2, x2_2, y2_2) then
                                    result true
                                else
                                    % Bottom . 75
                                    toCheckY := y1_1 % On bottom @ 3/4
                                    if CheckPointInBox (toCheckX, toCheckY, x1_2, y1_2, x2_2, y2_2) then
                                        result true
                                    else
                                        % Bottom .25
                                        toCheckX := round (width * .25) + x1_1 % .25
                                        if CheckPointInBox (toCheckX, toCheckY, x1_2, y1_2, x2_2, y2_2) then
                                            result true
                                        else
                                            % Bottom .50
                                            toCheckX := round (width * .50) + x1_1 % Half
                                            if CheckPointInBox (toCheckX, toCheckY, x1_2, y1_2, x2_2, y2_2) then
                                                result true
                                            else
                                                % Left and .50
                                                toCheckX := x1_1
                                                toCheckY := round (height * .50) + y1_1
                                                if CheckPointInBox (toCheckX, toCheckY, x1_2, y1_2, x2_2, y2_2) then
                                                    result true
                                                else
                                                    % Right and .50
                                                    if CheckPointInBox (toCheckX, toCheckY, x1_2, y1_2, x2_2, y2_2) then
                                                        result true
                                                    else
                                                        result false % Done
                                                    end if
                                                end if
                                            end if
                                        end if
                                    end if
                                end if
                            end if
                        end if
                    end if
                end if
            end if
        end if
    end rectangleToRectangle






    %============================================================================%
    % = == = == = == = = == = == Rectangle To Circle = == = == = == = == = == = =%
    %============================================================================%

    %   Rectange to Circle
    fcn rectangleToCircle (recX1, recY1, recX2, recY2, circleX, circleY, xr, yr : int) : boolean
        % Turn the circle into a box
        var tx1 : int := round ((circleX - (xr * .8))) %tx1 stands for TempX1
        var tx2 : int := round ((circleX + (xr * .8)))
        var ty1 : int := round ((circleY - (yr * .8)))
        var ty2 : int := round ((circleY + (yr * .8)))

        result rectangleToRectangle (recX1, recY1, recX2, recY2, tx1, ty1, tx2, ty2)

    end rectangleToCircle


end Collision


Working Example


Posted Below!

Author:  Raknarg [ Mon Jan 16, 2012 7:09 pm ]
Post subject:  RE:[Module] Collision

Pretty useful. However, to be honest, the rectangle to rectangle seems to be like a lot more work than it should've been.

Author:  Aange10 [ Mon Jan 16, 2012 7:18 pm ]
Post subject:  RE:[Module] Collision

Why so? A lot of times people settle for checking 4 points (corners), or decide to check the perimeter.

I do see how this could be a bit more, but i built it to reasonably check the entire rectangle, without actually doing so. The 14 strategic points allot a more accuracy than corners, but less time than scanning the perimeter.

However, I also designed it to check for collision at the most common intersections first, and find its result as quickly as possible.

Author:  Raknarg [ Mon Jan 16, 2012 7:27 pm ]
Post subject:  RE:[Module] Collision

Actually, now that I think about it, my way would have taken just as much time haha nevermind

Author:  Aange10 [ Mon Jan 16, 2012 7:31 pm ]
Post subject:  RE:[Module] Collision

Out of curiosity, what would your way have been?

Author:  Raknarg [ Mon Jan 16, 2012 7:35 pm ]
Post subject:  RE:[Module] Collision

It would have just been a corner comparison... but I was thinking of my game where I only have to compare 1 corner to 4 corners instead of 4 to 4

Author:  mirhagk [ Tue Jan 17, 2012 10:43 am ]
Post subject:  RE:[Module] Collision

If x1 and x2 are ordered so x1 is smaller than x2, then your rectangular collision detection can be a lot shorter and faster.

Turing:

%   Rectangle to Rectangle
fcn rectangleToRectangle (x1_1, y1_1, x2_1, y2_1, x1_2, y1_2, x2_2, y2_2 : int) : boolean
    if (x2_1 > x1_2) then %right side or 1st is greater than left side of 2nd
        if (x1_1 < x2_2) then %left side of 1st is less then right side of 2nd
            %if both of these are true then we know that the first rectangle has intersecting the 2nd on the x-axis. just do the same with the y
            if (y2_1 > y1_2) then
                if (y1_1 < y2_2) then
                end if
            end if
        end if
    end if
end rectangleToRectangle


EDIT: Also your circle to circle accepts 2 radius's for each circle, which suggests that the function calculates the intersection of 2 ovals (which it doesn't). You can shorten that to just accept one radius for each, and then only have the 1 if statement (instead of 4)

Author:  Zren [ Tue Jan 17, 2012 11:23 am ]
Post subject:  RE:[Module] Collision

You assume x1 and y1 are smaller than x2 and y2. You should *not* assume this. Your function should determine the smallest first. Otherwise you end up with a negative width.

Also learn about bitwise operators (and, or, ...). Your if chain could be broken down into:

code:

fcn blarg
    result a <= b and b <= c and c <= d
end blarg


Turing is also doesn't force you to end a statement at the end of the line. So for really long lines, you can do:

code:

fcn blarg
    result a <= b
        and b <= c
        and c <= d
end blarg

Author:  Aange10 [ Tue Jan 17, 2012 7:20 pm ]
Post subject:  RE:[Module] Collision

Quote:
Also learn about bitwise operators (and, or, ...). Your if chain could be broken down into:


I do know about these. However, I was thinking that splitting up the if statements would allow the program to determine a false result faster. However my err is in that I forgot that in an or statement the program will stop computing the rest of the statement if one of the ors become true.

My mistake. I'm going to implement both of your suggestions.

Author:  crossley7 [ Tue Jan 17, 2012 10:29 pm ]
Post subject:  RE:[Module] Collision

Just wondering why you need to check 14 points for rectangle to rectangle because if they intersect, 1 of the corners will overlap except in the case where 1 is very tall and narrow and the other is shorter and wider and the whole thing overlaps. you just have to check that case so there are really 9 cases. the 8 corners (2 rectangles) inside the other rectangle and the edge case where the centres overlap.

For circle to rectangle, you have to check 9 things again. The radius on corners and then radius overlapping a side and circle completely within rectangle. (Circle larger than rectangle should be covered by all of the first 8)

Author:  mirhagk [ Wed Jan 18, 2012 1:09 am ]
Post subject:  RE:[Module] Collision

Is there a reason the algorithm I suggested can't be used? Of course you will also need to make sure the points are ordered correctly (but this is easy to do)

Author:  Aange10 [ Wed Jan 18, 2012 7:52 am ]
Post subject:  Re: RE:[Module] Collision

mirhagk @ 18/1/2012, 12:09 am wrote:
Is there a reason the algorithm I suggested can't be used? Of course you will also need to make sure the points are ordered correctly (but this is easy to do)


Nope, I'm working on that right now.

Author:  Aange10 [ Sat Jan 21, 2012 7:58 pm ]
Post subject:  Re: [Module] Collision

Okay, I've implemented the new formulas, circle collision also now works with ovals.


Critiques, please?


I'm going to attach it, since it's 190 lines.

Author:  Zren [ Sun Jan 22, 2012 1:16 am ]
Post subject:  RE:[Module] Collision

Bounding boxes are usually suppose to surround the entire shape. It's usually better to have false positives then not detecting possible collisions (Eg: better to have some places the character can't move to then being half inside a wall).

Also this: http://imgur.com/usygV

There does exist ways to test oval collisions perfectly, but it's rather non-critical. You're better off wondering how to test collisions on regular shapes once those shapes have been rotated.

Author:  Aange10 [ Sun Jan 22, 2012 10:38 am ]
Post subject:  RE:[Module] Collision

Quote:

Bounding boxes are usually suppose to surround the entire shape. It's usually better to have false positives then not detecting possible collisions (Eg: better to have some places the character can't move to then being half inside a wall).


I've made the boxes all bigger.


I'm going to implement that CircleToRectangle formula, and to insure ovals will still work, I'll use my current formula for ovals, and this new one for circles (when comparing to rectangles)

Author:  Aange10 [ Sun Jan 22, 2012 12:45 pm ]
Post subject:  Re: [Module] Collision

Okay, here is the new collision detector.

It fully features each new technique I've learned :3



Any problems?



And *hint* is working to get it on the sticky list Wink


EDIT: I also changed the circle to circle collision to not use Square roots.

Author:  Zren [ Sun Jan 22, 2012 2:14 pm ]
Post subject:  RE:[Module] Collision

I like the part where you didn't even use your own functions for the new CircleRectangle collision test... You also didn't remove the use of sqrt in CircleCircle collision tests.

You will still get undetected collisions from your oval check, as the box doesn't cover the entire oval. Yes, I do mean that you should treat ovals the same as rectangles until such a time as you can refine the area down to just the oval (which might be complicated/code intensive thus the use of a bounding box check first).

Also, add circleToCircleCollision and other ___Collision functions to the export list as those are the ones that people will want to use, not the ones you use for debugging which add extra code overhead.

I haven't added this to the list as it can still be improved upon. While I can't do much quality control for ancient ass modules, your's can be. >:]

Author:  Aange10 [ Sun Jan 22, 2012 2:41 pm ]
Post subject:  RE:[Module] Collision

Quote:

I like the part where you didn't even use your own functions for the new CircleRectangle collision test...


What do you mean?

Quote:

You also didn't remove the use of sqrt in CircleCircle collision tests.


I did, after I attached it. That's why I edited it; I didn't remove the attachment because somebody had already downloaded it. So I just put an edit saying that I did.

Quote:

You will still get undetected collisions from your oval check, as the box doesn't cover the entire oval.


The sides inch off, but I'll just cover the entire oval (and a lot of extra space around it), if you think that is best.


Quote:

Also, add circleToCircleCollision and other ___Collision functions to the export list as those are the ones that people will want to use, not the ones you use for debugging which add extra code overhead.


I don't see the problem with the Boolean giving you an option to draw what is being detected. If I would have named it "drawBox" you probably wouldn't even complain about it. It's an extra feature with one Boolean parameter, and only one if statement to check for it in the module.

Why should I add the internal collision detection functions to the export list? They don't have a reason to use them; the functions already detect the difference between ovals and circles, misplaced x/y bounds of rectangles, etc. There is no reason not to use them. They determine if the shape is correct, and then execute collision detection. Likewise, they also offer you a choice to draw what is being detected.

I don't know about you, but I've had many occasions where collision was not working because of miss typed coordinates. Giving an option to draw what is being detected just makes it 100x easier to detect those mistypes.

Quote:

I haven't added this to the list as it can still be improved upon. While I can't do much quality control for ancient ass modules, your's can be. >:]

>Very Happy Good, I've learned a lot already xD

Author:  Aange10 [ Tue Jan 24, 2012 10:21 pm ]
Post subject:  RE:[Module] Collision

A response would be appreciated Smile

Author:  Zren [ Wed Jan 25, 2012 12:35 am ]
Post subject:  Re: RE:[Module] Collision

Hmmm oh right.

Aange10 @ Sun Jan 22, 2012 2:41 pm wrote:
Quote:

I like the part where you didn't even use your own functions for the new CircleRectangle collision test...


What do you mean?


I mean you redid rectangle and circle collision tests instead of using your own functions... Just look at your circleXrect function:

Turing:

if circleX >= recX1 - radius and circleY >= recY1 - radius and circleX <= recX2 + radius and circleY <= recY2 + radius then

...

elsif (circleX - recX1) ** 2 + (circleY - recY1) ** 2 <= radius ** 2 then

...


Ah sorry, now that I look at it, you really only just have a circle vs circle collision function. You could simplify that with twoPointsWithinDist(p1, p2, dist) which can be easily used for pointXcircle collision. twoPointsWithinDist(point, circle.center, cricle.radius). And also, for circleXcircle, twoPointsWithinDist(cir1.center, cir2.center, cir1.radius + cir2.radius). Basically, you can simplify the code you have now as well as expand it to include shape colliding with a point. Which is really where you should have been starting from, not complex shape vs complex shape. After all, mouse coordinates are points, making it silly that a user would need to write his own methods for colliding with points. So sorry, I misread how you implemented your functions. However that misunderstand led to this point.

Aange10 @ Sun Jan 22, 2012 2:41 pm wrote:

Quote:

Also, add circleToCircleCollision and other ___Collision functions to the export list as those are the ones that people will want to use, not the ones you use for debugging which add extra code overhead.


I don't see the problem with the Boolean giving you an option to draw what is being detected. If I would have named it "drawBox" you probably wouldn't even complain about it. It's an extra feature with one Boolean parameter, and only one if statement to check for it in the module.

Why should I add the internal collision detection functions to the export list? They don't have a reason to use them; the functions already detect the difference between ovals and circles, misplaced x/y bounds of rectangles, etc. There is no reason not to use them. They determine if the shape is correct, and then execute collision detection. Likewise, they also offer you a choice to draw what is being detected.


Having a choice to only use the logic code which is the only thing I'd use isn't a bad thing. Of course, I can obviously just edit the file myself. The point is, when you eventually reach using a language where recompiling someone else's library is annoying/unwanted, it's better to leave all your options open that are not explicitly private functions.

Think of the most annoying parameter you use in a function in Turing. Eg: Pic.Draw (picID, x, y, mode : int). 99% of the time, the user uses picCopy mode, however every time he wants to use the function, he must type that out. Replace picCopy with picMerge if the user has learned about colouy keys/transparency.

Examples of private stuff are either functions that could break usage elsewhere. Hmmm, and example being that the function only erases all the data, but normal behaviour would be to call another function that would remove that object from a list. Another one would be if the function is probably not permanent in your library, and you don't want to people to become dependent on it.

None of your function actually modify the data sent in the parameters. Nor does it modify any variables in the module's scope itself. It only reads and chucks out a response according to the state of those parameters. So it doesn't fall in the first example. It could arguably fall in the second one, this module isn't exactly stable enough to warrant that (yet).

Another reason is clarity. Your function names have nothing to do with 'draw'. Another thing is that boolean's as parameters can lead to some confusing code. Say you changed the name to drawCircleCollision. When you write code that calls this function:

drawCircleCollision(cir1, cir2, false)

Just glancing at that code, WITHOUT looking at the source of the collision module will confuse the reader into wondering what that parameter actually does. Where as:

checkCircleCollision(cir1, cir2)
drawAndCheckCircleCollision(cir1, cir2)

... Are more readable. Better explanation.

Aange10 @ Sun Jan 22, 2012 2:41 pm wrote:

I don't know about you, but I've had many occasions where collision was not working because of miss typed coordinates. Giving an option to draw what is being detected just makes it 100x easier to detect those mistypes.


Having options is fine. Preventing them is not/annoying.

~

Also: circleToCircle(): The name of this method implies that it is used for two circles, when in fact it compares two ovals, THEN simplifies if they are in fact, circles.

Author:  Aange10 [ Wed Jan 25, 2012 7:24 pm ]
Post subject:  Re: RE:[Module] Collision

Zren @ 24/1/2012, 11:35 pm wrote:

I mean you redid rectangle and circle collision tests instead of using your own functions... Just look at your circleXrect function:

Turing:

if circleX >= recX1 - radius and circleY >= recY1 - radius and circleX <= recX2 + radius and circleY <= recY2 + radius then

...

elsif (circleX - recX1) ** 2 + (circleY - recY1) ** 2 <= radius ** 2 then

...



No, that's two different if statements, not an elsif branch. It has to do with the little square in the picture you linked me.

Quote:

Ah sorry, now that I look at it, you really only just have a circle vs circle collision function. You could simplify that with twoPointsWithinDist(p1, p2, dist) which can be easily used for pointXcircle collision. twoPointsWithinDist(point, circle.center, cricle.radius). And also, for circleXcircle, twoPointsWithinDist(cir1.center, cir2.center, cir1.radius + cir2.radius).


I already to check the distance between two points (and compare to the sum of radii). Line 27-32 is the entire circle collision process.

Quote:
Basically, you can simplify the code you have now as well as expand it to include shape colliding with a point.

I guess I don't understand what you mean; I don't see where checking the distance between point A and B, and comparing it something C, is any use. If anything I already utilize that.

Quote:
Which is really where you should have been starting from, not complex shape vs complex shape. After all, mouse coordinates are points, making it silly that a user would need to write his own methods for colliding with points. So sorry, I misread how you implemented your functions.

I'm really not sure what you mean. I didn't start from complex vs complex. Understandably, circles, ovals, and rectangles are as basic as it gets. The only less is comparing two points, which is if point1X = point2X and point1Y = point2Y then. So, I don't see why it is silly that a user would write their own methods for colliding with points...?

I'm sure we have some confusion between us here. Here is basically how the program works thus far:
Turing:

    {parameters called}
        [CircleToCircle]
         * Detect if its a circle or an oval.
            () If its a circle check the differense between the distacne and the sum of the radii
                - Output result
            () If one or both circles are an oval, create bounding boxes for them
                - Output results by detecting the bounding boxes as rectangleToRectangle
        [RectangleToRectangle]
        * Make sure the points are in the correct order
            () If they are not in the correct order, it fixes them.
                - Output results based on the detection Mir showed us
            () If they are in the correct order
                - Outputs results based on the detection Mir showed us
        [RectangleToCircle]
        * Check the 'Circle' to see if its an oval or not
            () If it's an oval
                - Create a bounding box
                    & Output results by detecting the bounding box as a rectangle in rectangleToRectangle
            () If it'
s a circle
                - Check to see if the center point is close to the box
                    & See if the center point is in the box
                        # Output true
                    & See if the circle is within its own radius from any of the corners
                        # Output true
                    & otherwise
                        # Output false
                - otherwise
                    & Output false


Quote:

However that misunderstand led to this point.

Aange10 @ Sun Jan 22, 2012 2:41 pm wrote:

Quote:

Also, add circleToCircleCollision and other ___Collision functions to the export list as those are the ones that people will want to use, not the ones you use for debugging which add extra code overhead.


I don't see the problem with the Boolean giving you an option to draw what is being detected. If I would have named it "drawBox" you probably wouldn't even complain about it. It's an extra feature with one Boolean parameter, and only one if statement to check for it in the module.

Why should I add the internal collision detection functions to the export list? They don't have a reason to use them; the functions already detect the difference between ovals and circles, misplaced x/y bounds of rectangles, etc. There is no reason not to use them. They determine if the shape is correct, and then execute collision detection. Likewise, they also offer you a choice to draw what is being detected.


Having a choice to only use the logic code which is the only thing I'd use isn't a bad thing. Of course, I can obviously just edit the file myself. The point is, when you eventually reach using a language where recompiling someone else's library is annoying/unwanted, it's better to leave all your options open that are not explicitly private functions.

Think of the most annoying parameter you use in a function in Turing. Eg: Pic.Draw (picID, x, y, mode : int). 99% of the time, the user uses picCopy mode, however every time he wants to use the function, he must type that out. Replace picCopy with picMerge if the user has learned about colouy keys/transparency.

Examples of private stuff are either functions that could break usage elsewhere. Hmmm, and example being that the function only erases all the data, but normal behaviour would be to call another function that would remove that object from a list. Another one would be if the function is probably not permanent in your library, and you don't want to people to become dependent on it.

None of your function actually modify the data sent in the parameters. Nor does it modify any variables in the module's scope itself. It only reads and chucks out a response according to the state of those parameters. So it doesn't fall in the first example. It could arguably fall in the second one, this module isn't exactly stable enough to warrant that (yet).



Why exactly do I want *most* of my functions public? (Though I concur with the points you posted below, as I'll be describing)

Quote:


Another reason is clarity. Your function names have nothing to do with 'draw'. Another thing is that boolean's as parameters can lead to some confusing code. Say you changed the name to drawCircleCollision. When you write code that calls this function:

drawCircleCollision(cir1, cir2, false)

Just glancing at that code, WITHOUT looking at the source of the collision module will confuse the reader into wondering what that parameter actually does. Where as:

checkCircleCollision(cir1, cir2)
drawAndCheckCircleCollision(cir1, cir2)

... Are more readable. Better explanation.


I've never thought of it that way, and I have to agree. I now plan on reformatting my code, and I will definetly split that boolean parameter into two functions (drawCollsionX and CollisionX). [Yes, I read the article]

Quote:

Aange10 @ Sun Jan 22, 2012 2:41 pm wrote:

I don't know about you, but I've had many occasions where collision was not working because of miss typed coordinates. Giving an option to draw what is being detected just makes it 100x easier to detect those mistypes.


Having options is fine. Preventing them is not/annoying.



What do you mean preventing them?

Quote:

~

Also: circleToCircle(): The name of this method implies that it is used for two circles, when in fact it compares two ovals, THEN simplifies if they are in fact, circles.


I made this module in mind of simplicity for the user. A lot of new users would overlook the differenses of an oval and a circle. Also, I wanted a function that would work for circles of changing dimensions.

However that could be as simple as [in my games code, if I were making one]
code:

if radi1 = radi2 then
 circleToCircle
else
circleToOval
end if



So, I figure I should split the program into twelve functions?:

Turing:

    Collision.circleToCircle
    Collision.circleToOval
    Collision.ovalToOval
    Collision.rectangleToRectangle
    Collision.circleToRectangle
    Collision.ovalToRectangle
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    Collision.drawCircleToCircle
    Collision.drawCircleToOval
    Collision.drawOvalToOval
    Collision.drawRectangleToRectangle
    Collision.drawCircleToRectangle
    Collision.drawOvalToRectangle

Author:  Zren [ Thu Jan 26, 2012 12:57 am ]
Post subject:  Re: RE:[Module] Collision

Aange10 @ Wed Jan 25, 2012 7:24 pm wrote:
Zren @ 24/1/2012, 11:35 pm wrote:

I mean you redid rectangle and circle collision tests instead of using your own functions... Just look at your circleXrect function:

Turing:

if circleX >= recX1 - radius and circleY >= recY1 - radius and circleX <= recX2 + radius and circleY <= recY2 + radius then

...

elsif (circleX - recX1) ** 2 + (circleY - recY1) ** 2 <= radius ** 2 then

...



No, that's two different if statements, not an elsif branch. It has to do with the little square in the picture you linked me.


I know that. What I'm getting at is that they could be their own functions themselves as you used the same logic 3x and 4x respectively. Eg:

Turing:

if isPointInRectangle(px, py, rectX1, rectY1, rectX2, rectY2) then
....
elsif isPointInCircle(px, py, circleX, circleY, circleRadius) then


Aange10 @ Wed Jan 25, 2012 7:24 pm wrote:

Quote:

Ah sorry, now that I look at it, you really only just have a circle vs circle collision function. You could simplify that with twoPointsWithinDist(p1, p2, dist) which can be easily used for pointXcircle collision. twoPointsWithinDist(point, circle.center, cricle.radius). And also, for circleXcircle, twoPointsWithinDist(cir1.center, cir2.center, cir1.radius + cir2.radius).


I already to check the distance between two points (and compare to the sum of radii). Line 27-32 is the entire circle collision process.


You implement the logic yes, but if you wanted to use it for more than two ovals, you have to fill out useless parameters.
Turing:

    fcn CircleCollision (x1, y1, xRadius1, yRadius1, x2, y2, xRadius2, yRadius2 : int) : boolean
        var distance : real
        % Collision detection
        distance := sqrt ((x2 - x1) ** 2 + (y2 - y1) ** 2)
        if distance <= xRadius1 + xRadius2 then
            result true
        end if
        result false
    end CircleCollision

Your function doesn't even use the yRadiuses to begin with (which you imply that it would need as you force the user to supply them. To use it for two points (if we removed the already useless parameters), we'd need to enter 0 for one of the xRadiuses. Rather confusing eh?

CircleCollision(p1.x, p1.y, dist, p2.x, p2.y, 0)

Aange10 @ Wed Jan 25, 2012 7:24 pm wrote:

Quote:
Basically, you can simplify the code you have now as well as expand it to include shape colliding with a point.

I guess I don't understand what you mean; I don't see where checking the distance between point A and B, and comparing it something C, is any use. If anything I already utilize that.


Eg: Does the mouse collide with the object? You also used that subroutine repeatedly (as I mentioned above).

Aange10 @ Wed Jan 25, 2012 7:24 pm wrote:

Quote:
Which is really where you should have been starting from, not complex shape vs complex shape. After all, mouse coordinates are points, making it silly that a user would need to write his own methods for colliding with points. So sorry, I misread how you implemented your functions.

I'm really not sure what you mean. I didn't start from complex vs complex. Understandably, circles, ovals, and rectangles are as basic as it gets. The only less is comparing two points, which is if point1X = point2X and point1Y = point2Y then. So, I don't see why it is silly that a user would write their own methods for colliding with points...?


0D collisions are rather useless. So I'll agree on that point.
1D collisions are used all the time. They are what you use to build 2D collisions with.

Point collides with range on single axis.
Range collides with range.

Though admittedly, turning those into function is useless for the average user of this module. As if they require functions to do that, they need to learn how collisions work first.

The only thing in difficulty between point vs point and shape vs shape IS point vs shape (and line vs shape). You do use point collides with [insert 2D shape] in your own module (even if it isn't a function yet).

Quote:

I'm sure we have some confusion between us here. Here is basically how the program works thus far:
Turing:

            () If it's a circle
                - Check to see if the center point is close to the box
                    & See if the center point is in the box (pointInRectangle)
                        # Output true
                    & See if the circle is within its own radius from any of the corners (See if pointA and pointB are within xDistance)
                        # Output true
                    & otherwise
                        # Output false
                - otherwise
                    & Output false
 



I edited in the parts where you actually use collision with points.

Quote:

Why exactly do I want *most* of my functions public? (Though I concur with the points you posted below, as I'll be describing)


As they relate to the Collision detection, which is the point of the module.

[quote]
Quote:

Having options is fine. Preventing them is not/annoying.

What do you mean preventing them?
Quote:



Uhg. I dug myself into a hole for this one. I'll retract that statement.

Quote:

I made this module in mind of simplicity for the user. A lot of new users would overlook the differenses of an oval and a circle. Also, I wanted a function that would work for circles of changing dimensions.
...
So, I figure I should split the program into twelve functions?:

Turing:

    Collision.circleToCircle
    Collision.circleToOval
    Collision.ovalToOval
    Collision.rectangleToRectangle
    Collision.circleToRectangle
    Collision.ovalToRectangle
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    Collision.drawCircleToCircle
    Collision.drawCircleToOval
    Collision.drawOvalToOval
    Collision.drawRectangleToRectangle
    Collision.drawCircleToRectangle
    Collision.drawOvalToRectangle


Looks good (nudges at collisions with points). The confusion/error of a user is less likely to happen since the drawing functions are called Draw.Oval(). Not too mention they'll distinguish that there IS a difference when the look at the list of functions available.

Author:  Aange10 [ Fri Jan 27, 2012 9:38 pm ]
Post subject:  Re: RE:[Module] Collision

Zren @ 25/1/2012, 11:57 pm wrote:


You implement the logic yes, but if you wanted to use it for more than two ovals, you have to fill out useless parameters.
Turing:

    fcn CircleCollision (x1, y1, xRadius1, yRadius1, x2, y2, xRadius2, yRadius2 : int) : boolean
        var distance : real
        % Collision detection
        distance := sqrt ((x2 - x1) ** 2 + (y2 - y1) ** 2)
        if distance <= xRadius1 + xRadius2 then
            result true
        end if
        result false
    end CircleCollision

Your function doesn't even use the yRadiuses to begin with (which you imply that it would need as you force the user to supply them. To use it for two points (if we removed the already useless parameters), we'd need to enter 0 for one of the xRadiuses. Rather confusing eh?


With the new functions that parameter problem should be resolved.

Quote:

I edited in the parts where you actually use collision with points.


Relatively close to what I have now...

Quote:

Looks good (nudges at collisions with points). The confusion/error of a user is less likely to happen since the drawing functions are called Draw.Oval(). Not too mention they'll distinguish that there IS a difference when the look at the list of functions available.


Added - Here is the new list:

Turing:

% Points
Collision.isPointInCircle (pointX, pointY, circleX, circleY, circleRadius : int) : boolean
Collision.isPointInOval (pointX, pointY, circleX, circleY, circleXRadius, circleYRadius : int) : boolean
Collision.isPointInRectangle (pointX, pointY, rectangleX1, rectangleY1, rectangleX2, rectangleY2 : int) : boolean
Collision.are2PointsWithinDistance (point1X, point1Y, point2X, point2Y, distance : int) : boolean
% Collision
Collision.circleToCircle (circle1X, circle1Y, circle1Radius, circle2X, circle2Y, circle2Radius : int) : boolean
Collision.circleToOval (circleX, circleY, circleRadius, ovalX, ovalY, ovalXRadius, ovalYRadius : int) : boolean
Collision.rectangleToRectangle (box1_x1, box1_y1, box1_x2, box1_y2, box2_x1, box2_y1, box2_x2, box2_y2 : int) : boolean
Collision.circleToRectangle (circleX, circleY, circleRadius, recX1, recY1, recX2, recY2 : int) : boolean
Collision.ovalToRectangle (ovalX, ovalY, ovalXRadius, ovalYRadius, recX1, recY1, recX2, recY2 : int) : boolean
Collision.ovalToOval (oval1X, oval1Y, oval1XRadius, oval1YRadius, oval2X, oval2Y, oval2XRadius, oval2YRadius : int) : boolean
% Drawing (Collision)
Collision.drawOvalToOval (oval1X, oval1Y, oval1XRadius, oval1YRadius, oval2X, oval2Y, oval2XRadius, oval2YRadius : int)
Collision.drawOvalToRectangle (ovalX, ovalY, ovalXRadius, ovalYRadius, recX1, recY1, recX2, recY2 : int)
Collision.drawCircleToRectangle (circleX, circleY, radius,recX1, recY1, recX2, recY2 : int)
Collision.drawRectangleToRectangle (box1_x1, box1_y1, box1_x2, box1_y2, box2_x1, box2_y1, box2_x2, box2_y2 : int)
Collision.drawCircleToOval (circleX, circleY, circleRadius, ovalX, ovalY, ovalXRadius, ovalYRadius : int)
Collision.drawCircleToCircle (circle1X, circle1Y, circle1Radius, circle2X, circle2Y, circle2Radius : int)


I kept all the parameters in order of the name. (I.E circleToRectangle will require Circle parameters first, then Rectangle parameters)


I'd honestly like to find a better Oval Vs Oval collision algorithm. I've found this one to be the same as making a bounding box (because it really is), which is inaccurate.


I also plan on remaking the testing program, because it is absolutely disgusting to work with. It's a mess of copy and pasting. But I'll fix that before my next update, or before my final post.


: