FixedLogicrateFramerateGame

Hi. I was wondering if my implementation here was more or less correct. I made a new class FixedLogicrateFramerateGame with all the methods of both FixedLogicrateGame and FixedFramerateGame and the following merge of their respective start() methods:



  public final void start() {
    LoggingSystem.getLogger().log(Level.INFO, "Application started.");
    try {
      getAttributes();
      timer = Timer.getTimer(properties.getRenderer());
      setLogicTicksPerSecond(60); //default to 60 tps
      setFrameRate(60); //default to 60 fps
     
      initSystem();
     
      assertDisplayCreated();
     
      initGame();
     
      //main loop
      while (!finished && !display.isClosing()) {
        time1 = timer.getTime();
        loops = 0;
       
        startFrame();
       
        while ((time1 - time0) > tickTime && loops < MAX_LOOPS) {
          //update game state, do not use interpolation parameter
          update(-1.0f);
          time0 += tickTime;
          loops++;
        }
       
        //If the game logic takes far too long, discard the pending
        // time
        if ((time1 - time0) > tickTime) time0 = time1 - tickTime;
       
        float percentWithinTick = Math.min(1.0f,
            (float) (time1 - time0) / tickTime);
        //render scene with interpolation value
        render(percentWithinTick);
       
        //swap buffers
        display.getRenderer().displayBackBuffer();
       
        endFrame();
       
        Thread.yield();
      }
    } catch (Throwable t) {
      t.printStackTrace();
    } finally {
      cleanup();
    }
    LoggingSystem.getLogger().log(Level.INFO, "Application ending.");
   
    display.reset();
    quit();
  }



This in itself was pretty clear to me, but where it got a little tricky was in making FixedLogicrateFramerateSimpleGame, where I had to shift around some code. In particular:
FPS code was moved from update() to render() right at the top before anything else.
So was

rootNode.updateGeometricState(tpf, true);

but with an added

if(!pause)

around it.
So it ends up as follows:

  /**
   * This is called every frame in BaseGame.start()
   * @param interpolation unused in this implementation
   * @see AbstractGame#update(float interpolation)
   */
  protected final void update(float interpolation) {
    /** If toggle_pause is a valid command (via key p), change pause. */
    if (KeyBindingManager
        .getKeyBindingManager()
        .isValidCommand("toggle_pause", false)) {
      pause = !pause;
    }
   
    /** If toggle_wire is a valid command (via key T), change wirestates. */
    if (KeyBindingManager
        .getKeyBindingManager()
        .isValidCommand("toggle_wire", false)) {
      wireState.setEnabled(!wireState.isEnabled());
      rootNode.updateRenderState();
    }
    /** If toggle_lights is a valid command (via key L), change lightstate. */
    if (KeyBindingManager
        .getKeyBindingManager()
        .isValidCommand("toggle_lights", false)) {
      lightState.setEnabled(!lightState.isEnabled());
      rootNode.updateRenderState();
    }
    /** If toggle_bounds is a valid command (via key B), change bounds. */
    if (KeyBindingManager
        .getKeyBindingManager()
        .isValidCommand("toggle_bounds", false)) {
      showBounds = !showBounds;
    }
    /** If camera_out is a valid command (via key C), show camera location. */
    if (KeyBindingManager
        .getKeyBindingManager()
        .isValidCommand("camera_out", false)) {
      System.err.println("Camera at: " +
          display.getRenderer().getCamera().getLocation());
    }
   
    if (pause) return;
    /** Call simpleUpdate in any derived classes of SimpleGame. */
    simpleUpdate();
   
  }
 
  /**
   * This is called every frame in BaseGame.start(), after update()
   * @param interpolation unused in this implementation
   * @see AbstractGame#render(float interpolation)
   */
  protected final void render(float interpolation) {
    /** Recalculate the framerate. */
    timer.update();
    /** Update tpf to time per frame according to the Timer. */
    tpf = timer.getTimePerFrame();
    /** Check for key/mouse updates. */
    input.update(tpf);
   
    updateBuffer.setLength(0);
    updateBuffer.append("FPS: ").append((int)timer.getFrameRate()).append(" - ");
    updateBuffer.append(display.getRenderer().getStatistics(tempBuffer));
    /** Send the fps to our fps bar at the bottom. */
//    fps.print("FPS: " + (int) timer.getFrameRate() + " - " +
//              display.getRenderer().getStatistics());
    fps.print(updateBuffer);
   
    if (!pause) {
      /** Update controllers/render states/transforms/bounds for rootNode. */
      rootNode.updateGeometricState(tpf, true);
    }
   
    /** Reset display's tracking information for number of triangles/vertexes */
    display.getRenderer().clearStatistics();
    /** Clears the previously rendered information. */
    display.getRenderer().clearBuffers();
    /** Draw the rootNode and all its children. */
    display.getRenderer().draw(rootNode);
    /** If showing bounds, draw rootNode's bounds, and the bounds of all its children. */
    if (showBounds)
      display.getRenderer().drawBounds(rootNode);
    /** Call simpleRender() in any derived classes. */
    simpleRender();
    /** Draw the fps node to show the fancy information at the bottom. */
    display.getRenderer().draw(fpsNode);
  }



Does this sound about right to you? One could debate ofcourse about the geometry update, but in this case I was aiming for continuing rendering in all possible ways, including animations (which get flaky anyway when not updating regularly).

NB Is there any interest in adding the above combinations of existing classes and maybe FixedFramerateSimpleGame to the CVS?