Samuel
Samuel

Reputation: 597

Simple bouncing ball in haskell keeps bouncing higher

So, I did a simple simulation of a bouncing ball to learn haskell. The ball is supposed to bounce against the image borders and to be accelerated downward by gravity.

The problem is that the ball is "magically" bouncing higher as time passes. I would expect it to keep the same maximum height instead.

I suspect there is something wrong with bounce and not with move because bounce "teleports" the ball back inside the frame, which is not physically accurate. I tried different way to simulate a correct behavior but could not find anything working right.

What would be a correct way to do this?

Here is the code, running on CodeWorld:

main = simulationOf initial step draw

data World = Ball Point Vector

radius = 40
border = 250 - radius
g = -500

initial (x:y:vx:vy:_) = Ball (400*x  - 200, 400*y  - 200)
                             (400*vx - 200, 400*vy - 200)

step t world = bounce (move t world)

move t (Ball (x,y) (vx,vy)) = Ball (x + vx*t, y + vy*t) (vx, vy + g*t)

bounce (Ball (x,y) (vx,vy)) = Ball (nx,ny) (nvx, nvy)
  where nx  = fence (-border) border x
        ny  = fence (-border) border y
        nvx = if nx /= x then -vx else vx
        nvy = if ny /= y then -vy else vy

fence lo hi x = max lo (min hi x)

draw (Ball (x,y) _) = translate x y (solidCircle radius)

Upvotes: 2

Views: 523

Answers (2)

leftaroundabout
leftaroundabout

Reputation: 120741

This is a well-known artifact of the algorithm you're using to integrate the movement's differential equation.

The "real physics" is (I will only discuss the y component)

y/∂t = v(t)
v/∂t = g

You model this by a discrete sequence of heights and velocities

yi = yi − 1 + vi − 1 ⋅ Δt
vi = vi − 1 + g ⋅ Δt

This sure resembles the differential equations, just written as difference quotients – but it's not the same thing (except in the limit Δt → 0): in reality, the velocity itself changes during the time step, so it's not quite correct to alter the position just according the constant v value before that time step. Simply ignoring that complication is an approximation called Euler's method, and it's known to suck rather badly.

The much more accurate standard alternative is the fourth-order Runge-Kutta method, give that a try.

n.m.'s points about the bouncing is also valid, though to do it really properly you should calculate the exact time of impact, to neither neglect too much acceleration nor get too much that actually never happened.

Upvotes: 4

n. m. could be an AI
n. m. could be an AI

Reputation: 120031

Suppose the ball hits the ground exactly in the middle of the quantum of time. In reality (or rather in the frictionless "reality") the absolute value of velocity stays the same in the beginning and in the end of the quantum, but in your model it increases.

One should handle acceleration in bounce. The simplest possible way to do that is to do this:

move t (Ball (x,y) (vx,vy)) = Ball (x + vx*t, y + vy*t) (vx, vy)

step t world = bounce (move t world) t
bounce (Ball (x,y) (vx,vy)) t = Ball (nx,ny) (nvx, nvy) 
   ...
   nvy = if ny /= y then -vy else vy + g * t

The velocity won't increase during the bounce.

This is still not entirely accurate, the velocity still creeps up, but slower.

Upvotes: 2

Related Questions