Android FPS, how to make it smoother? - android

I am having trouble in constructing a basic game loop for my game. I am at the early phase and all I want to do is to move the the ball at a constant speed (for ex: 3) through the bottom of the screen. The position of the ball is updated in the main panel update method and it is drawed in the render part as expected. Nothing exceptional in the mechanism. The ball moves but it is definitely not smooth, the visual is quiet disturbing.. I measured the implementation times of these methods and the total implementation time of this couple is about 3-4 milliseconds. Under these circumstances, what is the suitable FPS? Are the given constant values suitable What is missing or wrong in my mechanism? Thanks a lot in advance. the code block in main thread.
private final static int MAX_FPS = 200;
private final static int FRAME_PERIOD = 1000 / MAX_FPS;
private final static int MAX_FRAME_SKIPS = 5;
public void run() {
initTimingElements();
long beginTime;
long timeDiff;
int sleepTime;
int framesSkipped;
long beginTime2;
long diff1;
long diff2;
sleepTime = 0;
Canvas canvas;
Log.d(TAG, "Starting game loop");
while (running) {
canvas = null;
try {
canvas = this.surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
beginTime = System.currentTimeMillis();
framesSkipped = 0;
this.gamePanel.update();
diff1=System.currentTimeMillis()-beginTime;
beginTime2=System.currentTimeMillis();
this.gamePanel.render(canvas);
diff2=System.currentTimeMillis()-beginTime2;
timeDiff = System.currentTimeMillis() - beginTime;
sleepTime = (int) (FRAME_PERIOD - timeDiff);
if (sleepTime > 0) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
}
}
while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) {
this.gamePanel.update();
sleepTime += FRAME_PERIOD;
framesSkipped++;
}
if (framesSkipped > 0) {
Log.d(TAG, "Skipped:" + framesSkipped);
}
framesSkippedPerStatCycle += framesSkipped;
storeStats();
}
} finally {
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}

Try using a TimerTask that fires off every 60ms or so.
That's what I do until I stop being lazy enough to do a proper implementation, but it works well.
Just remember that run() will be executed in a different thread, so use runOnUIThread() to run whatever code you need.

Related

Android choppy drawing

