Computer Science Canada

Collision Detection

Author:  Mr. T [ Sat Sep 24, 2005 3:03 pm ]
Post subject:  Collision Detection

Given the following code, can you show me how to do collision detection with the 1) whatdotcolour method 2) regular method.
And can you explain why the ball looks so jittery.
code:

View.Set ("offscreenonly")
const RADIUS : int := 5
const NUM_BALLS : int := 1
var x, y, dx, dy, clr : array 1 .. NUM_BALLS of int

 for i : 1 .. NUM_BALLS
            x (i) := Rand.Int (RADIUS, maxx - RADIUS)
            y (i) := Rand.Int (RADIUS, maxy - RADIUS)
            dx (i) := Rand.Int (-3, 3)
            dy (i) := Rand.Int (-3, 3)
            clr (i) := Rand.Int (1, 15)
        end for

loop
    for i : 1 .. NUM_BALLS
        if x (i) + dx (i) < RADIUS or
                x (i) + dx (i) > maxx - RADIUS then
            dx (i) := -dx (i)
        end if
        if y (i) + dy (i) < RADIUS or
                y (i) + dy (i) > maxy - RADIUS then
            dy (i) := -dy (i)
        end if
        x (i) := x (i) + dx (i)
        y (i) := y (i) + dy (i)
        Draw.FillOval (x (i), y (i), RADIUS, RADIUS, red)
        Draw.FillBox (300, 200, 200, 300, blue)
    end for
        View.Update
    cls
end loop

Author:  Cervantes [ Sat Sep 24, 2005 6:03 pm ]
Post subject: 

1) Don't go there. There are two reasons I say this. First, it's complicated for this sort of thing. Ideally, you would check a grid of pixels in front of each ball with a width equal to that of the ball and a depth equal to the speed (vector addition of x and y components of velocity) of the ball. This is complicated by the fact that the ball can be moving in 24 different directions.

2) Use the distance formula.

code:

if Math.Distance (  x (j), y (j), x (k), y (k)  ) < radius (j) + radius (k) then
    %Handle Collision
end if


(This is assuming you are checking for collisions between different, not with that blue square you've got in the middle (?) )

On that note, the blue box drawing method should be outside the for loop. There's no point in drawing a box multiple times. (Yes, your for loop only executes once, but that can be changed easily enough.)

Lastly, it doesn't look jittery to me. It actually runs very fast, as there is no delay.

If you are looking to do collisions with the box, use some if statements.
code:

if x (i) + RADIUS >= box_x1 and y (i) + RADIUS >= box_y1 and x (i) - RADIUS <= box_x2 and y (i) - RADIUS <= box_y2 then
    % collision
end if

Author:  Mr. T [ Sat Sep 24, 2005 6:10 pm ]
Post subject:  Alex's Opinion

Cervantes wrote:
(This is assuming you are checking for collisions between different, not with that blue square you've got in the middle (?) )

leave something out Confused

Author:  Cervantes [ Sat Sep 24, 2005 6:17 pm ]
Post subject: 

Oh my gosh! Thank you for catching that! +allmybits

Author:  Mr. T [ Sat Sep 24, 2005 6:24 pm ]
Post subject:  Alex's Opinion

Sad i was being serious...whatd u wanna say?

Author:  Cervantes [ Sat Sep 24, 2005 6:39 pm ]
Post subject: 

Between different balls. Hence the circular collision detection approach.

Author:  Mr. T [ Sat Sep 24, 2005 6:46 pm ]
Post subject:  Alex's Opinion

for this method can you break down what each part represents
code:

if Math.Distance (  x (j), y (j), x (k), y (k)  ) < radius (j) + radius (k) then
    %Handle Collision
end if

for this method, do i havta break up each part into its own if statement? because each side of the box represents a different collision outcome.
code:

if x (i) + RADIUS >= box_x1 and y (i) + RADIUS >= box_y1 and x (i) - RADIUS <= box_x2 and y (i) - RADIUS <= box_y2 then
    % collision
end if

Author:  Cervantes [ Sat Sep 24, 2005 7:02 pm ]
Post subject: 

1) If the distance between the centre's of two balls is less than the sum of their radii, a collision occurs.

2) Sort of. You need to split up the x and the y conditions. Hitting the box from the left or right both result in reversing the x velocity. (vx *= -1) Same goes for hitting the box from the top or bottom.

