Help with "make ball fall in hole" code
Miscellaneous Forums/General Discussion/Help with "make ball fall in hole" code
Hiya, I'm wondering how to make a ball fall in a hole when viewed from above.
Say the ball is rolling towards the hole and may go right in, miss totally or roll over the edge a bit.
So I thought about:
a) monitoring a single pixel in the middle of the ball (representing the bottom centre of the ball) and doing a pixel perfect collision with the hole and saying that when they collide, the bottom of the ball is over the hole and thus it's in. But this wouldn't be very realistic as the ball still needs to move to the centre of the hole (i.e. off the rim). To make things simple I could completely HALT the ball (to avoid having to program it skipping out of the hole if the speed is too great) and then set it's speed/direction up to point to the middle of the hole. I could do this by looking at the dx and dy from the centre of the ball to the centre of the hole.
b) monitor a ring of pixels round the edge of the ball. The when they are all over the hole, make it fall it. However, this may lead to the ball rolling across a rim and not going in because some outer pixels were not over the hole even though the middle centre of the ball was clearly over the hole. So this would feel like bad collision detection. Not sure about this one.
Any other ideas? Thanks in advance :-)
c) Use a smaller ring of points (maybe even just 4). When they are all in the hole the ball falls in. When one is in then the path of the ball deviates slightly. If this leads to them all being in the hole the ball falls in.
OK thanks i'll try that unless there are any more offers. Actually I thought of the smaller ring earlier. Wonder how to code the deviation though...
If point1_collide then deviatex:+2
if point2_collide then deviatey:+2
?
I think it might need 8 points at least.
Round hole?
Check the distance from the center of the ball to the center of the hole (distance formula.) If the radius of the ball plus the distance from the center of the hole is less than or equal to the radius of the hole, you have fallen in the hole.
If the distance from the center of the ball to the center of the hole is less than the radius of the hole but not "fallen in," treat the motion of the ball as a vector and deviate the direction and movement of the vector to account for falling into the hole. Choose a deviation that feels right for your program. It could be proportional, exponential, whatever.
Yes, /agree with above, just look at the distance the ball is from the hole. It's that simple.
How you can get the ball to "ride the rim" of the hole will be more complicated. Are you writing a golf game?
You can get a nice "ride the rim" effect if you choose a deviation scheme that has virtually no deflection near the outer edge of the hole, and an extreme deflection toward the center. An exponential formula would probably be closest without too much tweaking.
wmd: thanks. OK I'm gonna try this out now. I get the idea of an exponential deflection, may have some maths trouble applying the deflection to the ball's vector, well see...
andy_mc: minigame :-)
Yeah.
If the Ball's centre is within the hole's radius then rotate the ball's vector towards the vector from ball centre to hole centre.
The rate/amount you rotate the vector by is based on the distance from ball centre to hole centre. Something like:
ball_delta_angle = angle_from_ball_vec_to_hole_vec * ((hole_radius - ball_to_hole_distance) / hole_radius)
This is just off the top of my head so...
I think if things are done right, this should allow the ball to ride around the rim and even 'escape the hole's gravity' and miss, if the ball has sufficient velocity and/or trajectory angle.
That's cool. I've been thinking of writing a crazy golf game, but this bits been causing me head aches.
If Distance(Ball_Center, Hole_Center) < Hole_Radius
If Distance(Ball_Center, Hole_Center) < Hole_Radius-Ball_Radius
' Ball is completely within the hole.
Else
' Ball is more than halfway over the hole.
' Calculate how much of the ball is over the hole, minus the half that doesn't matter.
Portion_Over_Hole = Hole_Radius - Distance(Ball_Center, Hole_Center)
' Convert to range 0..1 where 0 means the center of the ball is at the edge of the hole, and 1 means the ball is entirely in the hole, just touching the edge.
Tween# = Portion_Over_Hole / Ball_Radius
' Apply cosine to Tween# to model how the ball will fall in faster as more of the ball enters the hole due to the increasing angle of the edge of the ball relative to the edge of the hole.
Tween# = 1.0 - Cos(90.0*Tween#)
' Magic happens here.
EndIf
Else
' Ball is safely outside the hole.
EndIf
I haven't quite done all the work for you, but where the magic happens, you need to take that Tween# value, (which will be between 0 and 1, moving more quickly towards 1 as the ball moves further over the edge, using cosine which would be the physically correct way to do it) and use that to scale a force vector which points at the center of the hole, which you would add to the ball's vector. This will cause the ball to slingshot around the edge of the hole if you almost get it in, and you can just stop adding forces and make it dissapear if it ever makes it all the way into the hole.
Big10p: Yeah cool, that would work.
sswift: yeah thanks a good start, appreciated!
havent read everything but:
I base everything on "world space" direction- if the ball is within <x> distance of the hole- <x> distance actually being the radius of the hole, then "pull" the ball towards the hole, like gravity pulls matter towards the earth?
the closer to the centre of the hole, the more the pull- also, damp the original speed.
that should give a nice result.
Cygnus: Yep thanks. I figured that out too, it's just translating that into actual maths (and then code) that's the "biatch". I've been reading up on vectors and matrix multiplication all day as I haven't done it for like 10 years.
You don't need any matrix multiplications. You just have to add vectors.
Don't you have my sprite system? Look at how I do the physics in there. :-)
Yep - you don't need to touch matrices for this. What part of the maths are you finding hard. I guess you already know how to rotate a vector?
cos_rot# = Cos(rotation_angle#)
sin_rot# = Sin(rotation_angle#)
new_x# = (x# * cos_rot#) - (y# * sin_rot#)
new_y# = (y# * cos_rot#) + (x# * sin_rot#)
Big:
You don't need to rotate a vector for this either. :-)
' Calculate normal which points from center of ball to center of hole.
Nx# = Ball_X#-Hole_X#
Ny# = Ball_Y#-Hole_Y#
D# = Sqr(Nx#*Nx# + Ny#*Ny#)
Nx# = Nx# / D#
Ny# = Ny# / D#
' Now this is where it gets tricky. I'm not sure how much force this vector should have, but I'm gonna take a wild guess from what I remember about my ball bouncing code, and say it's 2x the velocity of the ball.
' Why 2x? Consider what would happen in a completely elastic collision if a ball struck the opposite side of the hole after passing over it quickly. It would change direction 180 degrees. If you only added 1x the force in the opposite direction the ball would simply stop moving. We need it to dstart moving in the opposite direction, so we add 2x the force.
' But even though that's true of bounces, I'm just guessing that this is the right amount of force to apply to this case. I think it's right though. A roll around an edge is like millions of tiny bounces.
' Calculate force vector pointing toward center of hole.
Ball_Velocity# = Sqr(Ball_Vx#*Ball_Vx# + Ball_Vy#*BallVy#)
HoleForce_Vx# = Nx# * Ball_Velocity#*2.0
HoleForce_Vy# = Ny# * Ball_Velocity#*2.0
' Scale force vector by Tween# we calculated earlier, so ball is pushed towards the center of the hole less when it's only over the edge slightly.
HoleForce_Vx# = HoleForce_Vx# * Tween#
HoleForce_Vy# = HoleForce_Vy# * Tween#
' Add force pointing toward center of hole to balls velocity vector. Add less force if less time has passed this frame.
Ball_Vx# = Ball_Vx# + HoleForce_Vx#*Seconds#
Ball_Vy# = Ball_Vy# + HoleForce_Vy#*Seconds#
' Adjust ball's position according to it's final velocity and the amount of time passed this frame.
Ball_X = Ball_X + Ball_Vx*Seconds#
Ball_Y = Ball_Y + Ball_Vy*Seconds#
yeah the matrix stuff was for the ball bouncing off an angled surface and besides I wanted to relearn something that you confessed to not being good at ;-p
Big10p: Yep know that stuff thanks. I've also been using the dot product and the cross product and ArcTan today, bit like looking through the "round window".
well I sorted in the end thanks to all your help. This seems to work fine. The ball slingshots off nicely or goes into the hole. It uses some of my own classes but it should be obvious what they are doing:
'Is the ball teetering on the edge of the hole or in the hole?
'Remember Ball and Hole coords are midhandled.
Local dist:TLine = TLine.Create(BallX,BallY,HoleX,HoleY)
dist.CalcLength()
If dist.Length<=HoleRadius Then
'Is the ball 100% in the hole?
If dist.Length<=HoleRadius-BallRadius Then
BallXSpeed=0
BallYSpeed=0
MinigameFadeOut.Start()
'Play a sound
GameGrid.Channels.PlayGameSound(BallInHoleSound)
InHole = 1
Else
'OK, the ball is teetering so deflect it's path towards the middle of the hole.
'This may not make it go in, it may skip over it.
'How much of the ball is over the hole minus the inner half that doesn't matter.
Local OverHole:Double = HoleRadius-dist.Length
'Convert to a range of 0 to 1
Local tween:Double = OverHole/HoleRadius
'Make it fall in faster near the middle.
tween = 1.0 - Cos(90.0*tween)
'Make a Vector pointing from the ball to the hole.
Local Pull:TVector = TVector.CreateFromPoints(BallX,BallY,HoleX,HoleY)
'Make smaller
Pull.Normalise()
Local force! = 1.0 'tweak if need be
pull.Scale(force*tween)
BallXSpeed:+ pull.X*Delta
BallYSpeed:+ pull.Y*Delta
EndIf
EndIf
Actually I haven't used the ball's speed to alter the force, merely it's distance from the centre but it seems to work fine anyway.
[EDIT] OK I added that in too for the hell of it and will now test at different speeds.
[EDIT]Problem with using the balls speed to modify the force. If it stops rolling over the edge it will just stay there so I added a gravity component to the force which is always there even if the ball is not moving.