Java-Gaming.org    
Featured games (91)
games approved by the League of Dukes
Games in Showcase (576)
games submitted by our members
Games in WIP (498)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Understanding Active Rendering game loops  (Read 7158 times)
0 Members and 1 Guest are viewing this topic.
Offline Swattkidd7

Junior Member





« Posted 2011-07-14 23:38:04 »

Hey everyone, I have been programming my past games using the "traditional" method of just having the run method sleep for a certain amount of time and then repainting, however want to switch to the Active Rendering method.

I am having trouble finding articles, tutorials, etc. on this topic and am having trouble figuring out how to implement it. Looking at the source code for Metagun by notch I was able to implement his loop into my game, however do not understand certain parts.

Why does the code sleep for 500 seconds beforehand? If i take this piece of code out, I get a NullPointer error when trying to render the screen, not sure why this is happening.

But my main questions is what does the while(unprocessedTime > 0) loop does.

lastly, how would I implement an FPS counter in this type of loop?

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  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
public void run() {
        requestFocus();
        Image image = new BufferedImage(320, 240, BufferedImage.TYPE_INT_RGB);
        setScreen(new TitleScreen(this));

        long lastTime = System.nanoTime();
        long unprocessedTime = 0;
       
       [b] try {
            Thread.sleep(500);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }[/b]
   
        while (running) {
            Graphics g = image.getGraphics();

            long now = System.nanoTime();
            unprocessedTime += now - lastTime;
            lastTime = now;

            int max = 10;
            [b]while (unprocessedTime > 0) {
                unprocessedTime -= 1000000000 / 60;
                fps = unprocessedTime;
                screen.update(input);
                input.update();
                if (max-- == 0) {
                    unprocessedTime = 0;
                    break;
                }
            }[/b]
            screen.render(g);
            g.dispose();

            try {
                started = true;
                g = getGraphics();
                g.drawImage(image, 0, 0, GAME_WIDTH * SCREEN_SCALE, GAME_HEIGHT * SCREEN_SCALE, 0, 0, GAME_WIDTH, GAME_HEIGHT, null);
                g.dispose();
            } catch (Throwable e) {
            }
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


Thanks guys, any resources, links or anything at all will help, I really want to learn what is happening rather then just get it working.
Offline Karmington

Senior Member


Medals: 1
Projects: 1


Co-op Freak


« Reply #1 - Posted 2011-07-15 01:40:45 »

The first bold area, sleeping for 500 (millisecs ), half a second sleeping? The objective is to stacktrace and catch unexpected exceptions. Anyhow this only done once at start. Perhaps there is system where you have to wait to load some images/sounds before execution, and this half second gives it time to do so. Java is a bit ugly in this territory, I remember j2me not being at all nice in this. If you load something, it does it in the background or something? And if you try to start immediately it gives the Nullpointer. You have to make your own clean loaders perhaps.

Next boldness, i think here the idea is to go through updates depending on performance, if necessary go through many updates. So if unprocessed time is large, it will do multiple screen/logic updates before reaching render. In this case, the screen.update probably contains stuff that makes things move around on screen, so it has to be done to maintain overall logic.

So, an excellent example of a not-so-readable main loop. Optimally the sleeper would be explained, and the fps=unprocessedtime line would perhaps be chucked, since it is unlikely to give correct values - or does it?



Offline Swattkidd7

Junior Member





« Reply #2 - Posted 2011-07-15 02:26:41 »

Ahh yes, I guess that does make sense about the loading the resources, I guess it gives it time to load up before actually using them. I should just make it into a nicer loading method or something. (this was taken from a contest entry so I dont believe the intention of the code was to be presentable, but I actually enjoy going through it)

I see so what this loop is doing is making sure that if there was too much of a delay(?) it will keep the game logic going because a mis-step in this could change things, but once its caught up, render it all?

Lol sorry, the fps = unprocessedTime; was something I did just to see what the value for that was, somehow it got left in there.

But what I am not understanding is, this loop is updating at what FPS? because it seems to be tick based in the original code, how would I make movement, shooting and all of that uniform. For example I have seen some games that use Active Rendering run at 500 FPS, I would not want my character to update x+=5; at that rate correct?

Also if someone has a more readable game loop, i would really appreciate seeing that.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline JL235

JGO Coder


Medals: 10



« Reply #3 - Posted 2011-07-15 03:20:21 »

In regards to the FPS, what you are talking about is something different called 'delta time'. It is a little similar, in that it is based on the speed of the game, but it's aim is to generate a multiplier that you use for multiplying against all changing values. So rather then x += 5, it becomes x += 5*delta.

If the game is running at 500fps (which IMHO is waaaaaaaaaaay too fast and should be capped to a much lower value), then delta time will be a very small number (so you only move a small amount). If the game is running at 10fps, delta time should be large number (so you move much further then normal). Normally the expected speed for delta time to be based on is 60fps. So if your game is running at 60fps, delta time is 1, and at 30fps delta time becomes 2 (because your at half the speed).

I believe the algorithm is something along the lines of:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
// how long a frame should take, which is around 16.6 milli seconds
double idealTime = 1000.0 / 60.0;

long lastTime = time();

while ( true ) {
    long now = time();
    long diff = now - lastTime;
    double delta = diff / idealTime ;
   
    // update your game here
   
    lastTime = now;
}

Note that the above is just psudo-code. The '1000' in '1000 / 60' is 1 second in milliseconds, and if your using nano or micro seconds instead then you will need to change this value accordingly. You should also cap your maximum and minimum delta time values (and your maximum fps too), as any odd pauses can cause delta time to become very large to the point that it just messes up your game.

I'd also personally be interested in any better algorithms then the above; I've heard of people smoothing delta time over several frames and things like that, but it always just looks buggy when I've tried implementing this.

As for your mainloop, where is the null pointer occurring? It's been a while since I've written a mainloop in Java, but I don't remember having to sleep for half a second first. AFAIK there should be no real reason why you need to sleep for half a second, and if you do have to wait for something to get ready first then that seems like a very hacky way of checking (it would be better to check if it is safe to start or not).

Offline ra4king

JGO Kernel


Medals: 322
Projects: 2
Exp: 4 years


I'm the King!


« Reply #4 - Posted 2011-07-15 03:26:06 »

My game loop:
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  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
final int FPS = 60;
final long ONE_SECOND = (long)1e9;
int maxUpdates = /*user specified*/
int frames = 0;
int currentFPS = 0;
long time = System.nanoTime();
long lastTime = System.nanoTime();

isActive = true;

while(isActive()) {
   long diffTime = System.nanoTime()-lastTime;
   lastTime += diffTime;
   
   int updateCount = 0;
   
   while(diffTime > 0 && (maxUpdates <= 0 || updateCount < maxUpdates)) {
      long deltaTime = FPS > 0 ? deltaTime = Math.min(diffTime,ONE_SECOND/FPS) : diffTime;
     
      try{
         update(deltaTime);
      }
      catch(Exception exc) {
         exc.printStackTrace();
      }
     
      diffTime -= deltaTime;
     
      updateCount++;
   }
   
   try{
      do{
         do{
            Graphics2D g = (Graphics2D)strategy.getDrawGraphics();
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,quality);
           
            try{
               paint(g);
            }
            catch(Exception exc) {
               exc.printStackTrace();
            }
           
            if(showFPS) {
               g.setColor(Color.black);
               g.setFont(new Font(Font.SANS_SERIF,Font.TRUETYPE_FONT,10));
               g.drawString(currentFPS + " FPS",2,getHeight()-2);
            }
           
            g.dispose();
         }while(strategy.contentsRestored());
         
         strategy.show();
      }while(strategy.contentsLost());
   }
   catch(Exception exc) {
      exc.printStackTrace();
   }
   
   frames++;
   
   if(System.nanoTime()-time >= ONE_SECOND) {
      time = System.nanoTime();
      currentFPS = frames;
      frames = 0;
   }
   
   try{
      if(FPS > 0) {
         long sleepTime = Math.round((ONE_SECOND/FPS)-(System.nanoTime()-lastTime));
         if(sleepTime <= 0)
            continue;
         
         long prevTime = System.nanoTime();
         while(System.nanoTime()-prevTime < sleepTime) {
            if(useYield)
               Thread.yield(); //Smoother game loop, more CPU usage
           else
               Thread.sleep(1); //Less CPU usage but not as smooth as yield()
        }
      }
   }
   catch(Exception exc) {
      exc.printStackTrace();
   }
}


EDIT: If not waiting for 500ms causes a NPE, then that means there is a second thread loading resources.

Offline Swattkidd7

Junior Member





« Reply #5 - Posted 2011-07-15 07:03:44 »

@JL235 Thanks, that explanation helps me understand how to calculate the FPS, although I was curious as to how to implement that within the game loop that I posted, because that while loop within the while(running) throws me off completely as to what is happening. Also that sleep 500 was definitely a hack of getting it to work, it was written for a competition so I assume the author just wanted to get things working.

@R4KING, thanks for that, however I am curious as to the loops that use Thread.sleep(1), I have seen it used quite a bit but cant seem to grasp it. I will definitely think about implementing something like your code though.

Actually I think I got it working for the most part, (not sure yet so wont post anything) but thanks guys for the help, R4KING your example helped a lot so thanks again. Also here is a helpful link for people in the future who see this thread

http://www.koonsolo.com/news/dewitters-gameloop/
Offline ra4king

JGO Kernel


Medals: 322
Projects: 2
Exp: 4 years


I'm the King!


« Reply #6 - Posted 2011-07-15 08:02:48 »

Thread.sleep(int) is unreliable so I use yield() or sleep(1) in a while loop.
yield() produces a smoother game loop but hogs the CPU.
sleep(1) uses very little CPU time but the game loop is not as smooth.

Online princec

JGO Kernel


Medals: 282
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #7 - Posted 2011-07-15 11:35:28 »

While in debug mode I use sleep(), and on single core machines I use sleep() as well by default; in dual core or release code I use yield(). And I provide a commandline switch to force it one way or the other. Cover all your bases Smiley

Cas Smiley

Offline ra4king

JGO Kernel


Medals: 322
Projects: 2
Exp: 4 years


I'm the King!


« Reply #8 - Posted 2011-07-15 22:14:32 »

Cover all your bases Smiley
All your sleep are belong to us!

Offline Swattkidd7

Junior Member





« Reply #9 - Posted 2011-07-30 01:11:53 »

Hey guys, I have my loop updating at a constant 60 FPS, and then the rendering has no limit. However, if I have a block (just one block) moving left and right on the screen it twitches a bit from time to time.It isnt a constant twitch where I can predict where it will stutter, but just randomly it stutters. The time is still updating at the correct rate however it stutters.

I am not sure what could be causing this because the rendering is at its own rater (higher than 60 FPS).

Some ideas I have are that the code to keep updating at a constant rate is in a while loop and after that is rendering code. So if the loop some how falls behind, while it is catching up it is not rendering and therefore when it finally catches up the block jumps to the new position?

here is my loop, please dont be too harsh its roughly put together
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  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
public void run()
    {
        Image image = new BufferedImage(GAME_WIDTH,GAME_HEIGHT, BufferedImage.TYPE_INT_RGB);
        setScreen(new TitleScreen(this));

        int TICKS_PER_SECOND = 60;
        int ONE_SECOND = 1000000000;
        int SKIP_TICKS = ONE_SECOND / TICKS_PER_SECOND;
        int MAX_FRAMES_SKIP = 10;

        int currentFPS = 0;
        int frames = 0;
        long timePast = System.nanoTime();
        long time = System.nanoTime();

        int loops;

        while (running)
        {
            Graphics g = image.getGraphics();

            loops = 0;
            while (System.nanoTime() > time && loops < MAX_FRAMES_SKIP)
            {
                screen.update(input);
                input.update();
                time += SKIP_TICKS;
                loops++;
            }

            screen.render(g);
            if(!hasFocus())
            {
                g.setColor(Color.red);
                g.drawString("CLICK FOR FOCUS", Game.GAME_WIDTH/2-80,Game.GAME_HEIGHT/2);
            }
            g.dispose();

            frames++;

            if (System.nanoTime() - timePast >= ONE_SECOND)
            {
                timePast = System.nanoTime();
                currentFPS = frames;
                frames = 0;
            }

            try
            {
                g = getGraphics();
                g.drawImage(image, 0, 0, GAME_WIDTH * SCREEN_SCALE, GAME_HEIGHT * SCREEN_SCALE, 0, 0, GAME_WIDTH, GAME_HEIGHT, null);
                g.dispose();
            } catch (Throwable e)
            {
            }
            try
            {
                Thread.yield();
            } catch (Exception e)
            {
                e.printStackTrace();
            }

        }

    }
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline philfrei
« Reply #10 - Posted 2011-07-30 01:49:35 »

Hi -

You might find this neighboring thread interesting:

http://www.java-gaming.org/topics/slight-jerkiness/24311/view.html

Ostensibly that thread is about using a game loop in a passive rendering situation (and in my case, via a "scheduled" game loop algorithm), but the timing aspects dealt with could be pertinent just the same.

As a result of the investigations there, I was able to both get a better idea of what is going on with the various time-related objects and how they interact with the time info provided by the OS. If you have WindowsXP, for instance, there are many ways to run afoul of its 15msec system clock interrupt.

Pretty amazing, though, that one can run a long sleep thread in the background, from the start of the program, and this prompts the OS to use a more precise (though slightly costlier) means of getting the time. Doing so might clear up some of your timing problems.

In particular, check out post #16.

My programs are definitely running smoother now. I posted there a simple tool for timing durations between game loops that might help in diagnosing the problem. (#11)

"Greetings my friends! We are all interested in the future, for that is where you and I are going to spend the rest of our lives!" -- The Amazing Criswell
Offline Swattkidd7

Junior Member





« Reply #11 - Posted 2011-07-30 02:45:03 »

Hey thanks for the reply, I did try adding that long sleep thread in the beginning of my program but the same stuttering occurs, still have no idea what could be causing it but thanks for the link, ill continue to read up and see if i can figure it out, but any help is appreciated.

Specifically, is there anyone here that has a basic gameloop that doesnt stutter (similar to this active rendering approach)?
Offline ra4king

JGO Kernel


Medals: 322
Projects: 2
Exp: 4 years


I'm the King!


« Reply #12 - Posted 2011-07-30 10:23:19 »

Scroll up and check out my post (Post #4) on this thread.

Online princec

JGO Kernel


Medals: 282
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #13 - Posted 2011-07-30 12:23:45 »

Just 2p more to throw in here - on Vista and Win 7 the desktop compositor runs unfortunately independently of the refresh rate in your windows and sometimes it doesn't actually update every frame for whatever reason. End result is: I get a display which claims to be updating at 60Hz and even has data to prove it but Windows manages to make it glitch and drop a frame here and there now and again.

Doesn't happen in fullscreen, and not sure if this is purely OpenGL related or happens with Direct3D rendered windows, but just something I have observed. The slower the machine is the more likely the display update glitches are.

Cas Smiley

Offline Swattkidd7

Junior Member





« Reply #14 - Posted 2011-08-02 10:01:14 »

Hey guys, i have done some further test and see that the stuttering seems to happen completely randomly, even when the update loop is not catching up it just happens to stutter. I have a plain java2D block going left and right on the screen and it appears to jump forward and then jump back. I have no idea what could be causing it because the game is running at a constant 60 FPS, the rendering is much higher than that and the code is not putting a burden on the update loop causing it to catch up.

Sorry if any of you have mentioned something that would be a solution to this, I am just trying to understand this all and may not have understood what you meant, but from what I have been trying. I am yet to figure it out.
Offline ra4king

JGO Kernel


Medals: 322
Projects: 2
Exp: 4 years


I'm the King!


« Reply #15 - Posted 2011-08-02 23:23:59 »

Try using Canvas + BufferStrategy.

Offline Swattkidd7

Junior Member





« Reply #16 - Posted 2011-08-04 12:51:51 »

I converted it to Canvas and used the bufferstrategy, as followed by this tutorial

http://www.gamedev.net/page/resources/_/reference/programming/languages/java/java-games-active-rendering-r2418

although the result seems to be a bit better, still see a quit stutter here and there

*edit* I even ripped the drawing code from your loop posted and it still stutters... does anyone have a full example of just a simple block going left and right at speed 5 pixels without stuttering? that is all I am trying to achieve and its insane to me that nothing seems to be solving such a small problem.
Offline counterp

Senior Member


Medals: 11



« Reply #17 - Posted 2011-08-04 13:22:53 »

have any runnable code? an example application that stutters for you?
Offline Swattkidd7

Junior Member





« Reply #18 - Posted 2011-08-04 13:50:41 »

Here is a link to a quick example that I just wrote that shows the stuttering. I am not sure where I could upload the zip file of the source though.

link to the example
http://dl.dropbox.com/u/30070606/Example/example.jar

**edit, heres the http://cksgames.com/stutter/src.zip
Offline counterp

Senior Member


Medals: 11



« Reply #19 - Posted 2011-08-04 13:54:12 »

OK I notice the stutter, isn't the app small enough to just post the code here?
Offline Swattkidd7

Junior Member





« Reply #20 - Posted 2011-08-04 14:26:36 »

OK I notice the stutter, isn't the app small enough to just post the code here?

I linked to the source code, although Idk what happened to my link to the app...did you really see the app or did the link disappear? also the code is extremely basic, but I made it using my "library" but it is really only 4 files, 2 of them are significant, GameScreen (where the block is moved and drawn) and Game (the loop)
Offline ra4king

JGO Kernel


Medals: 322
Projects: 2
Exp: 4 years


I'm the King!


« Reply #21 - Posted 2011-08-04 15:01:39 »

Try this, I just made it right now: http://ra4king.is-a-geek.net/games/Stutter
Also try my JDoodleJump game: http://ra4king.is-a-geek.net/games/JDoodleJump

I saw stuttering your jar, but I don't see stuttering in either of my games. However, if you still do, then that is normal Java2D behavior since it is known to be quite slow and stuttering.

Both were made using my library: http://code.google.com/p/java-game-utils

EDIT: The source:

Stutter.java
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  
32  
33  
34  
35  
36  
37  
38  
package stutter;

import gameutils.Game;
import gameutils.gameworld.GameWorld;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;

public class Stutter extends Game {
   private static final long serialVersionUID = 6410054290342779730L;
   
   public static void main(String args[]) {
      Stutter game = new Stutter();
      game.setupFrame("Stutter", 800, 300, false);
      game.start();
   }
   
   protected void initGame() {
      setSize(800,300);
     
      useYield(true);
     
      GameWorld world = new GameWorld();
      world.add(new Block(200));
      setScreen(world,"GameWorld");
   }
   
   public void paint(Graphics2D g) {
      g.setColor(Color.white);
      super.paint(g);
     
      if(isPaused() && System.currentTimeMillis()/500%2 == 0) {
         g.setFont(new Font(Font.SANS_SERIF,Font.BOLD,30));
         g.drawString("Click to run!", getWidth()/2-50, getHeight()/2+20);
      }
   }
}


Block.java
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  
32  
33  
34  
35  
36  
package stutter;

import gameutils.gameworld.GameComponent;

import java.awt.Color;
import java.awt.Graphics2D;

public class Block extends GameComponent {
   private int speed;
   
   public Block(int speed) {
      super(0,125,50,50);
      this.speed = speed;
   }
   
   public void update(long deltaTime) {
      setX(getX()+speed*deltaTime/1e9);
     
      if(getX()+getWidth() > getParent().getWidth()) {
         speed = -speed;
         setX(getParent().getWidth()-getWidth());
      }
      else if(getX() < 0) {
         speed = -speed;
         setX(0);
      }
   }
   
   public void draw(Graphics2D g) {
      g.setColor(Color.black);
      g.fillRect(0,0,getParent().getWidth(),getParent().getHeight());
     
      g.setColor(Color.green);
      g.fill(getBounds());
   }
}

Offline Swattkidd7

Junior Member





« Reply #22 - Posted 2011-08-05 00:49:05 »

Thanks for the code and example, although I seem to see stuttering in your example also...I guess this is just something that will happen no matter what, and in a game setting I doubt it will be noticeable
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

xsi3rr4x (15 views)
2014-04-15 18:08:23

BurntPizza (13 views)
2014-04-15 03:46:01

UprightPath (27 views)
2014-04-14 17:39:50

UprightPath (12 views)
2014-04-14 17:35:47

Porlus (29 views)
2014-04-14 15:48:38

tom_mai78101 (51 views)
2014-04-10 04:04:31

BurntPizza (110 views)
2014-04-08 23:06:04

tom_mai78101 (211 views)
2014-04-05 13:34:39

trollwarrior1 (179 views)
2014-04-04 12:06:45

CJLetsGame (185 views)
2014-04-01 02:16:10
List of Learning Resources
by Longarmx
2014-04-08 03:14:44

Good Examples
by matheus23
2014-04-05 13:51:37

Good Examples
by Grunnt
2014-04-03 15:48:46

Good Examples
by Grunnt
2014-04-03 15:48:37

Good Examples
by matheus23
2014-04-01 18:40:51

Good Examples
by matheus23
2014-04-01 18:40:34

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:22:30

Anonymous/Local/Inner class gotchas
by Roquen
2014-03-11 15:05:20
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!