1

if I don't control the number of times per second my code executes, when I add a line, the program varies and I have to adjust the constants again. (translated by Google) My code running out of control:

public builder(){
    while(true)
        stepEvent();
}
private void stepEvent() {
    setOfActions();
    repaint();
}
Jean_K
  • 51
  • 7

3 Answers3

2
import java.util.Timer;
import java.util.TimerTask;

public class HelloWorld {
    public static void main(String []args) {
        // number of ms in 1/60 of a second
        // there will be some rounding error here,
        // not sure if that's acceptable for your use case
        int ms = 1000 / 60;
        Timer timer = new Timer();
        timer.schedule(new SayHello(), 0, ms);
     }
}

class SayHello extends TimerTask {
    public void run() {
       System.out.println("Hello World!"); 
    }
}
Daniel Centore
  • 3,220
  • 1
  • 18
  • 39
2

This is just one way to do it(it's very long but VERY precise - I recommend it for game development). In this case I'm using the run() method from the Runnable interface to execute the code.

public void run(){
    long lastTime = System.nanoTime();
    final double ns = 1000000000.0 / 60.0;
    double delta = 0;
    while(true){
        long now = System.nanoTime();
        delta += (now - lastTime) / ns;
        lastTime = now;
        while(delta >= 1){
            the code you want to be executed 
            delta--;
            }
        } 
   }

Explanation Line by Line:

Basically, I store the current time in nanoseconds in lastTime. Then in ns I store 1/60th of a second in nanoseconds and create a variable delta.

After this, I go inside the infinite while loop(it doesn't have to be infinite) and store the current time in nanoseconds once again in now. This is to take into account the amount of time that took the computer to go from the lastTime declaration line to the while loop line.

After doing all this, I add to delta the difference of now and lastTime divided by the 1/60th of a second(ns) I mentioned. This means that every time delta is equal to 1, 1/60th of a second will have passed.

Right after this, I make lastTime be the same as now. In the while loop that comes afterwards I check if delta is equal or greater than 1 and then in there you should put all the code you want to be executed 60 times per second. Don't forget to substract 1 from delta so it doesn't loop endlessly.

Analyze the code thoroughly and see if you can understand it. If you can't, I'll clarify further. I insist that this is just one possible way to do it, but there are many more ways.

Note: In some cases, you will never even need delta, but it is very helpful for some purposes.

Credit for the code: Most of this code(at least where I got it & learned it) is extracted from TheCherno's Game Programming Series

Have a great day!

JeroSquartini
  • 347
  • 1
  • 2
  • 11
  • Code as presented doesn't work - try putting a System.out.println into the inner while to demonstrate it doesn't do anything. It never goes into that section because delta is always < 1. – jon hanson Jun 27 '21 at 12:31
-1

Basically, you have to execute your stepEvent every 17 ms.

With the assumption you want to run sequentially, you could stop the execution during a defined period by using Thread.sleep(millis , nanos). In this case, we will stop the thread 17ms minus the stepEvent execution time (think to add condition to avoid negative value in sleep function)

long startedTime;
for(;;){
    startedTime = System.currentTimeMillis(); 
    stepEvent();
    Thread.sleep(17 - System.currentTimeMillis() + startedTime);
}

Otherwise you can use the ScheduledExecutorService which allows you to schedule code to run periodically at fixed time intervals (or after a specified delay). In this case, you can execute your step at a fixed rate every 17ms.

ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
scheduledExecutorService.scheduleAtFixedRate(YourClass::stepEvent, 0, 17, TimeUnit.MILLISECONDS);

You can also configure to use severals thread with Executors.newScheduledThreadPool

Fabien Leborgne
  • 377
  • 1
  • 5