Example #1
0
void game_tick( GameThreadSockets & gsockets, GameState & gs, SharedRenderState & srs, unsigned int now ) {
  Ogre::Quaternion o;
  uint8_t b;
  zstr_send( gsockets.zmq_input_req, "mouse_state" );
  char * mouse_state = zstr_recv( gsockets.zmq_input_req );
  parse_mouse_state( mouse_state, o, b );
  free( mouse_state );

  uint8_t w, a, s, d, spc, alt;
  zstr_send( gsockets.zmq_input_req, "kb_state" );
  char * kb_state = zstr_recv( gsockets.zmq_input_req );
  parse_kb_state( kb_state, w, a, s, d, spc, alt );
  free( kb_state );

  // yaw 0 looks towards -Z
  float yaw = o.getYaw().valueRadians();
  Ogre::Vector3 xp( cosf( yaw ), 0.0, -sinf( yaw ) );
  Ogre::Vector3 yp( -sinf( yaw ), 0.0, -cosf( yaw ) );

  float speed = 10.0f;
  if ( w ) {
    srs.position += speed * yp;
  }
  if ( s ) {
    srs.position -= speed * yp;
  }
  if ( a ) {
    srs.position -= speed * xp;
  }
  if ( d ) {
    srs.position += speed * xp;
  }
  if ( spc ) {
    srs.position[1] += speed;
  }
  if ( alt ) {
    srs.position[1] -= speed;
  }
}
Example #2
0
void game_tick( unsigned int now, GameState & gs, SharedRenderState & rs ) {
  // get the latest mouse buttons state and orientation
  zstr_send( gs.zmq_input_req, "mouse_state" );
  char * mouse_state = zstr_recv( gs.zmq_input_req );
  Uint8 buttons;
  Ogre::Quaternion orientation;
  parse_mouse_state( mouse_state, orientation, buttons );
  free( mouse_state );

  // at 16 ms tick and the last 10 orientations buffered, that's 150ms worth of orientation history
  gs.orientation_history[ gs.orientation_index ].t = now;
  gs.orientation_history[ gs.orientation_index ].o = orientation;
  gs.orientation_index = ( gs.orientation_index + 1 ) % ORIENTATION_LOG;

  // oldest orientation
  unsigned int q1_index = gs.orientation_index;
  // NOTE: the problem with using the successive orientations to infer an angular speed,
  // is that if the orientation is changing fast enough, this code will 'flip' the speed around
  // e.g. this doesn't work, need to use the XY mouse data to track angular speed
  // NOTE: uncomment the following line to use the full history, notice the 'flip' happens at much lower speed
  q1_index = ( q1_index + ORIENTATION_LOG - 2 ) % ORIENTATION_LOG; 
  Ogre::Quaternion q1 = gs.orientation_history[ q1_index ].o;
  Uint32 q1_t = gs.orientation_history[ q1_index ].t;
  Ogre::Quaternion omega = 2.0f * ( orientation - q1 ) * q1.UnitInverse() * ( 1000.0f / (float)( now - q1_t ) );
  omega.ToAngleAxis( gs.smoothed_angular_velocity, gs.smoothed_angular );
  //  printf( "%f %f %f - %f\n", gs.smoothed_angular.x, gs.smoothed_angular.y, gs.smoothed_angular.z, gs.smoothed_angular_velocity.valueDegrees() );
  rs.smoothed_angular = gs.smoothed_angular;

  if ( ( buttons & SDL_BUTTON( 1 ) ) != 0 ) {
    if ( !gs.mouse_pressed ) {
      gs.mouse_pressed = true;
      // changing the control scheme: the player is now driving the orientation of the head directly with the mouse
      // tell the input logic to reset the orientation to match the current orientation of the head
      zstr_sendf( gs.zmq_input_req, "mouse_reset %f %f %f %f", rs.orientation.w, rs.orientation.x, rs.orientation.y, rs.orientation.z );
      zstr_recv( gs.zmq_input_req ); // wait for ack from input
      // IF RENDER TICK HAPPENS HERE: render will not know that it should grab the orientation directly from the mouse,
      // but the orientation coming from game should still be ok?
      zstr_sendf( gs.zmq_render_socket, "# %s", "1" );
      // IF RENDER TICK HAPPENS HERE (before a new gamestate):
      // the now reset input orientation will combine with the old game state, that's bad
    }
  } else {
    if ( gs.mouse_pressed ) {
      gs.mouse_pressed = false;
      // changing the control scheme: the head will free spin and slow down for a bit, then it will resume bouncing around
      // the player looses mouse control, the game grabs latest orientation and angular velocity
      // the input thread was authoritative on orientation until now, so accept that as our starting orientation
      rs.orientation = orientation;
      gs.rotation_speed = gs.smoothed_angular_velocity;
      gs.rotation = gs.smoothed_angular;
      zstr_sendf( gs.zmq_render_socket, "# %s", "0" );
      // IF RENDER TICK HAPPENS HERE (before a new gamestate): render will pull the head orientation from the game state rather than input, but game state won't have the fixed orientation yet
    }
  }

  if ( rs.position.x > gs.bounce || rs.position.x < -gs.bounce ) {
    gs.direction.x *= -1.0f;
  }
  if ( rs.position.y > gs.bounce || rs.position.y < -gs.bounce ) {
    gs.direction.y *= -1.0f;
  }
  Ogre::Vector2 delta = gs.speed * ( (float)GAME_DELAY / 1000.0f ) * gs.direction;
  if ( !gs.mouse_pressed ) {
    if ( gs.rotation_speed.valueDegrees() == 0.0f ) {
      rs.position.x += delta.x;
      rs.position.y += delta.y;
    }
    //    printf( "game tick position: %f %f\n", rs.position.x, rs.position.y );

    // update the orientation of the head on a free roll
    // gs.rotation is unit length
    // gs.rotation_speed is in degrees/seconds
    // NOTE: sinf/cosf really needed there?
    gs.rotation_speed *= 0.97f;
    if ( gs.rotation_speed.valueDegrees() < 20.f ) {
      gs.rotation_speed = 0.0f;
    }
    float factor = sinf( 0.5f * Ogre::Degree( gs.rotation_speed * GAME_TICK_FLOAT ).valueRadians() );
    Ogre::Quaternion rotation_tick(
      cosf( 0.5f * Ogre::Degree( gs.rotation_speed * GAME_TICK_FLOAT ).valueRadians() ),
      factor * gs.rotation.x,
      factor * gs.rotation.y,
      factor * gs.rotation.z );
    rs.orientation = rotation_tick * rs.orientation;
  } else {
    // keep updating the orientation in the render state, even while the render thread is ignoring it:
    // when the game thread resumes control of the head orientation, it will interpolate from one of these states,
    // so we keep updating the orientation to avoid a short glitch at the discontinuity
    rs.orientation = orientation;
  }
}