
-----------------------------------
Cervantes
Sun May 30, 2004 5:57 pm

[Tutorial]Circular Collision Data
-----------------------------------
One of the greatest challanges I have faced in my programming life is getting two circles to bounce off each other as they would in real life: obeying the laws of physics.  There have been many attempts at solving this riddle.
Cervantes' Approach
A while back tony taught me how to create gravity fields.  When you have a gravity field (a spot that sucks whatever objects towards it) it is easy to reverse its effect, creating a repulsing field.  :wink:
Today I had a revelation: this could be used as a form of circular collision. 
I was using it in a slime volleyball setting, so I'm going to be talking in terms of players and balls.  
If the ball has collided with the player (determine using the distance formula) then make the player a repulsing gravity field.  Also, have a maximum speed for the ball's velocity, so as to not let it get out of control.  


setscreen ("offscreenonly")
var player :
    record
        x, y, vy, GFstrength, GFdist, GFforce, GFangle : real %GF = Gravity Field -- Collisions between ball and players in this
        radius, score : int                         %uses repulsing gravity fields
        jump : boolean
    end record

player.x := maxx div 2
player.y := maxy div 2
player.vy := 0
player.GFstrength := 3
player.radius := 40
player.score := 0
player.jump := false

var ball :
    record
        x, y, vx, vy : real
        radius : int
    end record

ball.x := 100
ball.y := 100
ball.vx := 0
ball.vy := 0
ball.radius := 12

var keys : array char of boolean
const max_speed := 7
loop


    ball.x += ball.vx
    ball.y += ball.vy

    if ball.x = maxx - ball.radius then
        ball.vx *= -1
    end if
    if ball.y = maxy - ball.radius then
        ball.vy *= -1
    end if

    if ball.vx > max_speed then
        ball.vx := max_speed
    elsif ball.vx < -max_speed then
        ball.vx := -max_speed
    end if
    if ball.vy > max_speed then
        ball.vy := max_speed
    elsif ball.vy < -max_speed then
        ball.vy := -max_speed
    end if

    Input.KeyDown (keys)
    if keys (KEY_LEFT_ARROW) then
        player.x -= 2
    end if
    if keys (KEY_RIGHT_ARROW) then
        player.x += 2
    end if
    if keys (KEY_UP_ARROW) then
        player.y += 2
    end if
    if keys (KEY_DOWN_ARROW) then
        player.y -= 2
    end if

    if Math.Distance (player.x, player.y, ball.x, ball.y) < player.radius + ball.radius then
        player.GFdist := Math.Distance (player.x, player.y, ball.x, ball.y) %figure out the distance between the player and the ball
        player.GFforce := player.GFstrength * (1 / player.GFdist * player.GFdist) %inverse square.  it's a gravity field thing.
        if player.x = ball.x then %this must be here or a division by 0 error could occur.  
            if ball.y > player.y then
                player.GFangle := 90
            else
                player.GFangle := 270
            end if
        else
            player.GFangle := arctand ((player.x - ball.x) / (player.y - ball.y)) %determine the angle between the player and the ball
        end if
        if ball.y < player.y then %without this, if the ball hits the underside of the player, it will
            player.GFangle += 180 %go into the player and do some wild turns, then shoot out the top somewhere.
        end if
        ball.vx += player.GFforce * sind (player.GFangle) %finally, apply the force of the gravity field to the x vector of the ball
        ball.vy += player.GFforce * cosd (player.GFangle) %apply the force of the gravity field to the y vector of the ball
    end if
    cls
    drawfilloval (round (player.x), round (player.y), player.radius, player.radius, 42)
    drawfilloval (round (ball.x), round (ball.y), ball.radius, ball.radius, blue)
    View.Update
    delay (10)

end loop
 

Please, let me know of any errors in the collision data in this program.  In this program, if the ball is moving really slowly, and it hits you (you are still) it will fire off with decent velocity away.  I haven't gotten around to trying to fix this, but I have an idea of how to.  

The methods of determining the colision data between two circles that I have seen so far all have their varying pros and cons.  I hope this new method has very few cons.  :wink:

-----------------------------------
Tony
Sun May 30, 2004 7:11 pm


-----------------------------------
not bad Cervantes - I see you advancing in your programming skillz. I'm glad that you're able to take the consept from one program and modify it to apply properly to another, but there's one major flaw.

when two balls collide, an inpulse force is created that acts only once during the brief moment two balls are in physical contact.

a force field (such as gravity, or negative gravity as in the example) on the other hand act continuely (all the time), but are just not as effective at the distance.

and while the code works since the field's activation is limited to the actual contact moment, the reasoning behind the physics model is wrong :?

-----------------------------------
Cervantes
Sun May 30, 2004 9:46 pm


-----------------------------------
true, its not an actual collision, but it works well enough.  Since the gravity field has no effect until there is a collision between the player and the ball (Math.Distance < sum of 2 radii) the ball gets repulsed quickly and it doesn't really look like its going into the player at all.

and while the code works since the field's activation is limited to the actual contact moment
it's very interesting playing slime volleyball if you take out the two if Math.Distance lines and have the repulsing gravity fields working non-stop :wink:

-----------------------------------
TheZsterBunny
Tue Feb 08, 2005 8:27 pm


-----------------------------------
Hey, 

Nice effect.

How 'bout a tutorial on gravity fields? this looks like something worth learning.

well, the concept anyways.

-Z

-----------------------------------
evildaddy911
Sun Oct 16, 2011 12:11 pm

Re: [Tutorial]Circular Collision Data
-----------------------------------
umm... you should make it so your ball cant go off the screen, i find a simple if statement works well,

[code]
if player.y < (maxy - player.radius) then
        if keys ('w') then
              player.y := player.y + 5
        end if
end if
[/code]

-----------------------------------
smool
Thu Dec 08, 2011 10:16 am

RE:[Tutorial]Circular Collision Data
-----------------------------------
Why not calculate tangent of cirlce at point of collision and use angle of incidence = angle of reflection to calculate a bounce?