I'm writing my very first android game. The graphics are primitive, some rectangles moving through the screen. The game seems smooth but with occasional stutters, every 0.5 - 1.0 secs, and I can't figure out what's causing it. I've already eliminated all the GC calls inside my draw / update routines, enabled hw acceleration in my surfaceView, activity and in the manifest file.
This is how my game loop looks like currently (taken from some sort of tutorial):
public void run() {
while (!terminated) {
if (!gameEngine.isRunning())
continue;
Canvas canvas = null;
try {
canvas = surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
long beginTime = SystemClock.elapsedRealtime();
int framesSkipped = 0;
gameEngine.update();
if(canvas != null)
gameEngine.draw(canvas);
long timeDiff = SystemClock.elapsedRealtime() - beginTime;
int sleepTime = (int) (FRAME_PERIOD - timeDiff);
if (sleepTime > 0) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException ignored) {
}
}
while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) {
gameEngine.update();
sleepTime += FRAME_PERIOD;
framesSkipped++;
}
}
} finally {
if (canvas != null)
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
If I log the value of timeDiff at every frame, it stays in the 5-15 range, so it doesn't indicate the stutters.
I'm using SystemClock.elapsedRealtime() instead of System.currentTimeMillis() because I've read that System.currentTimeMillis isn't accurate enough. (Or should I be using System.nanoTime() ?)
This isn't the first solution I tried using, and none of them have so far solved my issue. So I suspect the problem may lie somewhere else. I appreciate any help!

Blinking while drawing on canvas in loop

I have problem with drawing on android. I'm trying to create simple game that includes robots which will paint screen on different colors. Firstly I'm trying only paint screen without any robot image (I'm planing place it later on higher transparent view) but I encountered problem with flashing canvas.
So this is my render method. I can't use every time canvas.drawColor(Color.BLACK); before drawing because as I said robots need to paint screen with own color (Red and Blue). Other idea was to store every robot location and paint it on every "render" method, but it takes too much time and after few secounds game becoming really slow.
public void render(Canvas canvas) {
if(lastD1X!=-1 && lastD1Y!=-1){
canvas.drawLine(lastD1X, lastD1Y, droid.getX(), droid.getY(), drawPaint);
}
lastD1X = droid.getX();
lastD1Y = droid.getY();
if(lastD2X!=-1 && lastD2Y!=-1){
canvas.drawLine(lastD2X, lastD2Y, droid2.getX(), droid2.getY(), drawPaint2);
}
lastD2X = droid2.getX();
lastD2Y = droid2.getY();
}
This is my game loop:
#Override
public void run() {
Canvas canvas;
Log.d(TAG, "Starting game loop");
long beginTime; // the time when the cycle begun
long timeDiff; // the time it took for the cycle to execute
int sleepTime; // ms to sleep (<0 if we're behind)
int framesSkipped; // number of frames being skipped
sleepTime = 0;
while (running) {
canvas = null;
// try locking the canvas for exclusive pixel editing
// in the surface
try {
canvas = this.surfaceHolder.lockCanvas(null);
synchronized (surfaceHolder) {
beginTime = System.currentTimeMillis();
framesSkipped = 0; // resetting the frames skipped
// update game state
this.gamePanel.update();
// render state to the screen
// draws the canvas on the panel
this.gamePanel.render(canvas);
// calculate how long did the cycle take
timeDiff = System.currentTimeMillis() - beginTime;
// calculate sleep time
sleepTime = (int)(FRAME_PERIOD - timeDiff);
if (sleepTime > 0) {
// if sleepTime > 0 we're OK
try {
// send the thread to sleep for a short period
// very useful for battery saving
Thread.sleep(sleepTime);
} catch (InterruptedException e) {}
}
while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) {
// we need to catch up
this.gamePanel.update(); // update without rendering
sleepTime += FRAME_PERIOD; // add frame period to check if in next frame
framesSkipped++;
}
}
} finally {
// in case of an exception the surface is not left in
// an inconsistent state
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
} // end finally
}
}

what happens when new intent is called from view?

Im trying to start a new intent from my gameView using this method:
if(happy.getHP() <= 0){ //if my main-character dies
thread.setRunning(false);
Context context = getContext();
Intent intent = new Intent("nielsen.happy.activities.ENDSCREEN");
context.startActivity(intent);
}
If I do it without thread.setRunning(false);, the endScreen comes up but its buttons wont work, but if i stop my mainThread they do work.
Anyway, the problem with this code is that when my character dies, it freezes for 3-4 seconds, then the endscreen flickers for a sec, then the gameView flickers for a sec, THEN the endscreen comes up for real and the buttons work.
When I start an Activity from another activity, like when I press "Start Game" in my menu, I dont get this problem. I really dont understand what happens here that makes it lag like this.
adding my thread below:
public void run() {
Canvas canvas;
Log.d(TAG, "Starting game loop");
// initialise timing elements for stat gathering
initTimingElements();
long beginTime; // the time when the cycle begun
float time1 = System.currentTimeMillis();
float time2;
//long timeDiff; // the time it took for the cycle to execute
int sleepTime; // ms to sleep (<0 if we're behind)
int framesSkipped; // number of frames being skipped
sleepTime = 0;
while (running) {
canvas = null;
// try locking the canvas for exclusive pixel editing
// in the surface
try {
canvas = this.surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
beginTime = System.currentTimeMillis();
framesSkipped = 0; // resetting the frames skipped
// update game state
this.gamePanel.update();
// render state to the screen
// draws the canvas on the panel
this.gamePanel.render(canvas);
// calculate how long did the cycle take
timeDiff = System.currentTimeMillis() - beginTime;
// calculate sleep time
sleepTime = (int)(FRAME_PERIOD - timeDiff);
if (sleepTime > 0) {
// if sleepTime > 0 we're OK
try {
// send the thread to sleep for a short period
// very useful for battery saving
Thread.sleep(sleepTime);
} catch (InterruptedException e) {}
}
while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) {
// we need to catch up
this.gamePanel.update(); // update without rendering
sleepTime += FRAME_PERIOD; // add frame period to check if in next frame
framesSkipped++;
}
// for statistics
framesSkippedPerStatCycle += framesSkipped;
// calling the routine to store the gathered statistics
storeStats();
}
} finally {
// in case of an exception the surface is not left in
// an inconsistent state
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
} // end finally
}
}
adding whole method below:
private void checkCollision(Canvas canvas) {
Rect h1 = happy.getBounds();
for (int i = 0; i < enemies.size(); i++) {
Rect e1 = enemies.get(i).getBounds();
if (h1.intersect(e1)){
if(enemies.get(i).getX() < controls.pointerPosition.x){
enemies.get(i).setX(-20);
}else if (enemies.get(i).getX() > controls.pointerPosition.x){
enemies.get(i).setX(20);
}else if(enemies.get(i).getY() < controls.pointerPosition.y){
enemies.get(i).setY(-20);
}else if(enemies.get(i).getY() > controls.pointerPosition.y){
enemies.get(i).setY(20);
}
if(enemies.get(i).getCooldown() <= 0){
happy.damageHP(10);
score.incScore(-10);
enemies.get(i).setCooldown();
}
}
if(happy.getHP() <= 0){
thread.setRunning(false);
try {
thread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Context context = getContext();
Intent intent = new Intent("nielsen.happy.activities.ENDSCREEN");
context.startActivity(intent);
//end-screen !!!!!!!
}
if(enemies.get(i).getHP() <= 0){
enemies.get(i).death(canvas, enemies);
score.incScore(5);
break;
}
for (int j = 0; j < bullets.size(); j++) {
Rect b1 = bullets.get(j).getBounds();
if (b1.intersect(e1)) {
enemies.get(i).damageHP(5);
bullets.remove(j);
}
}
}
}
I would have to see what your thread is doing to be sure, but I'm pretty sure something like this is happening:
You call setRunning(false) which sets some flag in the thread class.
You start the new intent but the thread hasn't stopped yet because it hasn't gotten to the part where it checks the running flag
The thread (which hasn't paused yet) starts making changes to the gui, this confuses the android UI which thinks that view should be inactive
The thread gets to the point where it's waiting for setRunning(true), and everything is happy again.
If this is true, you can fix by waiting until the thread is blocked on setRunning(true), then creating the new intent.

android game loop surfaceview overlay with framelayout cause lag

i'm currently writing a android game, but now, i'm having some strange issues with the controls
if i have a framelayout with all my controls(the HP, points, game controls..etc) and put it on top of my surfaceview, my fps will never get above 20 fps; if i remove the framelayout, the game will hit 50+fps.
I'm suspecting that the system is rendering my surfaceview and framelayout's content all together in one thread, which explains why it's so slow
here's my game loop code
public void run() {
Canvas c;
initTimingElements();
long beginTime; // the time when the cycle begun
long timeDiff; // the time it took for the cycle to execute
int sleepTime; // ms to sleep (<0 if we're behind)
int framesSkipped; // number of frames being skipped
sleepTime = 0;
while (_run) {
c = null;
//long start = System.currentTimeMillis();
try {
c = _panel.getHolder().lockCanvas(null); // this is the problem!!
synchronized(_panel.getHolder()) {
beginTime = System.currentTimeMillis();
framesSkipped = 0; // resetting the frames skipped
_panel.updatePhysics();
_panel.checkForHits();
_panel.checkForKill();
_panel.checkForMCHits();
//if i put stuff related to ui in the loop, it will slow the control down to a unblelieveable state
//_panel.checkNPCQt();
_panel.onDraw(c);
timeDiff = System.currentTimeMillis() - beginTime;
// calculate sleep time
sleepTime = (int)(FRAME_PERIOD - timeDiff);
if (sleepTime > 0) {
// if sleepTime > 0 we're OK
/*
try {
// send the thread to sleep for a short period
// very useful for battery saving
Thread.sleep(sleepTime);
} catch (InterruptedException e) {}
*/
}
while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS) {
// we need to catch up
//_panel.updatePhysics(); // update without rendering
sleepTime += FRAME_PERIOD; // add frame period to check if in next frame
framesSkipped++;
}
if (framesSkipped > 0) {
Log.d(TAG, "Skipped:" + framesSkipped);
}
// for statistics
framesSkippedPerStatCycle += framesSkipped;
// calling the routine to store the gathered statistics
storeStats();
}
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
_panel.getHolder().unlockCanvasAndPost(c);
//Log.d(TAG, "unlock canvas");
}
}
i've pretty sure i got all my game logic and bitmaps are right; if i comment out all onDraw functions and everything else, i still got only 20-23 fps with framelayout there.
is there any alternatives? can create a separate thread for the UI draw? or am i just doing it wrong?
here is my XML state:
Solved, i accidentally messed up the framelayout, clean project is the answer

Creating and displaying game objects every 3 seconds on the screen

I am having trouble in creating and displaying multiple game objects on the screen for every 3 seconds. there is no problem when there's only one object but if I want to create multiple, the problem occurs. To explain in detail, There's a main game loop (the one identical with the existing ones on the internet) and in that game loop,in every 3 seconds I want a new object to be created, added to the ArrayList and then update game panel and show all the objects on the screen in every 3 seconds. The code block above works but it is too fast so the screen is filled with images, I want it to be periodic. What must I do? If using a background thread in order to prevent the block of UI thread, how can I do it?
Thanks in advance.
Here's my code block:
MAIN THREAD PART:
while (running) {
canvas = null;
try {
canvas = this.surfaceHolder.lockCanvas();
synchronized (surfaceHolder) {
beginTime = System.currentTimeMillis();
this.gamePanel.update();
this.gamePanel.render(canvas);
}
} finally {
if (canvas != null) {
surfaceHolder.unlockCanvasAndPost(canvas);
}
} // end finally
}
and Update method in my MainGamePanel class:
public void update() {
int random = 5 + (int) (Math.random() * (200 - 5));
droid = new Carrier(BitmapFactory.decodeResource(getResources(),
R.drawable.image), random, 1);
Carriers.add(Carrier);
for (int i = 0; i < Carriers.size(); i++) {
Carrier CarrierTemp = Carriers.get(i);
CarrierTemp .update();
}
}
Here's a solution that is built on your current code:
Put this in your thread somewhere:
int savedtime = 0;
long lastTime;
in your update() method:
//Calculate time since last update:
long now = System.currentTimeMillis();
savedtime += now - lastTime;
lastTime = now;
if(savedTime > 3000){//if more than three seconds have passed:
savedTime = 0;
int random = 5 + (int) (Math.random() * (200 - 5));
droid = new Carrier(BitmapFactory.decodeResource(getResources(),R.drawable.image), random, 1);
Carriers.add(Carrier);
}
for (int i = 0; i < Carriers.size(); i++) {
Carrier CarrierTemp = Carriers.get(i);
CarrierTemp .update();
}

Categories

Resources