Author:  Mr. T [ Sat Sep 24, 2005 7:22 pm ]
Post subject:  Alex's Opinion

but if i break it up like this
code:

if x (i) + dx(i) = 300  then
        dx (i) := -dx (i)
        end if

it covers x = 300 on the entire y axis Confused

[EDIT]
ok, i figured out. you just add restrictions to the what y should equal

code:

if x (i) + dx(i) = 300 and y(i)>=200 and y(i)<=300 then
        dx (i) := -dx (i)
        end if

Author:  Cervantes [ Sat Sep 24, 2005 7:49 pm ]
Post subject:  Re: Alex's Opinion

Pwned wrote:

code:

if x (i) + dx(i) = 300 and y(i)>=200 and y(i)<=300 then
        dx (i) := -dx (i)
        end if

Don't use equals. Use >= or <=. Reason being that the ball is moving at 3 pixels/loop iteration. Thus, at one time it's at 298, the next it's at 301, and the condition has never been met, though it should have.

code:

if x (i) + dx (i) >= 200 and x (i) + dx (i) <= 300 and y (i) >= 200 and y (i) <= 300 then
      dx (i) *= -1
end if
%Similarly for the y.

Author:  Mr. T [ Sat Sep 24, 2005 7:53 pm ]
Post subject:  Alex's Opinion

could you explain what the * is supposed to represent?

Author:  Mr. T [ Sat Sep 24, 2005 7:57 pm ]
Post subject:  Alex's Opinion

Ok, i am now gonna implement wat I have learned here into my jezzball game. I wanna avoid using processes, so do you have any idea how I can make the movement of the balls and the creation of the walls run in unison?

Author:  Cervantes [ Sat Sep 24, 2005 8:08 pm ]
Post subject: 

Put everything on a counter. Or a timer. Really, I don't know how you COULD put these things into processes!

dx *= -1
is the same as
dx := dx * -1

Just as
x += 1
is the same as
x := x + 1

Author:  Mr. T [ Sat Sep 24, 2005 8:12 pm ]
Post subject:  Alex's Opinion

Sorry, maybe I was being unclear. Here is my old version of JezzBall.
http://www.compsci.ca/v2/viewtopic.php?t=9749&postdays=0&postorder=asc&start=0
I wanna basically do the same thing, minus the process.

Author:  Cervantes [ Sun Sep 25, 2005 8:13 am ]
Post subject: 

Here's a small example, illustrating how to move and create pseudo-objects simultaneously, without the use of processes.

Turing:

View.Set ("offscreenonly")

var counter := 0

type obj :
    record
        x, y, vx, vy : real
        radius : int
    end record

var ball : flexible array 1 .. 0 of obj

fcn Init_Obj : obj
    var object : obj
    object.radius := Rand.Int (3, 10)
    object.x := Rand.Int (object.radius, maxx - object.radius)
    object.y := Rand.Int (object.radius, maxy - object.radius)
    object.vx := Rand.Int (-3, 3)
    object.vy := Rand.Int (-3, 3)
    result object
end Init_Obj

proc Create_New_Ball
    new ball, upper (ball) + 1
    ball (upper (ball)) := Init_Obj
end Create_New_Ball

loop

    counter := (counter + 1) mod 100
    if counter = 0 then
        Create_New_Ball
    end if

    for i : lower (ball) .. upper (ball)
        if ball (i).x <= ball (i).radius | ball (i).x >= maxx - ball (i).radius then
            ball (i).vx *= -1
        end if
        if ball (i).y <= ball (i).radius | ball (i).y >= maxy - ball (i).radius then
            ball (i).vy *= -1
        end if
        ball (i).x += ball (i).vx
        ball (i).y += ball (i).vy
    end for

    cls
    for i : lower (ball) .. upper (ball)
        Draw.FillOval (round (ball (i).x), round (ball (i).y), ball (i).radius, ball (i).radius, black)
    end for
    View.Update
    delay (10)
