Java Game Loop Explanation - java

Recently, I've been getting into Java Game programming. I have learned Java before, but this is my first time with Graphics, Game Loops etc.
I followed this tutorial for a Game Loop, and it's working pretty well.
There is nothing wrong with it, but I just can't figure out why I am thread.sleeping the code, and whats the point of it.
If anyone could explain what start, elapsed and running do, and why I am doing thread.sleep(wait) then I would be super appreciative!
GAME LOOP (Remember, it works, I just don't know why):
while (running) {
start = System.nanoTime();
update();
draw();
drawToScreen();
elapsed = System.nanoTime() - start;
wait = targetTime - elapsed / 1000000;
if (wait < 0) {
wait = 5;
}
try {
Thread.sleep(wait);
} catch (Exception e) {
Game.logger.log("ERROR! Printing Stacktrace...");
e.printStackTrace();
}
}
}

Well, running is a flag that can be set to false to terminate the game.
start and elapsed are used to measure the time one round in the loop took. You are waiting to not make the game run too fast. If you are moving elements with a set speed, then having the game loop run too fast makes them also move too fast. That can lead to a bad user experience, since the user might not be fast enough to play the game.
Additionally, any animation doesn't run smooth anymore without the waiting. It will speed up and slow down depending on how fast your code executes.
Just continue with the tutorial, and when are at the point where you make something move, remove the waiting and see what happens.
EDIT
The code makes a round in the loop take about targetTime. It's unit is milliseconds. So to calculate the frame rate, just divide 1000 / targetTime.

start is the time before the game logic runs. elapsed is the amount of time that it takes for the game logic to run. running is a boolean (true/false) variable that determines whether the game should continue. Thread.sleep(wait) is a method that delays for a certain amount of time.
The goal is to keep the amount of time between frames roughly constant by delaying, so that the animations don't run faster or slower depending on how fast your computer processor is running.

It appears the code aims to be executed targetTime seconds. So you count how much time has already passed (elapsed), and then calculate how much to wait (divide it to get your remaining time in miliseconds, required for methon sleep(wait)).
One purpose of such waiting is often forcing some time between repainting to the screen.
To get your FPS, one way would be to slightly change your code:
long prevStart = 0; //just initialize. First FPS is of course wrong, next get fine.
double FPS = 0;
while (running) {
start = System.nanoTime();
FPS = 1 / double(start - prevStart);
prevStart = start;
update();
draw();
drawToScreen();
elapsed = System.nanoTime() - start;
wait = targetTime - elapsed / 1000000;
if (wait < 0) {
wait = 5;
}
try {
Thread.sleep(wait);
} catch (Exception e) {
Game.logger.log("ERROR! Printing Stacktrace...");
e.printStackTrace();
}
}

Related

Java: Randomly generated numbers only appear in small part of given range

