Yemto
|
 |
«
Posted
2013-08-16 12:07:16 » |
|
I have trouble with my game loop. The one I have can cause objects to get stuck or teleport through other objects. I know it's caused when the FPS is low and the game tries to put the objects where they are suppose to be. But it ignore hit detection. My idea is to make the game not render all the frames when it runs slow, to try to get more time for the logic. But I'm not sure how to do that. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Override public void run(){ while(true){ double delta = (System.nanoTime() - lastUpdate) / 1000000000.0; lastUpdate = System.nanoTime(); world.update(delta); screen.repaint(); if(!maximumFps){ try{ Thread.sleep((lastUpdate-System.nanoTime() + optimalTime) / 1000000); }catch(Exception e){} }else{ try{ Thread.sleep(1); }catch(Exception e){} } } } |
|
|
|
|
sirkarpfen
|
 |
«
Reply #1 - Posted
2013-08-16 12:17:49 » |
|
What exactly are you doing inside world.update() (i think thats your global "gamelogic update" method)? Also are you using any libraries or pure java2d? A bit of code of screen.repaint() and world.update() would be very helpfull. Also this: 1
| try{ Thread.sleep(1); }catch(Exception e){} |
won't cause any noticable change to the current behavior, as you set the thread to sleep for just 1 millisecond.
|
|
|
|
Herjan
|
 |
«
Reply #2 - Posted
2013-08-16 12:23:52 » |
|
I thought ur loop was really weird... I like to program loops like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public void run(){ long start, end, time, sleeptime; while(true){ try{ start = System.currentTimeMillis(); tick(); render(); end = System.currentTimeMillis(); time = end - start; sleeptime = 1000/60 - time; if( sleeptime < 0 ) sleeptime = 0; Thread.sleep(sleeptime); }catch(Exception e){} } } |
Oh, and about skipping frames, never do actions based on frames, but on time...
|
|
|
|
Games published by our own members! Check 'em out!
|
|
sirkarpfen
|
 |
«
Reply #3 - Posted
2013-08-16 12:33:05 » |
|
I thought ur loop was really weird...
The loop wasn't that bad, and doesn't cause framelags. And where does he do actions based on frames? He updates the game using the delta time (as everybody should do)  . An advice to both of you: 1 2 3 4 5 6 7 8 9 10 11 12
| while(true) { ... }
while(running) { ... }
|
|
|
|
|
Yemto
|
 |
«
Reply #4 - Posted
2013-08-16 12:44:28 » |
|
Okay, I going to fix the while(true) issue later. The problem I have is that, at low fps the objects will jump through other objects, since I'm currently using... 1 2 3 4 5
| @Override public void update(double delta){ addX(25.0 * delta); addY(25.0 * delta); } |
...to move objects. what I need to do is let the game logic catch up with the frames. That way I was thinking of doing that is to not skip frames. So the game logic still act like it's running in 60 fps, when the player only see 30
|
|
|
|
sirkarpfen
|
 |
«
Reply #5 - Posted
2013-08-16 12:55:48 » |
|
So lets say your delta time is about 0.01 seconds. It means you're moving your object about 0.25 pixels every frame and that means (with a framerate of about 60 fps) you move your objects 15 pixels every second. If you check for collisions every frame, there should be no problem at all.
You're gamelogic happens every frame, so you cannot "limit" it to the frames. That means every time something is drawn, the gamelogic is calculated before. Also you're logic doesn't "skip" frames, as your frames don't skip frames. if you halt your gameLoop because of fps limitation (thread.sleep()), no logic will be done, but also no rendering will be done.
Another case would be, if you would use a seperate thread for your gamelogic. But i don't think thats the case here.
|
|
|
|
Yemto
|
 |