end loop

Author:  Mr. T [ Sun Sep 25, 2005 2:32 pm ]
Post subject:  Alex's Opinion

Thanks Alot. Very Happy

Author:  Mr. T [ Sun Sep 25, 2005 3:50 pm ]
Post subject:  Alex's Opinion

Can someone explain to me why both my Completed Wall Collision Detection and Incompleted Wall Collision Detection are not working?
code:

View.Set ("offscreenonly")
const RADIUS : int := 5
const NUM_BALLS : int := 3
var x, y, dx, dy, clr : array 1 .. NUM_BALLS of int
var box_x1, box_x2, box_y1, box_y2 : int := 0
var barX, barY, button, left, middle, right : int
var barCreator := true
var a, b : int := 0
var c := false
var d := false




for i : 1 .. NUM_BALLS
    x (i) := Rand.Int (RADIUS, maxx - RADIUS)
    y (i) := Rand.Int (RADIUS, maxy - RADIUS)
    dx (i) := Rand.Int (-5, 5)
    dy (i) := Rand.Int (-5, 5)
    clr (i) := Rand.Int (1, 15)
end for

loop
    %Outer Boundary Collision
    for i : 1 .. NUM_BALLS
        if x (i) + dx (i) < RADIUS or
                x (i) + dx (i) > maxx - RADIUS then
            dx (i) := -dx (i)
        end if
        if y (i) + dy (i) < RADIUS or
                y (i) + dy (i) > maxy - RADIUS then
            dy (i) := -dy (i)
        end if

        %Incompleted Wall Collision
        if whatdotcolour (x (i), y (i)) = red or whatdotcolour (x (i), y (i)) = green then
            return
        end if

        %Completed Wall Collision
        if x (i) + dx (i) >= box_x1 and x (i) + dx (i) <= box_x2 and y (i) >= box_y1 and y (i) <= box_y2 and whatdotcolour (x (i), y (i)) = blue then
            dx (i) *= -1
        end if

        if y (i) + dy (i) >= box_y1 and y (i) + dy (i) <= box_y2 and x (i) >= box_x1 and x (i) <= box_x2 and whatdotcolour (x (i), y (i)) = blue then
            dy (i) *= -1
        end if

        x (i) := x (i) + dx (i)
        y (i) := y (i) + dy (i)

        %Draw Ball
        Draw.FillOval (x (i), y (i), RADIUS, RADIUS, black)
    end for

    %Wall Creation
    Mouse.ButtonChoose ("multibutton")
    Mouse.Where (barX, barY, button)
    left := button mod 10           % left = 0 or 1
    middle := (button - left) mod 100       % middle = 0 or 10
    right := button - middle - left         % right = 0 or 100

    if barCreator = true then

        if left = 1 and /*barX <= maxx div 2 and barX >= 1 and*/ whatdotcolour (barX, barY) not= blue then
            button := 0
            box_x1 := barX
            box_x2 := barX
            box_y1 := barY
            box_y2 := box_y1 + 10
            if (box_x1 + a) <= maxx then
                c := true
            else
                c := false
            end if
            if (box_x1 - b) >= 0 then
                d := true
            else
                d := false
            end if
        end if
    end if

    if c = true then
        barCreator := false
        a += 3
    end if
    if c = true then
        barCreator := false
        b += 3
    end if

    if box_x1 + a >= maxx then
        Draw.FillBox (box_x1 + a, box_y1, box_x2, box_y2, blue)
    else
        Draw.FillBox (box_x1 + a, box_y1, box_x2, box_y2, red)
    end if

    if box_x1 - b <= 0 then
        Draw.FillBox (box_x1 - b, box_y1, box_x2, box_y2, blue)
    else
        Draw.FillBox (box_x1 - b, box_y1, box_x2, box_y2, green)
    end if

    View.Update
    cls
end loop

