• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Android Game Loop

 
Stephen Bell
Ranch Hand
Posts: 41
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi All

My game is written using openGL on Android and I'm having a bit of a hard time trying to understand the main game-loop

I've read Dewitters Game Loop many times, and it's a really good article. However there are some things it doesn't address.

At the moment, this is what I have:



At the moment, all I'm concerned with is limiting the game updates (ticks per second). As for rendering I can leave that for another day, so right now, this loop is supposed to limit the ticks per second to 60 and let the rendering go as fast as the device can handle.

However, when I run this on my tablet (Nexus 10) the result isn't quite what I'd hoped, it averages between 62 and 65 and when I run it on an old Galaxy Ace handset, it could be the same or slightly higher.

Can anyone see anything obviously wrong with my code?

Many thank all!


 
Steve Luke
Bartender
Posts: 4181
22
IntelliJ IDE Java Python
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think your main problem is how and where you do the check on the number of ticks. Your entire loop is in the onDrawFrame() method, and you aren't really controlling when that method gets called, the OS is (more accurately, the screen display is, I think). And so you could get a couple ticks to go by, the screen renders but a second hasn't passed yet (so no log) and the method comes to an end. Then then a couple more frames come by, render, no second ticks by, so no log and the method ends. This cycle continues a few times, and finally a second ticked off between calls to onDrawFrame. You had 60 lined up before the second ticked by, then two more logic frames kick by and you render and when you get to logging the output, more than a second went by and more than 60 ticks were recorded. You log the ticks, but not the time those ticks occurred over, so your count of ticks per second would be off. It very well could be that your app is updating 60 times per second but your logging doesn't capture actually ticks per second, it captures ticks since the last time ticks were reset.

Also, System.currentTimeMillis() isn't a very trusted means of calculating elapsed time on mobile devices. A better approach might be SystemClock.uptimeMillis() or SystemClock.ellapsedRealtime() (see SystemClock). This prevents clock resets from being a problem (a user could set the clock, the time could be set automatically from a network time server, time zones changed, etc...)

I am not sure I particularly like this layout - where the vsync controls both the drawing and the game update. I would consider one of two options:
1) Create your own logic thread which loops more-or-less continuously (that whole while(running) outer loop in the linnk you provided) that does the updateLogic() call in your method (with its inner while loop to control it to 60 ticks/s). If you changed the render method to manual, you would then call the GLSurfaceView's requestRender() method in place of your render(). This would trigger a call to onDrawFrame() in which you do your painting. If you did not set the render mode to manual, the game re-renders at vsync speed (I think) so you don't need to request render, onDrawFrame() would be called automatically.


I think this approach, with manual rendering, closely matches what is described in the link you posted.

2) I am not very keen on close loops like the the one provided in the link you gave and described above. I would much prefer having the logic thread schedule when it needs activity so it doesn't drain as much power and gives other things a chance to run. You might consider using a ScheduledExecutorService to schedule the logic. It doesn't make any guarantees about precision in time, but would be much friendlier to the mobile device's battery. In this case you would make a simple Runnable which calls updateLogic() then schedules it for every 1/60th of a second. You would let the renderer render automatically or request renders like above, and since your renders are done in a different thread they won't interfere with logic updates.

A couple of other things to note: Both of these approaches use different threads for the logic and the rendering, while putting it all in onDrawFrame() puts the logic in the same thread as the rendering. The former is more likely to render smoothly but requires thread-safe data sharing so you would need to consider that. The latter is easier to implement but rendering interferes with logic and logic interferes with rendering, so the game can get choppy. I like to keep painting and Logic on different threads myself, but I have to admit I am not a game programmer so the timing requirement may need a single thread approach, or a closed loop like the one described above.
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic