Skip to content

Physics

chino edited this page Jan 12, 2013 · 3 revisions

Timers

SDL GetTicks is called from routines in timer.* which is used by the game.

This is also used to update framelag variable (below).

framelag

Number of seconds passed since last frame.

This variable is used in all step calculations.

See CalculateFramelag() in oct2.c

framelag multiplier / real_framelag

The game physics seems to have been speeded up by multiplying seconds passed by 71.

We're not sure why this was done instead of tweaking other globals which define rate of movement such as GLOBAL_SCALE (see below).

There may be times when you want to know the real time passed in seconds in which case you should use real_framelag variable instead.

GLOBAL_SCALE

This variable is used in many calculations.

It's most likely the unit of measurement used for the coordinate system (need to document this).

Collisions

General Order

General order of collision checking:

  1. test for bsp level collision and respond
  2. test enemy collision and respond
  3. test for bsp level collision again and respond (I guess so the enemy doesn't push us outside)
  4. test background object collision and respond

An old function from PXR which tried to re-implement bsp collision in ruby:

# See this urls for an updated version:
# https://github.com/chino/pxr/blob/master/scenes/default.rb

def collide_body_with_plane body, node, collision_point

  # forsaken globals
  global_scale = 0.25
  collision_fudge = 10 * global_scale

  # from OneGroupPolyCol in collisions.c
  # enemy collision detection here would detect and respond
  # background object collision detection as well
  # but bg colls would not run the following code
  # the following code code runs if RayCollide hits bsp walls
  # but again not if bg col happens
  e = collision_point + body.velocity
  nDOTe =   e.dot(node.normal) + node.distance
  d = nDOTe.abs + collision_fudge
  dn = node.normal * d
  target_pos = e + dn # position after sliding

  # from BackgroundCollide in collisions.c
  epos = collision_point
  dv = epos - body.pos
  dist_bg = dv.length
  # skipping all the group portal detection
  # further down in BackgroundCollide response
  dv = body.velocity.normalize
  impact_dotp = -dv.dot(node.normal)
  impact_offset = impact_dotp != 0 ? collision_fudge / impact_dotp : 2 * dist_bg
  if dist_bg > impact_offset
    epos -= dv * impact_offset
  else
    epos = body.pos
  end

  # from ProcessShips in ships.c 
  body.pos = epos
  body.velocity = target_pos - body.pos

end

Note: That earlier up epos -= dv * impact_offset seems to be some kind of collision fudge that causes the player to slightly bounce off the surface. This causes a pretty nasty bug with players on lower frame-per-second systems where the player bounces so strongly off the walls that they could get stuck in a tight hall way bouncing back and forth uncontrollably. I also noticed that strangely moving slower in PXR gives you a larger bounce back.. Look in Forsaken source for: ObjForceExternalOneOff( Obj, &BumpForce );

Levels

Forsaken uses BSP trees for determining if something is inside or outside of a level group. See also: Rendering

This technique is generally called a bounding volume bsp tree.

You can see the general idea ported from C to Ruby in PXR.

In there point_inside_tree? is a recursive function which checks if a given point is inside the bsp tree.

There is also the ray_collide_* family of functions used for determining where a ray collides with the level.

Note: A general concept to notice that in collide we don't stop on the first plane we collide with. Instead it should run for at least three iterations where each face you collide with is resolved by moving you to the collision point of the ray test. This I presume is the largest amount of faces you could collide with at any given time (colliding with the inside corner of a box). I cannot think of any situation in any level that would let you hit 4 faces of a bsp tree at the same time..

There is also some details in detecting level group portals which is not yet documented.

Feeler Rays

Nine rays shoot out of the biker and are used to test for collisions against enemies and background objects.

Clone this wiki locally