Author:  [Gandalf] [ Sun Sep 25, 2005 5:56 pm ]
Post subject: 

code:
        %Completed Wall Collision
        if x (i) + dx (i) >= box_x1 and x (i) + dx (i) <= box_x2 then
            dx (i) *= -1
        end if

        if y (i) + dy (i) >= box_y1 and y (i) + dy (i) <= box_y2 then
            dy (i) *= -1
        end if

Why did you have all that other stuff? The conditions were never being met. The whole point of having the two seperate if statements is so that you do diferent things for x collision, and for y collision.

Author:  Mr. T [ Sun Sep 25, 2005 6:05 pm ]
Post subject:  Alex's Opinion

[Gandalf] wrote:
Why did you have all that other stuff?

What other stuff? Confused

Author:  [Gandalf] [ Sun Sep 25, 2005 6:10 pm ]
Post subject: 

All of this:
code:
and y (i) >= box_y1 and y (i) <= box_y2 and whatdotcolour (x (i), y (i)) = blue

and for the other if statement too. You are basically doing 3 levels of collision detection here.

Author:  Mr. T [ Sun Sep 25, 2005 6:18 pm ]
Post subject:  Alex's Opinion

Well, what I was trying to do was cover collision for both the horizontal surfaces and vertical surfaces of a box. Here is the original code, in which the collision detection works fine.
code:

View.Set ("offscreenonly")
const RADIUS : int := 5
const NUM_BALLS : int := 3
var x, y, dx, dy, clr : array 1 .. NUM_BALLS of int
var box_x1 :=200
var box_x2 :=300
var box_y1 :=200
var box_y2 :=300






for i : 1 .. NUM_BALLS
    x (i) := Rand.Int (RADIUS, maxx - RADIUS)
    y (i) := Rand.Int (RADIUS, maxy - RADIUS)
    dx (i) := Rand.Int (-5, 5)
    dy (i) := Rand.Int (-5, 5)
    clr (i) := Rand.Int (1, 15)
end for

loop
    %Outer Boundary Collision
    for i : 1 .. NUM_BALLS
        if x (i) + dx (i) < RADIUS or
                x (i) + dx (i) > maxx - RADIUS then
            dx (i) := -dx (i)
        end if
        if y (i) + dy (i) < RADIUS or
                y (i) + dy (i) > maxy - RADIUS then
            dy (i) := -dy (i)
        end if

        %Wall Collision
        if x (i) + dx (i) >= box_x1 and x (i) + dx (i) <= box_x2 and y (i) >= box_y1 and y (i) <= box_y2 then
            dx (i) *= -1
        end if

        if y (i) + dy (i) >= box_y1 and y (i) + dy (i) <= box_y2 and x (i) >= box_x1 and x (i) <= box_x2 then
            dy (i) *= -1
        end if

        x (i) := x (i) + dx (i)
        y (i) := y (i) + dy (i)

        %Draw Ball
        Draw.FillOval (x (i), y (i), RADIUS, RADIUS, red)
    end for

   
   
    Draw.FillBox (box_x1 , box_y1, box_x2, box_y2, blue)
   
    View.Update
    cls
   
   
end loop

Author:  Mr. T [ Tue Sep 27, 2005 6:50 pm ]
Post subject:  Alex's Opinion

So can anyone figure out why the collision detection isn't working?
code:

View.Set ("offscreenonly")
const RADIUS : int := 5
const NUM_BALLS : int := 3
var x, y, dx, dy, clr : array 1 .. NUM_BALLS of int
var box_x1, box_x2, box_y1, box_y2 : int := 0
var barX, barY, button, left, middle, right : int
var barCreator := true
var a, b : int := 0
var c := false
var d := false




for i : 1 .. NUM_BALLS
    x (i) := Rand.Int (RADIUS, maxx - RADIUS)
    y (i) := Rand.Int (RADIUS, maxy - RADIUS)
    dx (i) := Rand.Int (-5, 5)
    dy (i) := Rand.Int (-5, 5)
    clr (i) := Rand.Int (1, 15)
