Game Loop control - java

i'm having a tremendous difficulty understanding a piece of code that controls a loop of a game... I can't understand the purpose of this while loop "while(unprocessedSeconds > secondsForEachTick)" and why the FPS counter if inside of that if(tickCounter % 60 ==0) like follows on code:
public void run()
{
int frames = 0;
double unprocessedSeconds = 0;
long previousTime = System.nanoTime();
double secondsForEachTick = 1/60.0;
int tickCount = 0; //RENDER COUNTER
boolean ticked = false;
while (running)
{
long currentTime = System.nanoTime();
long passedTime = currentTime - previousTime;
previousTime = currentTime;
unprocessedSeconds = unprocessedSeconds + passedTime / 1000000000.0;
int count = 0;
while(unprocessedSeconds > secondsForEachTick)
{
tick();
count++;
unprocessedSeconds -= secondsForEachTick;
ticked = true;
tickCount++;
if(tickCount % 60 == 0){
System.out.println(frames + " fps");
previousTime += 1000;
frames = 0;
}
}
System.out.println("Iterações do loop: "+count);
if(ticked)
{
render();
frames++;
ticked = false;
}
}
}

That inner while cycle ensures that the game update is based on fixed time, rather than frame time. The unprocessed time is getting collected and as soon as it is greater than the time frame for one tick, it calles tick().
The TickCount is basically counts the ticks (the tick time is 1/60 sec, so 60 tick/sec), and as soon as it 1 sec elapsed it prints the collected frames (so FPS). Also, ticked signals that something may changed in the game, so a new render is required.

This loop is used to have constant time in game. So if for some reason you get lag, you will do several logic update and one render. I assume tick() performs some logic operations.
To be more precise. For example, you have bullet, and bullet position need to be updated at 0.1s to do proper collision test. If for some reason delta time grows to 0.4s your bullet will fly through walls. To deal with it you performs several iterations with smaller time step, this loop doing it.

Related

How do I stop the timer from counting down when I switch to pause state?

I have a java game wherein there is a countdown timer from 60 secs. It works fine, but when I pause the game and return back to play state. the original time is now reduced because I found out that the timer still keeps running from the system no matter what gameState I'm in. How do I fix this?
I tried storing the remainingTime to a pauseTime variable whenever I switch states, and just subtract it and stuff. But my efforts seem to failed.
// GET ELAPSED TIME
if(gp.gameState == gp.playState && remainingTime >= 0) {
soundCounter--;
elapsedTime = System.currentTimeMillis() - startTime;
remainingTime = totalTime - elapsedTime;
if(remainingTime <= 0) {
remainingMilliseconds = 0;
remainingSeconds = 0;
remainingMinutes = 0;
// GAME OVER
gp.gameOver();
} else {
remainingMilliseconds = remainingTime % 1000;
remainingSeconds = (remainingTime / 1000) % 60;
remainingMinutes = (remainingTime / 1000) / 60;
}
}
// DRAW TIMER
timeString = String.format("%02d:%02d:%03d", remainingMinutes, remainingSeconds, remainingMilliseconds);
Your problem is that you are calculating your elapsed time forever since the first startTime.
One of the solution would be to calculate a delta (difference) time between loop iterations.
Here some very primitive code that should get you started:
public static void main(String[] args) {
boolean paused = false;
long lastRun = System.currentTimeMillis();
long elapsed = 0;
System.out.println("Game start");
while (true) {
long now = System.currentTimeMillis();
long delta = now - lastRun;
if (!paused && delta > 0) {
elapsed += delta;
// Do game stuff
System.out.println("Elapsed: " + elapsed);
if (elapsed >= 5000) return;
lastRun = now;
}
}
}

Update integer values every second in Java with something between the given numbers