«
Reply #6 - Posted
2013-08-16 13:05:36 » |
|
So lets say your delta time is about 0.01 seconds. It means you're moving your object about 0.25 pixels every frame and that means (with a framerate of about 60 fps) you move your objects 15 pixels every second. If you check for collisions every frame, there should be no problem at all.
You're gamelogic happens every frame, so you cannot "limit" it to the frames. That means every time something is drawn, the gamelogic is calculated before. Also you're logic doesn't "skip" frames, as your frames don't skip frames. if you halt your gameLoop because of fps limitation (thread.sleep()), no logic will be done, but also no rendering will be done.
Another case would be, if you would use a seperate thread for your gamelogic. But i don't think thats the case here.
You don't understand the issue. if the framerate becomes to low, the detla time can go up to 0.99 which can cause the object to jump through other objects, because it will be teleported 24 px. Anyway, I know my code don't skips frames. That is what I'm trying to implement. Let say I have two threads. one for game logic, and one for the frames. Wouldn't that cause issues/instability?
|
|
|
|
Opiop
|
 |
«
Reply #7 - Posted
2013-08-16 13:18:32 » |
|
No, don't do this. Having two threads is a terrible idea. This forum has a whole board dedicated to things like loops. Just search for game loop and implement one of them.
|
|
|
|
Yemto
|
 |
«
Reply #8 - Posted
2013-08-16 13:26:16 » |
|
No, don't do this. Having two threads is a terrible idea. This forum has a whole board dedicated to things like loops. Just search for game loop and implement one of them.
That's what I thought, and guess how I got hold of this one I have, I was thinking of having some if statement to skill screen.repaint(); to skip frames. But I'm not exactly sure how to do it.
|
|
|
|
SHC
|
 |
«
Reply #9 - Posted
2013-08-16 13:28:24 » |
|
If the framerate becomes to low, the detla time can go up to 0.99 which can cause the object to jump through other objects, because it will be teleported 24 px.
That's a known problem with variable timestep game loops. A solution is to make frames of constant length by using fixed timestep game loop. Now, let's make a game loop that keeps the game logic at the same rate and renders a frame if the maximum fps is not reached. Let's start by making some variables for the game loop. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| long now = getCurrentTime(); long gameTime = getCurrentTime();
long ups = 60;
long timeForLogic = 1000 / 60;
int framesSkipped= 0; int maxFrameSkip = 5;
int fps = 0; int frames = 0; long lastFpsCount = getCurrentTime(); |
Here, is just a method that returns the current time in milliseconds. Now, let's write the inner game loop. For better results, we separate rendering and logic. First, we need to only update the logic only when it is required. Did you notice that variable? It's is what we use to check when the update is required. So if the condition now + timeForLogic > gameTime |
is met, we need to update. Ok, but wee also need to check for frame limiting. So change the condition to (now + timeForLogic > gameTime) && (framesSkipped < maxFrameSkips) |
to make sure we render a frame in between. So now the code for the game loop will be 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| while (running) { framesSkipped = 0; now = getCurrentTime();
while ((now + timeForLogic > gameTime) && (framesSkipped < maxFrameSkips)) { world.update();
gameTime += timeForLogic; framesSkipped++; }
screen.repaint(); frames++;
if (now - lastFpsCount >= 1000) { fps = frames; frames = 0; } } |
And now, this limits the updates you have to do in a second, but rendering how many frames it can. Be careful that it uses the total cpu. To limit that, just sleep by 1 ms at the end of fps count.
|
|
|
|
Games published by our own members! Check 'em out!
|
|
Herjan
|
 |
«
Reply #10 - Posted
2013-08-16 13:33:37 » |
|
The loop wasn't that bad, and doesn't cause framelags. And where does he do actions based on frames? He updates the game using the delta time (as everybody should do)  . The title is: "Skip frames" and: My idea is to make the game not render all the frames when it runs slow, to try to get more time for the logic. This doesnt look like using time
|
|
|
|
Opiop
|
 |
