I have two interfaces. Entity for updates. Drawable for rendering. They both have two interface methods. One that is called every frame, one every second.
Entity.java
public interface Entity
{
public void updatePerFrame ();
public void updatePerSecond ();
}
Drawable.java
public interface Drawable
{
public void drawPerFrame ();
public void drawPerSecond ();
}
The main component class Game has two lists, one for Entity and one for Drawable.
public class Game {
// if the game is running, default = true
// if the game is paused, default = false
private boolean isRunning;
private boolean isPaused;
// execution time for the last cycle of game loop
private long lastLoopTime;
private long curLoopTime;
private long deltaLoopTime;
private double deltaTime;
// if a second has passed since last execution
private boolean secondPassed;
private long secondTimer;
// nanoseconds spent per frame
private final int OPTIMAL_FPS = 60;
private final int OPTIMAL_TIME = 1000000000 / OPTIMAL_FPS;
// entities
private List<Entity> entities;
// drawable
private List<Drawable> drawables;
// fps tracker
FPSViewer fpsViewer;
/**
* Main Function, instantiating Game
*/
public static void main() {
Game g = new Game();
g.gameLoop();
}
/**
*
*/
public Game () {
// the game is on and not paused
isRunning = true;
isPaused = false;
// a second has not yet passed
secondPassed = false;
secondTimer = System.currentTimeMillis();
// init entities and drawables
entities = new ArrayList<Entity>();
drawables = new ArrayList<Drawable>();
// begin with current time
lastLoopTime = System.nanoTime();
// create the fps viewer
fpsViewer = new FPSViewer();
entities.add(fpsViewer);
drawables.add(fpsViewer);
}
/**
* Game Loop
*/
public void gameLoop () {
while (isRunning == true) {
// if the game is paused
if (isPaused == true) {
// set paused attributes
// to-be-done
// wait for user to unpause
while (isPaused == true) {
}
// reset time synching
lastLoopTime = System.nanoTime();
// reset fps viewer
fpsViewer.reset();
}
// get delta time
curLoopTime = System.nanoTime();
deltaLoopTime = curLoopTime - lastLoopTime;
deltaTime = deltaLoopTime / (double)OPTIMAL_TIME;
// set last to current
lastLoopTime = curLoopTime;
// check if a second has passed
if ((System.currentTimeMillis() - secondTimer) > 1000) {
secondPassed = true;
secondTimer = System.currentTimeMillis();
}
// render everything
render ();
// update game
gameUpdate();
// reset if a second has passed
if (secondPassed == true )
secondPassed = false;
// wait for game to catch up (if loop execution was too fast)
try {
Thread.sleep( (lastLoopTime - System.nanoTime() + OPTIMAL_TIME)/1000000 );
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
/**
* Game Updates
*/
private void gameUpdate () {
for (Entity e : entities) {
e.updatePerFrame ();
}
if (secondPassed == true) {
for (Entity e : entities) {
e.updatePerSecond();
}
}
}
/**
* Renders all graphics
*/
private void render () {
for (Drawable d : drawables) {
d.drawPerFrame ();
}
if (secondPassed == true) {
for (Drawable d : drawables) {
d.drawPerSecond();
}
}
}
}
As a test there is the FPSViewer.
It currently sits at 62 fps. Which will be fixed in the next iteration.
public class FPSViewer implements Drawable, Entity {
private long lastFpsUpdateTime;
private long lastExecutionTime;
private byte fps;
public void drawPerFrame () {
}
public void drawPerSecond () {
System.out.println ("Frame: " + fps);
}
/**
* update fps counter
*/
public void updatePerFrame () {
lastFpsUpdateTime += (System.nanoTime() - lastExecutionTime);
lastExecutionTime = System.nanoTime();
fps++;
}
/**
* Resets frame counter back to 0
*/
public void updatePerSecond () {
lastFpsUpdateTime = 0;
fps = 0;
}
public void reset () {
lastFpsUpdateTime = 0;
lastExecutionTime = 0;
fps = 0;
}
}
Now to the feedback wanted, everything basically. Be merciless. Here are some things to focus on. The game will consist mostly of 2D Buttons with mouse and keyboard input.
Entitys shouldn't know anything about render state, so wouldn't needupdatePerFrame(). AnddrawPerSecond()is obviously too slow forDrawable... why do you have two methods in the first place? \$\endgroup\$drawPerSecond ()is used currently to render the fps once per second.updatePerFrame ()is the standard update, called once per execution. TheupdatePerSecond ()was me trying to get some timings done. If I wanted to time things on second basis instead of per loop execution (currently frame). \$\endgroup\$