Simple Gravity (Physics)

Having a complete brain fart. I’d like to move something along the Z axis following a parabolic path due to gravity.

Here’s what I have so far:

dz = (zVelocity0 * timeElapsed + 0.5 * Globals.GRAVITY * timeElapsed * timeElapsed) - 
(zVelocity0 * (timeElapsed - deltaTime) + 0.5 * Globals.GRAVITY * (timeElapsed - deltaTime) * (timeElapsed - deltaTime))

pos.setZ(pos.getZ() + dz)

I’m using the equation:

z' = z0 + v0 * t + 1/2 * a * t^2

where z0 = 0 and v0 = zVelocity0

Essentially it’s this - When I start to fall, start keeping track of how much time has passed since I started falling. During each update, find the position on the parabola at my current elapsed time and also at the time of my last update. Subtract the two and move myself the difference. How can I optimize this so it’s not a ton of multiplications and stuff?

Just apply the formula you presented in your post, no extra multiplications. The trick is to distinguish between absolute time (‘t’), time passed since start of simulation (‘tsim’), and time passed since last simulation step (‘elapsed time’). You need to feed the ‘delta t’ into your formula.

import time

z0 = np.getZ()     # initial z position
vz0 = 20.0         # initial z velocity
g = -9.81          # gravity
t0 = time.time()   # initial time

for i in range(20):
  t = time.time()  # current time
  tsim = t - t0    # time passed since start of simulation
  z = z0 + vz0 * tsim + 0.5 * g * tsim * tsim
  print tsim, z
  time.sleep(0.2)  # emulate 'frames'

If running from within a Panda3D task you can replace the second call to time.time() with adding the ‘elapsed time’ (elapsed since LAST frame, not since simulation start!) with something like t = t0 + elapsedTime.

The downside of this approach is that you have to keep track of the time when something starts to fall down (t0), in oder to be able to find the time passed (tsim).

Another approach would be to “integrate” the object’s movement yourself. Here you don’t need to keep track of any (absolute or relative) time. But you need to keep track of the current velocity of an object, e. g. by storing this value on your NodePath via setPythonTag:

x --> x + dx
  with: dx = v * dt

v --> v + dv
  with: dv = g * dt
z = 100
v = 10
g = -9.81

for i in range(10):
  global v
  global z
  dt = 0.2     # elapsed time since last frame
  dv = g * dt
  v = v + dv
  dz = v * dt
  z = z + dz
  print z, v

The downside of this approach is that it won’t produce exact values like the first approach. The values get worse the bigger your timestep is (framerate!). The smaller the timesteps the better the results. You cold, for example, break down the elapsed time into tiny steps of 0.01 seconds.