Framerate and game loop on mobile - android

I'm searching how to manage game framerate on mobiles devices, here is my problem:
On a computer with got something like that:
void main()
{
while(game.isRunning())
{
event.handle(eventInfos);
game.update(dt);
graphic.render();
}
}
On a mobile device with got something like that:
void update()
{
game.update(dt);
}
void render()
{
game.render(dt);
}
void event()
{
game.handle(eventInfos);
}
When I search on internet, I found something like that everytime:
-> GameLoop
-> Fix your time step
I'm using IOS (With GLKViewController) and Android (with the NDK), and I've that rendering method is call from another thread
Thanks for your help!

I findthe GameLoop link you have posted is very straight forward, he runs a thread which in its turn check for right time to call update() in these lines
while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) {
// we need to catch up
// update without rendering
this.gamePanel.update();
// add frame period to check if in next frame
sleepTime += FRAME_PERIOD;
framesSkipped++;
}

Related

Time delays and game loop

I'm doing a simple match-3 game and I'm currently using a game loop like the code below. I'm using some frame calculations for optimal speed of th game. I took this from another game that I have done before. But this seems unnecessary for this type of game.
I need to have some time delays at several places, like when I have moved an object on the game area, I want a short time delay before the call to an method that check if there is a match of three objects in a row. And then I also need a short time delay when the code has detect a match, so that I can do some simple effect at those positions in the game grid before the user starts to move another object and then check for a match.
As it is now every thing happens at once and I wonder if it would be better to run this game without this calculations of frames and how I could do instead to get some time delays?
I have tested to use Thread.sleep(250) inside this code, but didn't worked the way I hade hoped for.
What could be a better approach for running a game like this?
// Game loop ---------------------------------------
#Override
public void run() {
// TODO Auto-generated method stub
long beginTime;
long timeDiff;
int sleepTime;
int framesSkipped;
sleepTime = 0;
while (gameRunning) {
if (!surfaceHolder.getSurface().isValid())
continue;
try {
canvas = surfaceHolder.lockCanvas();
beginTime = System.currentTimeMillis();
framesSkipped = 0;
// Different game states
switch (gameState) {
case 0: // Intro game
drawStartPage(canvas);
break;
case 1: // Play game
canvas.drawRGB(0,0,0);
if(touchActionDown) {
touchActionDown = false;
colorObjectManager.checkPosition(touchX, touchY);
touchActionMove = false;
}
if(touchActionMove) {
touchActionMove = false;
colorObjectManager.swapObject(moveDirection);
// Time delay
colorObjectManager.checkMatch();
// Time delay
}
// Call method to draw objects on screen
colorObjectManager.drawObjectsList(canvas);
break;
case 2: // End game
break;
}
// Calculate difference from first call to
// System.currentTimeMillis() and now
timeDiff = System.currentTimeMillis() - beginTime;
// Calculate sleepTime
sleepTime = (int) (FRAME_PERIOD - timeDiff);
if (sleepTime > 0) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
}
}
while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) {
// Call method to only update objects on screen
updateObjects();
sleepTime += FRAME_PERIOD;
framesSkipped++;
}
} finally {
surfaceHolder.unlockCanvasAndPost(canvas);
}
} // End while-loop
}
// End game loop ---------------------------------------
I suggest use libgdx its a simple frameWork and you dont need to Calculate the DeltaTime.
AFAIK Dont use the Thread sleep on a surfaceholder use a seperate thread and lock the canvas.
you can use android animations. fadein fadeout to be fancy.
//some other method to delay
new Handler().postDelayed(new Runnable()
{
#Override
public void run()
{
// your code here
}
}, 1000/* 1sec delay */);
also got a very lame solution
//for 5 second of delay
for(int i=0;i<5000:i++){
for(int k=0;k<5000:k++){
for(int j=0;j<5000:j++){
}
}
}

Is there an easy way to set up Android to only update screen when it needs to?