end for

loop
    %Outer Boundary Collision
    for i : 1 .. NUM_BALLS
        if x (i) + dx (i) < RADIUS or
                x (i) + dx (i) > maxx - RADIUS then
            dx (i) := -dx (i)
        end if
        if y (i) + dy (i) < RADIUS or
                y (i) + dy (i) > maxy - RADIUS then
            dy (i) := -dy (i)
        end if

        %Incompleted Wall Collision
        if whatdotcolour (x (i), y (i)) = red or whatdotcolour (x (i), y (i)) = green then
            return
        end if

        %Completed Wall Collision
        if x (i) + dx (i) >= box_x1 and x (i) + dx (i) <= box_x2 and y (i) >= box_y1 and y (i) <= box_y2 and whatdotcolour (x (i), y (i)) = blue then
            dx (i) *= -1
        end if

        if y (i) + dy (i) >= box_y1 and y (i) + dy (i) <= box_y2 and x (i) >= box_x1 and x (i) <= box_x2 and whatdotcolour (x (i), y (i)) = blue then
            dy (i) *= -1
        end if

        x (i) := x (i) + dx (i)
        y (i) := y (i) + dy (i)

        %Draw Ball
        Draw.FillOval (x (i), y (i), RADIUS, RADIUS, black)
    end for

    %Wall Creation
    Mouse.ButtonChoose ("multibutton")
    Mouse.Where (barX, barY, button)
    left := button mod 10           % left = 0 or 1
    middle := (button - left) mod 100       % middle = 0 or 10
    right := button - middle - left         % right = 0 or 100

    if barCreator = true then

        if left = 1 and /*barX <= maxx div 2 and barX >= 1 and*/ whatdotcolour (barX, barY) not= blue then
            button := 0
            box_x1 := barX
            box_x2 := barX
            box_y1 := barY
            box_y2 := box_y1 + 10
            if (box_x1 + a) <= maxx then
                c := true
            else
                c := false
            end if
            if (box_x1 - b) >= 0 then
                d := true
            else
                d := false
            end if
        end if
    end if

    if c = true then
        barCreator := false
        a += 3
    end if
    if c = true then
        barCreator := false
        b += 3
    end if

    if box_x1 + a >= maxx then
        Draw.FillBox (box_x1 + a, box_y1, box_x2, box_y2, blue)
    else
        Draw.FillBox (box_x1 + a, box_y1, box_x2, box_y2, red)
    end if

    if box_x1 - b <= 0 then
        Draw.FillBox (box_x1 - b, box_y1, box_x2, box_y2, blue)
    else
        Draw.FillBox (box_x1 - b, box_y1, box_x2, box_y2, green)
    end if

    View.Update
    cls
end loop

Author:  Mr. T [ Sat Oct 01, 2005 9:32 pm ]
Post subject:  Alex's Opinion

Any ideas? Confused

Author:  Cervantes [ Sat Oct 01, 2005 10:00 pm ]
Post subject: 

Are you certain that box_x1, box_x2, etc. are all correct? Should you need an array of coordinates? I haven't run your code, yet.

Also, why are you mixing your coordinate comparisons with whatdotcolour detection? Don't do that! The whatdotcolour is probably not working at all because just before you check your whatdotcolours, you cleared the screen (at the end of the loop). I think whatdotcolour checks the back buffer, not the front buffer.

Author:  Mr. T [ Sat Oct 01, 2005 10:36 pm ]
Post subject:  Alex's Opinion

Why would i need an array of coordinates?

Author:  Cervantes [ Sun Oct 02, 2005 8:02 am ]
Post subject: 

Because it looks like you are generating boxes. You wouldn't need an array of coordinates if you just removed the old box whenever you create a new box (which I think you're doing), but if you wanted to keep the old boxes as you generate more, you'd need a (flexible) array.

Did you try getting rid of the whatdotcolour / placing the cls elsewhere?

Author:  Mr. T [ Sun Oct 02, 2005 12:45 pm ]
Post subject:  Alex's Opinion

