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.
Related
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.
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.
I am trying to print a long value held by elapsed, can someone help me with the format of how to do it?
This prints 0.0
but i know it has more significant digits (maybe like .0005324 or something)
System.out.println("It took " + (double)elapsed + " milliseconds to complete SELECTION_SORT algorithm.");
'
System.currentTimeMillis();
long start = System.currentTimeMillis();
int sortedArr[] = selectionSort(arr1);
long elapsed = System.currentTimeMillis() - start;
System.out.println("\n///////////SELECTIONSort//////////////");
System.out.println("\nSelection sort implemented below prints a sorted list:");
print(sortedArr);
System.out.printf("It took %.7f ms....", elapsed);
//System.out.println("It took " + (double)elapsed + " milliseconds to complete SELECTION_SORT algorithm.");'
'
private static int[] selectionSort(int[] arr) {
int minIndex, tmp;
int n = arr.length;
for (int i = 0; i < n - 1; i++) {
minIndex = i;
for (int j = i + 1; j < n; j++)
if (arr[j] < arr[minIndex])
minIndex = j;
if (minIndex != i) {
tmp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = tmp;
}
}
return arr;
}'
Changing the format won't give you more resolution which is what your real problem is hee if you print 1 ms with 7 digits you just get 1.0000000 every time. This doesn't help you at all.
What you need is a high resolution timer
long start = System.nanoTime();
int sortedArr[] = selectionSort(arr1);
long elapsed = System.nanoTime() - start;
System.out.println("\n///////////SELECTIONSort//////////////");
System.out.println("\nSelection sort implemented below prints a sorted list:");
print(sortedArr);
System.out.printf("It took %.3f ms....", elapsed / 1e6);
However, if you do this once you are fooling yourself because Java compiles code dynamically and gets fast the more you run it. It can get 100x faster or more making the first number you see pretty useless.
Normally I suggest you run loops many times and ignore the first 10,000+ times. This will change the results so much that you will see that the first digit was completely wrong. I suggest you try this
for(int iter = 1; iter<=100000; iter *= 10) {
long start = System.nanoTime();
int[] sortedArr = null
for(int i=0;i<iter;i++)
sortedArr = selectionSort(arr1);
long elapsed = System.nanoTime() - start;
System.out.println("\n///////////SELECTIONSort//////////////");
System.out.println("\nSelection sort implemented below prints a sorted list:");
print(sortedArr);
System.out.printf("It took %.3f ms on average....", elapsed / 1e6 / iter);
}
You will see you results improve 10x maybe even 100x just by running the code for longer.
You can use print formatting. For a double or float, to get 7 places after the decimal place, you would do:
System.out.printf("It took %.7f ms....", elapsed);
EDIT:
You are actually using a long, not a double, so you cannot have significant digits, because long only takes on integer values.
A long is an integer value and does not have decimal places.
To get an approximation of the runtime, run the same sort in a loop, say 1000 times and then divide the measured time by 1000.
For example:
System.out.println("It took " + ((double)elapsed) / NUMBER_OF_ITERATONS);
Try this:
String.format("%.7f",longvalue);
by using above line you can format your long or any floating point numbers. Here 7 is referred how many digits you want after '.' .
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.
I'm writing a method to compute the running time for an algorithm. The algorithm is run a specified number of trials and then I compute the running time using System.currentTimeMillis(). However whenever I call the method the value always ends up being zero. Any direction towards fixing this problem is appreciated.
public long runTime(algorithm alg, int[] array, int trials)
{
long initialTime = System.currentTimeMillis();
for(int i = 0; i < trials; i++)
{
alg.runAlgorithm(array);
}
return ((System.currentTimeMillis() - initialTime) / (long) trials);
}
((System.currentTimeMillis() - initialTime) / (long) trials);
It seems the Algorithm is taking less than a 1 ms to complete its loop, and so you need to break it even to smaller unit... Using nanoTime() may do the work for u...
Eg:
public long runTime(algorithm alg, int[] array, int trials)
{
long initialTime = System.nanoTime();
for(int i = 0; i < trials; i++)
{
alg.runAlgorithm(array);
}
return ((System.nanoTime() - initialTime) / (long) trials);
}
If your return value is less then one. Use return type double. In your example, you should use double instance of long.