I'm working on a game and I want my enemies to spawn with a delay between 1-5 seconds. My code for that part looks like this:
#Override
public void run() {
try {
while (true) {
Random r = new Random();
int cooldownTime = r.nextInt((5000 - 1000) + 1) + 1000;
long lastSpawn = 0;
long time = System.currentTimeMillis();
if (time > lastSpawn + cooldownTime) {
System.out.println(cooldownTime);
addEnemies();
lastSpawn = time;
}
If I understand nextInt correctly this should spawn enemies 1000-5000 ms apart every time, but my results are really weird and I can't quite figure out why. This is an example of what it would look like if I print cooldownTime.
2523
1190
1095
1061
1168
1119
1052
1159
1071
1076
1000
1394
1249
1070
And so on... It seems that the first enemy is truly spawned randomly and the others are always in the low 1000's. This happens every time. Does anyone know why it's like that? I'm quite lost.
Calling Random r = new Random(); repeatedly is extremely pathological and ruins the statistical properties of the generator. (The results you get are most likely a strong function of your system clock time.)
Do that step once and your results will be far better. (There are also more efficient ways to implement a delay than this - consider sleep - Java compilers are not yet optimising out burn loops.)
Note also that your observations are further complicated by the fact that you are not printing every number drawn.
Not sure if this your exact issue, but you had some problems with the logic of System.currentTimeMillis() and were just looking at the total current time and not the difference between the time.
Additionally you only want to look for a new random value once the if actually executes so you do not generate a Random number each loop iteration, but rather each time an enemy spawns you generate a new one for the next enemy.
Here is the modified code that takes all of this into account:
Random r = new Random();
long time = System.currentTimeMillis();
int cooldownTime = r.nextInt((5000 - 1000) + 1) + 1000;
while (true) {
long timeDifference = System.currentTimeMillis() - time;
if (timeDifference > cooldownTime) {
//addEnemies();
System.out.println(timeDifference); //Prints the time taken for enemy to spawn
cooldownTime = r.nextInt((5000 - 1000) + 1) + 1000;
time = System.currentTimeMillis(); //set the initial time again
}
}
This will generate a random number between 1000 and 5000 and execute the if block each time after the delay, resetting the values in the if to do it forever.
However, there are most likely better ways to add a delay to your logic like some comments pointed out(sleep), but this is the corrected logic for your method.
Well, first of all, several of your variables are being created INSIDE the loop. You need to move the creation of the Random object, as well as the lastSpawn and cooldown variables outside the loop. This is because the lastSpawn variable is being overwritten each time the loop executes with 0, meaning you're always checking if the current time is greater than 0. You need to store it outside the loop so that it will retain the last value you assigned to it. For the same reason, cooldown needs to be outside the loop because you're generating a new cooldown every loop, and System.currentTimeMillis() is ALWAYS going to be larger than it because System.currentTimeMillis() gets you the system time offset from January 1, 1970. Finally, as System.currentTimeMillis() is represented by a long, you'll want any time-related variables to be long as well, otherwise you could end up overflowing your variable if the current time in milliseconds is too high for an integer to store.
Here is a better way to achieve what you're looking to do:
import java.util.Random;
public class RandomCooldown {
public static void main(String [] args) {
Random rand = new Random();
long start = System.currentTimeMillis();
long lastSpawn = start;
long cooldown = getCooldown(rand);
while(true) {
long time = System.currentTimeMillis();
long elapsed = (time - lastSpawn);
if(elapsed >= cooldown) {
System.out.println("Adding enemies!");
cooldown = getCooldown(rand); // only generate a new cooldown once the old cooldown has been surpassed
lastSpawn = time;
}
}
}
public static long getCooldown(Random rand) {
return (long)((rand.nextInt(4000) + 1) + 1000);
}
}
Hope this helps!
Here is a suggestion that works as I think you like. I has not one but two loops. The outer loop generates new enemies and the inner loop makes updates (not sure how much of that this enemy generating thread needs to update but included it just in case).
public void run() {
Random r = new Random();
// setup
while (true) {
int wait = r.nextInt((5000 - 1000) + 1) + 1000;
long time = System.currentTimeMillis();
System.out.println("Adding enemies at " + time
+ ", next add roughly in " + wait + " ms.");
while (wait + time > System.currentTimeMillis()) {
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
// update
}
}
}
The Random object is reused and the call Thread.sleep(30) makes the thread hand over control for 30 ms, a time during which the CPU can do more useful things than busy wait. (30 is BTW not a magic number that must be used but just a number I chose. You need to experiment and find what number works best in your game.)
The print out shows what happens.
Adding enemies at 1565096018610, next add roughly in 2890 ms.
Adding enemies at 1565096021530, next add roughly in 2301 ms.
Adding enemies at 1565096023863, next add roughly in 4944 ms.
Adding enemies at 1565096028813, next add roughly in 3042 ms.
Adding enemies at 1565096031879, next add roughly in 2661 ms.
... and so on. The actual numbers will not be the same of course when you run this code but similar.
Hope this helps and good luck with your game!
It looks fine to me. You should probably use the same Random() instance for each iteration. And remember: humans have no ability to perceive randomness. Alternatively, you could try seeding the Random-Generator (using the Random(long seed) constructor), just in case there's some weird stuff happening with your seed.

Java: First iteration of for loop takes longer

I am writing some code to test using the MIDI libraries in Java, and have run across a problem. The pause between notes is much longer (almost twice as long, in fact) after the very first note than after all the others. I can't see any reason why, as the sequence of notes has already been generated (hence it is not also having to perform those calculations within the first iteration of the loop, it is only playing notes).
I think I may have also had this problem in the past with a simulation which, without any explanation I could find, took almost 100% of its tick length to perform calculations on the first tick only, and then used only about 2% on all successive iterations.
Main code (extract):
public void play() {
MidiPlayer player = new MidiPlayer();
for (int i = 0; i < NUMNOTES; i++) {
long tic = System.currentTimeMillis();
player.playNote(10, notes[i]);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
long toc = System.currentTimeMillis();
System.out.println(toc - tic);
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Code for playNote():
public void playNote(int channel, int note) {
channels[channel].allNotesOff();
channels[channel].noteOn(note + 60, volume);
}
There are no 'if' statements that specify the first loop, so surely the delay should be uniform for all notes, as the number of calculations being performed should be the same for all iterations. Please note that the timing variables are just for testing purposes, and the effect was audibly noticeable before I included those.
EDIT: I should also mention that the output produced shows each iteration of the loop taking the expected 200 (occasionally 201) milliseconds. It seems to suggest that there is no gap - yet I clearly hear a gap every time I run the code.
Since you have sleeps, you should calculate how long you should sleep instead of trying to sleep the same amount of time each time - calculate how much more time you actually need to the next note to be played and sleep that much amount. i.e.
long tic = System.currentTimeMillis();
player.playNote(10, notes[i]);
long time_spent = System.currentTimeMillis() - tic;
Thread.sleep(200 - time_spent);

Surfaceview - moving around bitmap at the same speed with different fps

I have many bitmaps I move around on a surfaceview and sometimes the fps drops which makes the bitmap move slow or super fast randomly, I've seen someone post a solution using system time or something like that, but couldn't find it, so I wonder if anyone knows how can I make the speed be the same even if the fps drops.
Edit:
I thought that maybe I can calculate time different using:
int myFPS;
if(gameLoopThread.startTime!=System.currentTimeMillis())
myFPS=(int) (1000 / (gameLoopThread.startTime-System.currentTimeMillis())*-1);
else
myFPS=25;
float new2=1;
new2=25/myFPS;
and then just multiple
currentSpeed.y += speed*new2;
but it didn't work out because the fps showed was wrong, but I think this is the way to do it? or I might be wrong..
Update:
Single threaded loop:
To keep the speed of your game at a constant rate, you will have to skip rendering at some point, should a loop iteration take longer than expected.
while(isRunning){
beginTime = SystemClock.uptimeMillis();
framesSkipped = 0;
//Update game state
update();
render();
//how long we took to update and render
loopTime = SystemClock.uptimeMillis() - beginTime;
//calculate how long to sleep
sleepTime = loopPeriod - timeDiff;
//All work was done on time.
if (sleepTime > 0) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {}
}
//We were too slow. Update without rendering.
while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) {
update();
//make sure we don't keep looping here.
sleepTime += loopPeriod;
framesSkipped++;
}
}
}
This loop prioritizes your logic updates, and skips rendering if we are behind. The benefit is, that your game-actors are updated constantly and independently from possible frame rate drops.
Two threads: (original answer)
Another way to ensure steady movement at low FPS, is to do rendering in one thread, and logical stuff in another one.
Example for the game logic thread:
while(isRunning){
startTime = SystemClock.uptimeMillis();
//update game logic, no rendering.
update();
//time it took to update the game state.
loopTime = SystemClock.uptimeMillis() - startTime;
//pausing here to make sure we update the right amount per second.
if(loopTime < updatePeriod){
try {
Thread.sleep(updatePeriod-updateTime);
} catch (InterruptedException e) {
Log.e(TAG,"Interrupted while sleeping");
}
}
}
The update period is the amount of milliseconds a single update iteration is allowed to take.
updatePeriod = 1000 / ups;
ups = updates per second. If your game runs at 60 fps max, use 60 ups.
Note that both loops are very basic, and, without modification, not suitable for advanced applications.
Also, use SystemClock.uptimeMillis(); it's more reliable.
How I kept track of fps 1000milliseconds / 25 = 40 fps
At the start of the while loop make sure you get the time.
long starttime = System.currentTimeMillis();
Then after everything is finished and rendered you get the time again.
long endtime = System.currentTimeMillis();
Subtract start time from end time then divide by 1000 multiply by -1 to get how many times your runnable can loop in a second.
int MyFPS = (int) (1000 / (starttime - endtime) * -1);
If your answer is 75 then you're running at 75fps.
You just need to put the thread to sleep for 35 milliseconds to be at 40fps.
Tracking the low fps I never got around to doing. Hope this helps a little though.
#Override
public void run() {
while (THREAD) {
long starttime = System.currentTimeMillis();
if (!myHolder.getSurface().isValid())
continue;
Update(); <----Running the game.
Main_Render(); <----Rendering graphics.
long endtime = System.currentTimeMillis();
int MyFPS = (int) (1000 / (starttime - endtime) * -1);
if (MyFPS >= 25) {
sleep_length = MyFPS - 25;
try {
Thread.sleep(sleep_length);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

Updating and rendering for a 2D game in Java

So, I am working on making a 2D game in Java, and I really don't have too much experience with Java. I currently use a very simple loop using a swing timer running every 10ms or so that looks something like:
public void actionPerformed(ActionEvent e) {
update();
repaint();
}
However, I need something more practical for obvious reasons. These reasons include the fact that more lag means less FPS AND slower movement/other updating.
I found the following code in a tutorial for a 3D Java game here. It would begin running when the program starts, and I understand enough to know it would work. However, I do not fully understand it: (tick() is the updater, render() renders the screen)
long currenttime;
long previoustime = System.nanoTime();
long passedtime;
int frames = 0;
double unprocessedseconds = 0;
double secondspertick = 1 / 60.0;
int tickcount = 0;
boolean ticked = false;
while (gameIsRunning) {
currenttime = System.nanoTime();
passedtime = currenttime - previoustime;
previoustime = currenttime;
unprocessedseconds += passedtime / 1000000000.0;
while (unprocessedseconds > secondspertick) {
tick();
unprocessedseconds -= secondspertick;
ticked = true;
tickcount++;
System.out.println(tickcount);
if (tickcount % 60 == 0) {
System.out.println(frames + " FPS");
previoustime += 1000;
frames = 0;
}
}
if (ticked) {
render();
frames++;
}
render();
frames++;
}
This code was not explained in the tutorial I found it in. Could someone please break this down and explain it?
I have also looked here for ideas, and the final piece of code on that page with a render thread and an update thread makes a lot of sense to me.
Which method should I use? One of the above, or something totally different? Also, you can probably tell that this is my first question here on stackoverflow.
Thanks in advance,
Josh
tick() is probably updating the game object's physical properties (position, velocity, etc.) tick() is called multiple times each update because some simulations can't handle too large a timestep without becoming unstable.
There's a popular article online which explains why this is the case, and why using a fixed timestep is the proper procedure. Check it out.
Each update the game is advanced in 1/60th second (so 60 frames a second) increments. This is repeated until there's less than 1/60th a second remaining in the aggregate. Aggregate is just a fancy word for sum.
Then a snapshot of the game's current state is rendered to the screen.
I won't get too deep into it, but really this code should be inerpolating each object's position by the remaining time in the aggregate during render().
long currenttime;
long previoustime = System.nanoTime();
long passedtime;
int frames = 0;
//this is an aggregate, games usually step in fixed units of time.
//this is usually because physics simulations can't handle too large of time steps.
double unprocessedseconds = 0;
double secondspertick = 1 / 60.0;
int tickcount = 0;
boolean ticked = false;
while (gameIsRunning) {
//get elapsed nano seconds from the epoch (january 1st, 1970)
currenttime = System.nanoTime();
//take difference of current time in nanos and previous time in nanos
passedtime = currenttime - previoustime;
previoustime = currenttime;
//divide to get the elapsed time in seconds.
unprocessedseconds += passedtime / 1000000000.0;
while (unprocessedseconds > secondspertick) {
tick();
unprocessedseconds -= secondspertick;
ticked = true;
tickcount++;
System.out.println(tickcount);
if (tickcount % 60 == 0) {
System.out.println(frames + " FPS");
previoustime += 1000;
frames = 0;
}
}
if (ticked) {
render();
frames++;
}
render();
frames++;
}
Good luck Josh.
Edit:
I have no experience with games using one thread for updates, and one for rendering. I can't give advice on those for that reason. If you have little or no experience with multithreading I'd avoid it as only complex games are likely to require this approach, and multithreading will add a multitude of issues you probably don't want to deal with.
Multithreaded game engines will consume more memory between rendering and updating than a single threaded game, or will wind up being depend on one another anyway. This is because the two threads can't manipulate the same data simultaneously. Therefor the only way for the two threads to operate is with synchronization on those data structures, or by the update thread suppling the render thread with immutable data to render.
Writing a multithreaded game engine would be a good introduction to threading. It could teach you quite a lot. Depends on what you want to get out of this.
If you are making a 2D game I feel even more confident that you will not need one thread for updating and one for rendering.
If you really want to pursue this, here's the approach I'd take.
You don't need more than a while loop to control rendering.
The way I do my engines is just as explained before, I multi-thread. Basically, if you split the job of processing and drawing the game into two segments it becomes quicker at the expense of more resources in use. I do a little something like this:
public class Engine implements Runnable {
//Sets classes
Engine tick = new Engine(true);
Engine render = new Engine(false);
Thread tickThread = new Thread(tick);
Thread renderThread = new Thread(render);
boolean job;
boolean isRunning = false;
long sleepTime = 5L;
public Engine(boolean job) {
//Sets what the thread does
this.job = job;
}
public static void startEngine() {
//Starts Engine
isRunning = true;
tickThread.start();
renderThread.start();
}
public void tick() {
//Process things
}
public void render() {
//Draw things
}
public void run() {
//Do engine base things
while(isRunning) {
if(job) {
tick();
} else {
render();
}
Thread.sleep(sleepTime);
}
}
}
This is by no means advanced. This is just an example of what a simple multi-thread game engine would be like. Honestly, I used this exact code when I was starting off making games. This could be used but some adjustments should be made depending on what you use it for. What I mean is that lets say you have an object that's moving and its being rendered at the same time. If the objects position is 50 and increasing and the render method is drawing it then the object could go to 51 then 52 before being rendered again. Normally, the processing is faster than the drawing. Another example: Lets say you have an ArrayList and are constantly removing and adding objects to it. Sometimes you can remove an object just as the render method is about to draw it and cause a null pointer exception because it's trying to draw something that doesn't exist. (I used "if(object.get(i) != null)" and worked around it that way)
I hope this helped at least a little (two years later, lol) and helped you get a basis of what multi-threading is like (if you didn't already).

Why is my game lagging?

I'm making a basic 2D game, yet I'm having problems with lag. The character on the game moves fine, yet sometimes slows right down, mainly when near an enemy. The enemy is not causing the lag though, as I've had 50 of them on the screen at once and it runs fine.
I've done the timing almost identically to how it's done in the Killer Game Programming in Java book, yet it doesn't seem to work too well. The FPS also seems to change a lot, which it shouldn't, because it should always take 15ms to complete an update-render-paint-sleep cycle, can anyone explain this?
Also, I think it lags more when my computer is doing things in the background (antivirus scanning, etc.), although I can run the game at about 550FPS while it's running other programs, so I don't think it's my computer.
Here's how I do the timing:
int waitTime = 1000 / 65; //65 being the desired FPS
while(running){
if(!loading){
gameUpdate();
gameRender();
gamePaint();
afterTime = System.nanoTime();
timeDiff = afterTime - beforeTime;
sleepTime = waitTime - (timeDiff / 1000000L);
if(sleepTime > 0){
try{
mainThread.sleep(sleepTime);
} catch(InterruptedException ie){}
}
else{
sleepSkipped++;
if(sleepSkipped == maxSleepSkipped){
Thread.yield();
sleepSkipped = 0;
}
}
fpsTime += (System.nanoTime() - beforeTime) / 1000000;
fps++;
if(fpsTime > 1000){
System.out.println("FPS: " + fps);
fps = 0;
fpsTime = 0;
}
beforeTime = System.nanoTime();
}
}
I think your problem is similar to one very recently Weird behavior in Thread.sleep()
I see that in your loop you add the sleeptime to your timer, meaning it keeps increasing (lowering fps) until it becomes so large that substracting the waittime from it gives a negative number, making your loop go into the one that yields the thread where it adds to the skipcount and yields when the count is high enough.
As arynaq suggested, it was a problem with the enemy collision detection. Every cycle through the loop made each enemy call quite a few methods, however I have now removed and relocated many of the method calls, which has completely fixed the lag problem. Thank you, arynaq.

Categories