Placing the cls elsewhere did help the collision detection with the uncompleted walls. So I'm guessing that my collision detection with the completed walls must be off since it does not have any affect.

Author:  Cervantes [ Sun Oct 02, 2005 1:43 pm ]
Post subject: 

What are completed/uncompleted walls?

If you are referring to your "%Incompleted Wall Collision" or "%Completed wall collision", it should have a major affect on both of them.

Author:  Mr. T [ Sun Oct 02, 2005 2:30 pm ]
Post subject:  Alex's Opinion

Well it didnt have an affect on the completed wall collision section, so I'm guessing there's something wrong with the actual collision code.
code:
View.Set ("offscreenonly")
const RADIUS : int := 5
const NUM_BALLS : int := 3
var x, y, dx, dy, clr : array 1 .. NUM_BALLS of int
var box_x1, box_x2, box_y1, box_y2 : int := 0
var barX, barY, button, left, middle, right : int
var barCreator := true
var a, b : int := 0
var c := false
var d := false




for i : 1 .. NUM_BALLS
    x (i) := Rand.Int (RADIUS, maxx - RADIUS)
    y (i) := Rand.Int (RADIUS, maxy - RADIUS)
    dx (i) := Rand.Int (-5, 5)
    dy (i) := Rand.Int (-5, 5)
    clr (i) := Rand.Int (1, 15)
end for

loop
    %Outer Boundary Collision
    for i : 1 .. NUM_BALLS
        if x (i) + dx (i) < RADIUS or
                x (i) + dx (i) > maxx - RADIUS then
            dx (i) := -dx (i)
        end if
        if y (i) + dy (i) < RADIUS or
                y (i) + dy (i) > maxy - RADIUS then
            dy (i) := -dy (i)
        end if

        %Incompleted Wall Collision
        if whatdotcolour (x (i), y (i)) = red or whatdotcolour (x (i), y (i)) = green then
            return
        end if

        %Completed Wall Collision
        if x (i) + dx (i) >= box_x1 and x (i) + dx (i) <= box_x2 and y (i) >= box_y1 and y (i) <= box_y2 and whatdotcolour (x (i), y (i)) = blue then
            dx (i) *= -1
        end if

        if y (i) + dy (i) >= box_y1 and y (i) + dy (i) <= box_y2 and x (i) >= box_x1 and x (i) <= box_x2 and whatdotcolour (x (i), y (i)) = blue then
            dy (i) *= -1
        end if

        x (i) := x (i) + dx (i)
        y (i) := y (i) + dy (i)

        %Draw Ball
        Draw.FillOval (x (i), y (i), RADIUS, RADIUS, black)
    end for
View.Update
    delay (10)
    cls
    %Wall Creation
    Mouse.ButtonChoose ("multibutton")
    Mouse.Where (barX, barY, button)
    left := button mod 10           % left = 0 or 1
    middle := (button - left) mod 100       % middle = 0 or 10
    right := button - middle - left         % right = 0 or 100

    if barCreator = true then

        if left = 1 and /*barX <= maxx div 2 and barX >= 1 and*/ whatdotcolour (barX, barY) not= blue then
            button := 0
            box_x1 := barX
            box_x2 := barX
            box_y1 := barY
            box_y2 := box_y1 + 10
            if (box_x1 + a) <= maxx then
                c := true
            else
                c := false
            end if
            if (box_x1 - b) >= 0 then
                d := true
            else
                d := false
            end if
        end if
    end if

    if c = true then
        barCreator := false
        a += 3
    end if
    if d = true then
        barCreator := false
        b += 3
    end if

    if box_x1 + a >= maxx then
        Draw.FillBox (box_x1 + a, box_y1, box_x2, box_y2, blue)
    else
        Draw.FillBox (box_x1 + a, box_y1, box_x2, box_y2, red)
    end if

    if box_x1 - b <= 0 then
        Draw.FillBox (box_x1 - b, box_y1, box_x2, box_y2, blue)
    else
        Draw.FillBox (box_x1 - b, box_y1, box_x2, box_y2, green)
    end if

   
end loop


: