public class HighResTimer implements Runnable { private int ticks, autoLength; private Thread timerThread; private boolean autoCorrection = true; private boolean running = false; private long timeDiff, startTime, endTime, msDelay, targetMs; public HighResTimer() { timerThread = new Thread(this); timerThread.setPriority(Thread.MAX_PRIORITY); timerThread.setDaemon(true); } public int getTickCount() { return ticks; } public void resetTickCount() { ticks = 0; } public void startTimer() { running = true; timerThread.start(); } public void stopTimer() { running = false; try { timerThread.join(); } catch (Exception e) {} } public void setAutoCorrection(boolean on, int sampleLength) { autoCorrection = on; autoLength = sampleLength; } public void setDelay(int tmsDelay) { msDelay = tmsDelay; targetMs = msDelay; } public void run() { // From oNyx on javagaming.org /* // for the 4k games private long lastFrame=0; float yield=10000f; float frameAverage=16f; //start with desired msec per frame [...] long timeNow = System.currentTimeMillis(); //rolling average for the last 10 time inputs frameAverage = (frameAverage * 10 + (timeNow - lastFrame)) / 11; lastFrame=timeNow; //16f = for 16msec //0.1f = damping value //and that +0.05f bit is for ensuring that it can grow faster after it ran flat out for a while yield+=yield*((16f/frameAverage)-1)*0.1f+0.05f; for(int i=0;i 0){ Thread.sleep(msDelay); } ticks++; synchronized (this) { notifyAll(); } if (autoCorrection && (ticks % autoLength == 0)) { endTime = System.currentTimeMillis(); timeDiff = ((endTime - startTime) / autoLength) - targetMs; startTime = endTime; if (timeDiff > 0) { msDelay--; } if (timeDiff < 0) { msDelay++; } } } } catch (Exception e) {} } }