I have 2 integer values, let's say int a = 5 and int b = 4.
public static void run() {
long lastTime = System.nanoTime();
final double ns = 1000000000.0 / 60.0;//60 times per second
double delta = 0;
while(running) {
long now = System.nanoTime();
delta = delta + ((now-lastTime) / ns);
lastTime = now;
while (delta >= 1)//Make sure update is only happening 60 times a second
{
delta--;
}
}
What I want to achieve is to be able to change values of the integers within the while (delta >= 1){} every second to a number between 100 and 400. I want to create a paint method that takes the values of the integers and updates the component sizes within my JFrame. I just need an idea to go with, so I can move on.
I'm not sure if I fully understood your question. However, if your intention is to run a bit of code 60 times per second, there is definitely an easier way to accomplish this - via Java's Thread.sleep() mechanism. You can use Java's Random class to actually generate random values for a and b:
public static void run() {
Random random = new Random();
while (running) {
try {
Thread.sleep(16); // 16 millisecond sleep; will run 60 times per second
// Generate random number between 100 and 400
a = (random.nextInt() % 300) + 100;
b = (random.nextInt() % 300) + 100;
} catch (Exception e) {
System.out.println("Exception encountered when trying to sleep! " + e.toString());
}
}
}
Alternatively, you can also use Java's Timer and TimerTask classes to the same effect.

Game Loop updates too fast

I want to create a start menue for a Pong clone where the ball in the background bounces off the edges. However the game loop updates to fast so the Coordinates of the ball are already out of the JFrame before you can see it and it moves to fast. I found that through sysouts.
I guess it has something to do with threads but I am not sure.
The main class calls this Class as a thread but the important part is in the class BackgroundBallMovement
package main;
public class BackgroundBallMovement implements Runnable{
private boolean running = true;
#Override
public void run() {
long lastTime = System.nanoTime();
final double ns = 1000000000.0 / 60;
double delta = 0;
while(running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
while(delta >= 1) {
update();
delta = 0;
System.out.println("X-Koordinate " + Var.ballX + " " + "Y-Koordinate " + Var.ballY);
}
render();
}
}
//Spiellogik updaten
private synchronized void update() {
Var.ballX += 1;
Var.ballY += 1;
}
//Objekte zeichnen
private synchronized void render() {
Var.drawStartMenue.repaint();
}
}
You're not using Thread.sleep(). Instead you are waiting until System.nanoTime() changed. This means that the CPU is running all the time (not good).
Also this loop:
while(delta >= 1) {
...
delta = 0;
...
}
doesn't make sense because it could be replaced by an if.
Then you are never updating the lastTime variable. So this line:
delta += (now - lastTime) / ns;
will result in a quadratic function because it will result in something like this (each loop execution):
delta += 0.1;
delta += 0.2;
delta += 0.3;
...
Then because you are never updating the lastTime variable after 1s the condition
while(delta >= 1)
will always be met and your ball will move incredibly fast.
Your first approach could be something like this:
#Override
public void run()
{
while(running)
{
update();
render()
System.out.println("X-Koordinate " + Var.ballX + " " + "Y-Koordinate " + Var.ballY);
Thread.sleep(1000L/60L);
}
}
That's because your math sucks ;-)
Yes, (now - lastTime) / ns is the amount of frames that should have been rendered since the engine started. Therefore your code simplifies to:
while (true) {
delta = framesSinceStart();
while (delta >= 1) {
renderFrame();
delta = 0;
}
}
which is equivalent to
while (true) {
if (framesSinceStart() >= 1) {
renderFrame();
}
}
That is, your code correctly waits to render the first frame, but doesn't record that it has rendered that frame, and therefore always thinks it is late, and never waits anymore.
Instead, you might try something like:
while (true) {
if (framesSinceStart() - framesRendered >= 1) {
renderFrame();
framesRendered++;
}
}
Btw, simply staying in an endless loop to spend time is not very power efficient. It would be better to use something like Thread.sleep() to wait - but calculating the time it should be waiting by hand is a little hairy. Fortunately, the Java API comes with nice helper classes to use:
ThreadPoolExecutor executor = Executors.newSingleThreadExecutor();
executor.scheduleAtFixedRate(() -> renderFrame(), 0, 1000 / 60, TimeUnit.ms);
Try Thread.sleep(long millis)
while(running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
while(delta >= 1) {
update();
delta = 0;
try{
Thread.sleep(1000);
} catch(Exception e) { }
System.out.println("X-Koordinate " + Var.ballX + " " + "Y-Koordinate " + Var.ballY);
}
render();
}
another thing you can try is reducing the ball speed.
private synchronized void update() {
Var.ballX += 0.01;
Var.ballY += 0.01;
}

LWJGL Game Loop not working

I am trying to make a simple game in LWJGL 3 but I am stuck in place with my main game loop not working;
float fps = 60;
double ns = 1000000000 / fps;
long last = System.nanoTime();
double delta = 0;
while(glfwWindowShouldClose(window) != GL_TRUE){
delta += (System.nanoTime() - last) / ns;
System.out.println(delta);
last = System.nanoTime();
while(delta-- >= 1){
update();
}
render();
}
I added the print to test what is going on and I noticed that delta is always less than zero, which shouldn't ever happen;
I am using LWJGL 3 with Java 1.8 SE
Why do you think that it is impossible to get negative values?
This expression
while(delta-- >= 1)
will decrease delta by 1 at least once, no matter if the loop is taken or not.

Java - Thread.sleep inside run method

I'm following a tutorial and below is the run method to generate logic and frame updates. I understand how the ticks are updated 60 ticks/second but I don't understand how we adjust frame per second here.
Right now with Thread.sleep(2), frame per second is around 460. Without it the numbers go way up, around 10 million updates per second. The code Thread.sleep(2) suspends the thread for only 2 milliseconds right? Why/how does Thread.sleep exactly work here to drop it so low?
Isn't it simpler to create a nsPerFrame = 1000000000D/ (FPS)D to set whatever FPS I want the way he did with ticks?
public void run(){
long lastTime = System.nanoTime();
double nsPerTick = 1000000000D / 60D;
int frames = 0;
int ticks = 0;
long lastTimer = System.currentTimeMillis();
double delta = 0;
while(running){
long now = System.nanoTime();
delta += (now - lastTime) / nsPerTick;
lastTime = now;
while(delta >= 1){
ticks++;
tick();
delta-= 1;
}
try{
Thread.sleep(2);
} catch(InterruptedException e){
e.printStackTrace();
}
frames++;
render();
if(System.currentTimeMillis() - lastTimer >= 1000){
lastTimer += 1000;
System.out.println(ticks + "," + frames);
frames = 0;
ticks = 0;
}
}
}
Well sleep(2) is called repeatedly in your running-loop so the hard upper limit in this case is 500 cycles per second (1000 ms divided by 2 ms), and your measured 460 fps is pretty close to that.
Sure enough you can adjust the sleep duration according to your needs and if needed stuff it into the somewhat higher-precision method Thread#sleep(long, int) where the second parameter is "nanos" (take a look at the docu for caveats!).
The formula for your case is FPS = 1000 ms / sleep duration in ms. From which follows: sleep duration in ms = 1000 ms / FPS.

Categories