I am making a board game. The board doesn't ever move, but pieces on top of it sometimes do depending on user interaction. There are also UI elements which may update periodically.
Right now the way I set it up is by overwriting the onDraw() method of a SurfaceView subclass. I have a drawing thread that constantly calls postInvalidate() in a while loop:
class PanelThread extends Thread
{
//...
long sleepTime = 0;
long nextGameTick = System.currentTimeMillis();
#Override
public void run()
{
Canvas c;
while (_run)
{ // When setRunning(false) occurs, _run is
c = null; // set to false and loop ends, stopping thread
try
{
c = _surfaceHolder.lockCanvas(null);
synchronized (_surfaceHolder)
{
// Insert methods to modify positions of items in onDraw()
_panel.postInvalidate();
}
} finally
{
if (c != null)
{
_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
nextGameTick += MILLISECONDS_PER_FRAME;
sleepTime = nextGameTick - System.currentTimeMillis();
if(sleepTime >= 0)
{
try
{
sleep(sleepTime, 0);
} catch (InterruptedException e)
{
continue;
}
}
else
{
//we're behind, oh well.
System.out.println("behind!");
nextGameTick = System.currentTimeMillis();
}
}
}
This is not efficient and is taking a lot of CPU. Is there a easy way to get android to only update when something changes?
You have the right idea, but it needs a bit of refinement.
You definitely do not want to loop as fast as the CPU can handle it though.
You should be sleeping your Thread in every loop for a little while. You most certainly do not need to do everything in your loop every millisecond.
I found this guide to FPS control to be incredible helpful in designing a game loop.
This Android-specific game loop guide also provides a lot of great sample code and an in-depth explanation.

Surface view drawing thread - busy loop?

All examples of the use of a SurfaceView seems to use a run method that performs a busy loop. Is that a valid way to do this? All the code I can see follows this paradigm from the lunar lander sample. However, creating a busy while loop seems to be a strange way to code multi threaded apps. Shouldnt the drawing code wait on a queue of drawing commands, or something similar. I would have implemented it that way, but the amount of code that I see that does is like below makes me ask the question... What is the best semantics for a thread drawing on a SurfaceView.
public void run() {
while (mRun) {
Canvas c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
// DO DRAWING HERE
}
} finally {
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
I don't know what is best practice in this case, but I have successfully used a slightly modified version of that example in my apps. Since I respond to touch input (rather than continuously updating the canvas) I added a flag to test if drawing even needs to be done. I also added a sleep after each refresh to limit system load. This is my code inside of the try block:
if(mPanel.needsRefresh()) {
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
mPanel.onDraw(c);
}
} else {
SystemClock.sleep(10);
}

Android gameloop, update and draw separate or not?

I'm just picking up android development to make a game. Touched it before, but only picked up the basics. I'm a bit confused how to set up a main loop. I've been into XNA (C#) and I love the separated update/draw loop.
I was wondering how a typical android gameloop works? I've searched online and came across 2 methods:
public void run() {
while (running) {
//Method 1: update is called here
view.update();
Canvas c = null;
try {
c = view.getHolder().lockCanvas();
synchronized (view.getHolder()) {
//Method 2: update is called inside view.onDraw
view.onDraw(c);
}
} finally {
if (c != null) {
view.getHolder().unlockCanvasAndPost(c);
}
}
}
}
Let's take the updating of game entities as an example for the 2 methods:
//METHOD1
public void onDraw(Canvas canvas)
{
for (GameEntity entity : entities)
{
entity.update();
entity.draw(canvas);
}
}
//END METHOD 1
//METHOD 2
public void update()
{
for (GameEntity entity : entities)
{
entity.update();
}
}
public void draw(Canvas canvas)
{
for (GameEntity entity : entities)
{
entity.draw(canvas);
}
}
//END METHOD 2
Now I have no experience with threads whatsoever, so I have no idea how XNA does the update/draw loops behind the screens in xna.
But using method 1, I would have to loop through all the entities twice, once for updating and another time for seperate drawing. I'm afraid this will kill the performance, but I háve seen this in samples online.
Am I missing something or am I right and is method 2 the best performance wise?
It matters not how many times you loop since it only matters how many actions you do. And the amount of actions done are basicly the same. since the second "for" only adds an one more supposed "if" for each entety. So its not much.
But it gives you the ability to do only one of the actions and not forced to do both.
for example: if I want the game to update 60 times per sec but only draw 40 fps, I can only do that in method 2. This allows you to have a more fluid game with less calculations, but only if you use it right.
If you have the darw and update happen at the same rate, then it is stupid to split them

Android: Thread pausing intermittently

having some trouble with a Thread (CanvasThread) that is intermittently pausing at random points within my application. Everything else in the app continues to function as necessary, it's simply this thread that randomly blocks out for some reason and doesn't draw anything new to the screen. I noticed that Surface.lockCanvasNative() seems to be the last function called before the block, and the first one returned after. In a pattern as such:
Surface.lockCanvasNative (Landroid/graphics/Rect)Landroid/graphics/Canvas; # 26,560 msec ____
Surface.lockCanvasNative (Landroid/graphics/Rect)Landroid/graphics/Canvas; # 40,471 msec ____|
Surface.lockCanvasNative (Landroid/graphics/Rect)Landroid/graphics/Canvas; # 40,629 msec ____
Surface.lockCanvasNative (Landroid/graphics/Rect)Landroid/graphics/Canvas; # 54,516 msec ____|
This is evident with the traceview below:
I have been using the CanvasThread.run() below if it helps:
#Override
public void run() {
boolean tellRendererSurfaceChanged = true;
/*
* This is our main activity thread's loop, we go until
* asked to quit.
*/
while (!mDone) {
/*
* Update the asynchronous state (window size)
*/
int w;
int h;
synchronized (this) {
// If the user has set a runnable to run in this thread,
// execute it and record the amount of time it takes to
// run.
if (mEvent != null) {
mEvent.run();
}
if(needToWait()) {
while (needToWait()) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
if (mDone) {
break;
}
tellRendererSurfaceChanged = mSizeChanged;
w = mWidth;
h = mHeight;
mSizeChanged = false;
}
if (tellRendererSurfaceChanged) {
mRenderer.sizeChanged(w, h);
tellRendererSurfaceChanged = false;
}
if ((w > 0) && (h > 0)) {
// Get ready to draw.
// We record both lockCanvas() and unlockCanvasAndPost()
// as part of "page flip" time because either may block
// until the previous frame is complete.
Canvas canvas = mSurfaceHolder.lockCanvas();
if (canvas != null) {
// Draw a frame!
mRenderer.drawFrame(canvas);
mSurfaceHolder.unlockCanvasAndPost(canvas);
//CanvasTestActivity._isAsyncGoTime = true;
}
else{
Log.v("CanvasSurfaceView.CanvasThread", "canvas == null");
}
}
}
}
Just let me know if I can provide any other useful information. I'm simply looking for clues as to why my thread might be blocking at this point? Thanks for any help in advance!
I've since narrowed the block down to mSurfaceHolder.unlockCanvasAndPost(canvas); I inserted a log before and after this call and the one after is not logged after app is frozen; but the log before is last logged event on this thread. It's not pausing or using a null canvas either, because I threw in logs for those instances as well; which are not logged even once until app is done.
I'm not sure if this could be the reason, but under SurfaceHolder.lockCanvas(), it warns that,
If you call this repeatedly when the
Surface is not ready (before
Callback.surfaceCreated or after
Callback.surfaceDestroyed), your calls
will be throttled to a slow rate in
order to avoid consuming CPU.
If null is not returned, this function
internally holds a lock until the
corresponding
unlockCanvasAndPost(Canvas) call,
preventing SurfaceView from creating,
destroying, or modifying the surface
while it is being drawn. This can be
more convenient than accessing the
Surface directly, as you do not need
to do special synchronization with a
drawing thread in
Callback.surfaceDestroyed.
I'm not sure what the threshold is when the CPU starts throttling. How many threads are refreshing the canvas?
btw,
if(needToWait()) {
while (needToWait()) {
is redundant
I have since figured out my problem. I'm not sure why but because I had accidentally forgot to fully comment out an earlier asyncTask(), thus had two doing roughly the same tasks and obviously struggling to do so with the same variables and such. Thanks for your pointers, but simply another careless mistake on my part I guess.

Categories

Resources