2D Ball Physics and Collisions

Blitz3D Forums/Blitz3D Programming/2D Ball Physics and Collisions

Head(Posted 2006) [#1]
Hi,

first sorry for my bad english *g*

I need a 2D ball collision thats simulate a working "bounce" on every shape. But with no friction, just a ball with constant speed, but with realistic reflect. On 0-360° Walls and circles, half-circles etc. like in a pinballgame, but without friction, gravity, etc...

I found something long time ago but its does not work correct. My math is not better than my english lol...

Anyone have an example? Or a little source for me? I looked at so many mathsites, but i dont understand the theory :(

Thank you =)
(i hope someone understand my text lol)


b32(Posted 2006) [#2]
A way to do it is to scan around the shape that you want to check for collisions. If you have a ball, you could scan around it in a circle.
for i = 0 to 360
coll_pix_x = cos(i)
coll_pix_y = sin(i)
next
For every pixel, check if it has the background color. If not, a collision has occured.

If you found a colliding pixel, you could calculate the angle between this pixel and the object using Atan2:
oldangle = Atan2(coll_pix_x - obj_x, coll_pix_y - obj_y)

With this angle, you could calculate a new angle:
newangle = -oldangle - 90

And with this new angle, you can calculate the new velocity of the ball:
vx# = cos(newangle)
vy# = sin(newangle)

Exit the loop and move the ball using:
x = x + vx
y = y + vy

If you have an irregular shape you want to check, there is a floodfill routine in the archives. You can modify it so, that it stores where the boundries were, that stopped the floodfill. Floodfill your objects image background at the start of the program and store all 'boundry coordinates' in a type. In the above code, replace the circle checking routine by a For .. Each loop.


Head(Posted 2006) [#3]
many thanks.. this sounds good.. i wanna try it now =)
hope it works, but i understand all your tips =) thx again ...

Edit:
Ok, the collision works fine.. but the "bounce" is wrong. Its just work on one wall and on the other, the ball moves on the line, and then behind it :(


Stevie G(Posted 2006) [#4]
@ Head,

I don't use alot of 2d stuff but this is how I would do it ...

Make a proxy collision map for the lanscape which is not visible to the user. For each of the edges of the landscape colour this with a thick edge ( at least as thick as the fastest speed the ball can travel ) in a ( say red ) colour which represents the angle that that edge points, in effect it's collision normal.

Lets say you want to be accurate to 32 angles. Color 5,0,0 represents 0 degrees and color 160,0,0 represents 355 degrees. If your using tiles then you'll need to have a proxy collision tile for each.

A naff picture done in paint to show you what I mean.



When checking collisions get the red element of the pixel collided and convert this to an angle. Assume ball has a velocity of Vx#, Vy# so from this you can determine the reflection vector.

const BallRadius# = 8.0

;check 8 directions at 45 degree intervals
for CheckAngle = 0 to 7
  cx# = Ballx + BallRadius * cos( CheckAngle * 45 )
  cy# = Bally + BallRadius * sin( CheckAngle * 45 )
  ;RedColor = {read pixel at cx, cy and get red element}

  CollisionAngle# = ( ( RedColor-5) / 5 ) * ( 360.0 / 32.0 )
  ;get collision normal vector 
  Nx# = cos( CollisionAngle )
  Ny# = sin( CollisionAngle )

  ;project velocity onto collision normal vector
  VdotN# = Vx * Nx + Vy * Ny
  ;calculate normal force
  Nfx# = -2.0 * Nx * VdotN
  Nfy# = -2.0 * Ny * VdotN
  ;add normal force to velocity vector
  Vx = Vx + Nfx
  Vy = Vy + Nfy

next


Hopefully I've explained this enough? This will work but involves a bit of pre-processing.

Stevie


Head(Posted 2006) [#5]
ok, thx again.. i will try this one.. oh damn i hate math *g*


b32(Posted 2006) [#6]
Here is what I tried:

The bouncing back angle is not quite what it should be, my maths are not too good. :(


Stevie G(Posted 2006) [#7]
Here's Bram's adapted to include the correct maths as mentioned above. It seems to work well for every angle.

Stevie




AJirenius(Posted 2006) [#8]
Just a small question, is the collisionwalls to be 2D as well? If that's the case I would probably go with scanning dots around the ball. Doesn't have to be lots and lots of scans. A small pinballball could have an array of 24 points. Noone would ever see any difference and it would be very fast. (no use of sin or cos in the actual checkings)


Stevie G(Posted 2006) [#9]
@ AJirlenius, in the version I posted there are only 12 checks around the ball.

On modern hardware Cos and Sin are very fast so I see no reason for a lookup. You would have to have thousands being processes each frame to even notice a tiny bit of slowdown.

Stevie


Head(Posted 2006) [#10]
OK, it works.. I testet it on Walls with different Angles > and < 90° works fine...

But one question.. i dont understand the Speed. I wanna change the speed of the ball, but the only effect is that the ball will be faster and faster after collision oO


b32(Posted 2006) [#11]
Stevie, that works very nice! :D
"Head", the part that moves the ball is
x=x+vx
y=y+vy
The part before that, the "For CheckAngle" loop, is the part that checks for collisions. The ball takes 1px big steps now. If you make those steps too big, it will 'miss out' on collisions. The way to avoid that, is to repeat both the collision checking and the movement a few times after each other: move the ball 1 px, then check it, then moved 1 px again, then checked again etc.


Head(Posted 2006) [#12]
thx u all for ur help... i used "x=x+vx+speed" and not "x=x+vx*speed" lol
now i try it with the 1px per loop method... but at the moment i need a break.. my brain is emty at the moment :D


Stevie G(Posted 2006) [#13]
@ Head.

The velocity is the speed, albeit defined as a vector rather than scalar so adding it to the x position makes no logical sense.

To set a new speed at the start

Global Speed# = 2.0

and change these lines ...

newd# = Rand(0, 360)
;set velocities (direction ball)
vx = Cos(newd) * Speed
vy = Sin(newd) * Speed

At the moment the Speed is implied as 1.0.

Stevie