[Tutorial]Circular Collision Data
Author |
Message |
Cervantes
|
Posted: Sun May 30, 2004 5:57 pm Post subject: [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.
Homer_Simpson's approach
He uses angles, velocities, and weights. I took the basis of this code and tried to make my own Slime Volleyball program, one where the ball bounces correctly off the walls. I found this exceedingly difficult, and gave up. Cicular collision works well, but I find it difficult to do much else.
thoughtful's approach
He uses the method I like, x, y, vx, and vy. vx and vy are the x velocity, and y velocity. This style makes for easy bouncing off of a flat surface (a wall, for example). Simply make the vx or vy value negative, depending on where the wall is. thoughtful's collision between circles (in this case, pool balls) is flawless for this type of program: for when energy transfer is not 100%. I tried several times to modify his code into my slime volleyball program or also into a pong program where the paddles are circles, and failed. The collision just wasn't right.
rhomer's approach
This approach is nice and simple. It uses the x, y, vx, and vy style, and works well for the most part. The main problem is that the ball tends to go inside the player and do some wild things, or possibly even go through the player.
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.
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.
code: |
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 <= 0 + ball.radius or ball.x >= maxx - ball.radius then
ball.vx *= -1
end if
if ball.y <= 0 + ball.radius or 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. |
|
|
|
|
|
Sponsor Sponsor
|
|
|
Tony
|
Posted: Sun May 30, 2004 7:11 pm Post subject: (No subject) |
|
|
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 |
Tony's programming blog. DWITE - a programming contest. |
|
|
|
|
Cervantes
|
Posted: Sun May 30, 2004 9:46 pm Post subject: (No subject) |
|
|
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.
tony wrote: 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 |
|
|
|
|
|
TheZsterBunny
|
Posted: Tue Feb 08, 2005 8:27 pm Post subject: (No subject) |
|
|
Hey,
Nice effect.
How 'bout a tutorial on gravity fields? this looks like something worth learning.
well, the concept anyways.
-Z |
|
|
|
|
|
evildaddy911
|
Posted: Sun Oct 16, 2011 12:11 pm Post subject: 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
|
|
|
|
|
|
|
smool
|
Posted: Thu Dec 08, 2011 10:16 am Post subject: 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? |
|
|
|
|
|
|
|