«
Reply #11 - Posted
2013-08-16 14:08:00 » |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| long lastTime = System.nanoTime(); double nsPerTick = 1000000000D / 60D; int ups = 0; int fps = 0; long lastTimer = System.currentTimeMillis(); double delta = 0; while(game loop not quit blub) { long now = System.nanoTime(); delta += (now - lastTime) / nsPerTick; lastTime = now; boolean renderOK = false; while(delta >= 1) { ups++; update(); delta -= 1; renderOK = true; } if(shouldRender) { fps++; render(); } if(System.currentTimeMillis() - lastTimer >= 1000) { lastTimer += 1000; System.out.println("frames: " + fps + " | updates: " + ups); fps = 0; ups = 0; } } |
Use this. Just found it on the forum, I also use game loops like this and they have never failed me. Smaller code doesn't always make for better code.
|
|
|
|
GNecro1
|
 |
«
Reply #12 - Posted
2013-08-16 14:17:10 » |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| public int finalFrames = 0;
public void run() { long lastTime = System.nanoTime(); final double amountOfTicks = 60.0; double ns = 1000000000 / amountOfTicks; double delta = 0; int ticks = 0; int frames = 0; long timer = System.currentTimeMillis();
while (run) { long now = System.nanoTime(); delta += (now - lastTime) / ns; lastTime = now; if (delta >= 1) { tick(); ticks++; delta--; } draw(); frames++; if (System.currentTimeMillis() - timer > 1000) { timer += 1000; finalFrames = frames; frames = 0; ticks = 0; } } }
|
|
Java freak! 
|
|
|
Yemto
|
 |
«
Reply #13 - Posted
2013-08-16 15:16:54 » |
|
I ended up with 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| @Override public void run(){ long lastTime = System.nanoTime(); double ticksPerSec = 120.0; double tickTime = 1000000000.0 / ticksPerSec; long time = System.currentTimeMillis(); int ticks = 0; double delta = 0; while(running){ long now = System.nanoTime(); delta += (now - lastTime) / tickTime; lastTime = now;
while(delta >= 1){ world.update(0.01); delta -= 1; ticks++; } if(System.currentTimeMillis()-time >= 1000){ time = System.currentTimeMillis(); System.out.println("T:"+ticks); ticks = 0; } screen.repaint(); try{ Thread.sleep(2346); }catch(Exception e){} } } |
the reason why i don't reset delta in the while(running) loop is to let delta build up to 1 or higher, in which the while(delta) loop subtract that. with help of the sleep function I tested to run the game in 2 fps, and with 700 fps. I timed it and in both cases the objects had traveled the same distance.
|
|
|
|
SHC
|
 |
«
Reply #14 - Posted
2013-08-16 15:26:17 » |
|
@Yemto There are two things to say on your loop. System.currentTimeMillis() |
is not reliable across platforms. It is known to be lagging by 16-56 ms on windows. Always use - And why are you sleeping for a large time?
Glad that it's solved but those are my doubts and suggestions.
|
|
|
|
Opiop
|
 |
«
Reply #15 - Posted
2013-08-16 15:35:50 » |
|
Please for the love of god take out that sleep call. Don't be lazy, code it yourself. The sleep function may not work properly and can mess up your loop timing. If I'm correct.
|
|
|
|
Yemto
|
 |
«
Reply #16 - Posted
2013-08-16 16:22:04 » |
|
@Yemto There are two things to say on your loop. System.currentTimeMillis() |
is not reliable across platforms. It is known to be lagging by 16-56 ms on windows. Always use - And why are you sleeping for a large time?
Glad that it's solved but those are my doubts and suggestions. Thanks, I didn't know that about currentTimeMillies, and Thread.sleep was only for testing the code when it can't run optimally. Please for the love of god take out that sleep call. Don't be lazy, code it yourself. The sleep function may not work properly and can mess up your loop timing. If I'm correct.
for the love of god, read the comment in the code, and I needed help, someone provided me with a code that worked. I took a look at it and kept testing and changing it so it fitted with what I wanted.
|
|
|
|
Opiop
|
 |
«
Reply #17 - Posted
2013-08-16 19:16:29 » |
|
Ok, I'm sorry I completely missed the comment. I just saw a sleep call and immediately was a little angry... sorry again!
|
|
|
|
|