efficient android rendering - android

I've read quite a few tutorials on game programming on android,
and all of them provide basically the same solution as to drawing the game, that is having a dedicated thread spinning like this:
public void run() {
while(true) {
if(!surfaceHolder.getSurface().isValid()) continue;
Canvas canvas = surfaceHolder.lockCanvas();
drawGame(canvas); /* do actual drawing here */
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
now I'm wondering, isn't this wasteful? Suppose I've a game with very simple graphics, so that the actual time in drawGame is little;
then I'm going to draw the same things on and on, stealing cpu from the other threads;
a possibility could be skipping the drawing and sleeping a bit if the game state hasn't changed,
which I could check by having the state update thread mantaining a suitable status flag.
But maybe there are other options. For example, couldn'it be possible to synchronize with rendering,
so that I don't post updates too often? Or am I missing something and that is precisely what lockCanvas does,
that is it blocks and burns no cpu until proper time?
Thanks in advance
L.

I would say the tutorials you have seen are wrong, you really want to wait in the main loop. 16 milliseconds would be the target frame time in the example below
public void run() {
while(true) {
long start = System.currentTimeMillis();
if(!surfaceHolder.getSurface().isValid()) continue;
Canvas canvas = surfaceHolder.lockCanvas();
drawGame(canvas); /* do actual drawing here */
surfaceHolder.unlockCanvasAndPost(canvas);
long frameTime = System.currentTimeMillis() - start;
try {
Thread.sleep(Math.max(0, 16 - ( frameTime )));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

You don't need to draw canvas from a loop in a thread, you can do this on request, like when moving the finger over the screen.
If the animation is not intensive, one can use just a custom view and then invalidate() the view from some user input event.
It is also possible to stop the thread and then create and start it again, as many time as needed witin the same SurfaceView class.

Related

Objects not moving at the same speed, when Thread sleeps for a millisec

I am currently trying to move some rectangle objects (displayed as bitmaps on my surfaceview).
They should all move with the same speed, therefor my code looks like this:
new Thread (new Runnable()
{
#Override
public void run()
{
while(true)
{
newTime = System.currentTimeMillis();
frameTime = newTime - currentTime;
currentTime = newTime;
physics(frameTime);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
i move my rectangle objects in the physics method based on the frametime parameter.
So my problem is the following: with the code i just posted all my rectangles move at the same speed, but the graphics are lagging. The lag disappears as soon as i remove the Thread.sleep(1), but then my rectangle objects wont move with the same speed anymore (some rectangles move faster than others).
any ideas?
Edit:
the physics and movedown methods are just normal methods in my classes, both are not in any threads or something. they are only getting called from my Thread i posted above
public void physics(double delta)
{
for(int i=0; i<=5; i++)
{
rectangles[i].moveDown(delta);
}
}
public void moveDown(double delta)
{
setY((double) (getY() + ((sH)*(delta/1000))));
//sH is the screen height
}
Edit2:
Graphics code
while(true)
{
if(!ourHolder.getSurface().isValid())
{
continue;
}
Canvas canvas = ourHolder.lockCanvas();
synchronized(ourHolder) {
graphics(canvas);
// in this method all the drawings happen
// e.g. canvas.drawBitmap
}
ourHolder.unlockCanvasAndPost(canvas);
}
It is difficult to analyse given the code you posted, since it's unclear what physics(frameTime); is actually doing. It seems like each moving rectangle is updated in its own Thread. Then the result you get has to be expected because one thread or the other will be called more often than the others depending on thread scheduling. Instead, use one single thread to control your simulation (e.g. update your frameTime and provide it to the other threads). However, IMHO you have to rethink your architecture.
It's hard to tell from your posted code what the problem could be, but one thing I notice is that you could experience some clock drift. See: Does time jump in android devices?.
Although, it looks like you are moving the rectangles using a fixed offset, so even if there were clock drift, I would expect them to jump around but by the same amount. So I agree with Axel that there appears to be some thread interaction going on.
How are you drawing to the screen? If you have another thread processing the graphics, the two threads could get out of sync and you'll need to ensure you are locking things properly. If you are using the deltas to update the location on the screen in your paint method, maybe instead use an absolute position that you update in your physics() method and draw based on that. It seems you probably need to rethink some of the architecture.

android button animation with click

I'm trying to make flying balloons (up and down, infinitely) and by clicking on one of them, it will changes its direction. I tried to use Animation, but it don't support click on a view at a current position at a current time. I know, that there are two methods, for at least:
use an OpenGL
and use a Canvas.
I don't want to use OpenGL for so quit simple animation. And I don't understand how to do it, using Canvas(were read this, google docs and some google search links).
I don't need a code, all I need it's the way how to do it and the algorithm.
Alright, this is what I've set up for one of my projects that would work exactly as you need...
You need to create 4 main aspects:
- An Activity (extend Activity)
- A SurfaceView (extend SurfaceView implement SurfaceHolder.Callback)
- A Thread (Extend Thread)
- Objects that interact (extend Drawable)
The Activity starts and generates a SurfaceView that creates a Thread. The View or the Thread can contain the objects that you draw/interact with, its up to you how you want to store the data at this point but its easiest if you come up with a design that has the least coupling between classes.
Once started, the Thread runs constantly until stopped (setting isRunning to false):
/**
* Processing loop
*/
public void run() {
while (isRunning) {
try {
sleep(25);
} catch (InterruptedException e) {
Log.e("Thread","Thread Interruption");
e.printStackTrace();
}
update();
}
Log.d("Thread", "Game Loop Stopped");
}
/**
* Main processing of the game loop.
*/
private void update() {
handleInput();
updatePhysics();
updateUI();
updateState();
updateAI();
updateAnimations();
updateSound();
updateVideo();
}
In this class you see the update() method that does a bunch of actions each iteration of the thread.
The methods that will interest you mostly are the handleInput, updateUI and updatePhysics methods.
In the handleInput you'll do a callback to the SurfaceView to get the data that you need for processing information. My handleInput is fairly simple in that it just grabs the MotionEvent from the SurfaceView class's onTouchEvent (this gets implemented when you use the SurfaceHolder.OnCallBack interface).
The updateUI method calls the SurfaceView's update where it re-draws the Canvas with each object, or balloon
public void update(List<Actor> actors) {
Canvas canvas = null;
try {
canvas = surface.lockCanvas();
synchronized (surface) {
//Blank the Canvas
for (int i = 0; i < actors.size(); i++) {
actors.get(i).draw(canvas);
}
}
} catch (NullPointerException e) {
e.printStackTrace();
} finally {
if (canvas != null) {
surface.unlockCanvasAndPost(canvas);
}
}
}
Here we can see that it calls the draw method passing the canvas object to each one of your interactable objects. I've called mine "Actors" in the code above. How you choose to implement draw is up to you but it sounds like you'll be using a lot of canvas.drawBitmap() functions.
Going back to the Thread's updatePhysics method you'll want to use it to update the objects before or after they're drawn to the screen. For you you'll want to have them change their X and/or Y positions on the screen or change the direction its moving after the handleInput decides you've hit a balloon.
Its very hard to explain this well in a StackOverflow reply. If you really want I can try to put something more informative together this weekend and post it externally for you (I can provide my UML class diagrams among other information such as picture examples, structures and data flows.
Please let me know if I can help you further! Please note that this isn't all my work. I used a lot of tutorials online for basic Android Game structure but don't have the links available right now to provide references.

Confusion over Canvas/OpenGl Techniques

I'm a completely newbie to android programming, having done some java for my computing levels but nothing too complex!
I'm working on a game where an object falls down the screen and has to be sorted into the relevant 'box' when it reaches the bottom.
I've got a surface view running with a thread etc, using canvas draw methods, however, i can't for the life of me see how i will be able to make the falling object reach a speed where it'll present a challenge to the user.
Running the thread with a change of 1 in the y direction causes the object to crawl down the screen. Greater changes in Y lead to jumpy graphics.
Would OpenGL make any difference or are there other canvas methods i can implement?
Hope that makes sense!
Thanks in advance
----Thread------
public void run()
{
Canvas canvas;
while(running)
{
canvas = null;
try{
canvas = this.surfaceholder.lockCanvas();
synchronized(surfaceholder)
{
gamepanel.Check();
this.gamepanel.onDraw(canvas);
}
}finally
{
if(canvas != null)
{
surfaceholder.unlockCanvasAndPost(canvas);
}
}
}
}
----SurfaceView-------
protected void onDraw(Canvas canvas){
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.gamebackground), 0, 0, null);
SortItOut.sortitout.Letter.draw(canvas);
}
-----Letter----- (Each object is a different letter)
public static void draw(Canvas canvas)
{
y += 1;
canvas.drawBitmap(LetterObject, x, y, null);
}
Those are the methods i would believe are relevant (The Check method is simply to check whether the object has reached the bottom of the screen).
You must load all your bitmaps in the constructor for the SurfaceView, never in onDraw()
Aside from the bitmap loading problem, you can make it fall faster my increasing the rate of the y change. If you do it too much, the box will appear to jump, but I bet you could get away with up to 10 pixel changes before that would happen (experiment).
You would only need to do OpenGL in this case if performance was slowing you down. I don't think that's the case. Although, I would stop loading the bitmap in the onDraw method and put it in the onCreate or some constructor. onDraw gets called hundreds of times and that's killing your app.

Android game scrolling background

I'm just trying to figure out the best approach for running a scolling background on an android device. The method I have so far.... its pretty laggy. I use threads, which I believe is not the best bet for android platforms
#Override
public void run() {
// Game Loop
while(runningThread){
//Scroll background down
bgY += 1;
try {
this.postInvalidate();
t.sleep(10);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
where postinvalidate in the onDraw function simply pushings the background image down
canvas.drawBitmap(backgroundImage, bgX, bgY, null);
Thanks in advance
UPDATE
I've identified the problem. And it is the fact that my player updates the same rate as the background scrolls (making it look choppy). from top to bottom. This is because both get drawn in the same function. I'm not really sure how to tackle this and would be grateful for any help. i.e so that player movement is handled separately from the map scrolling
Also how can I control the speed at which onDraw(canvas) get called?
Thanks in advance.
However, I have patched together a different run loop for anyone having the same problem. This is partially from the jetboy example on google.
Below is my inner class in my surfaceview
class MapThread extends Thread{
private Map map;
private SurfaceHolder holder;
private boolean run = false;
public MapThread(Map map, SurfaceHolder holder){
this.holder = holder;
this.map = map;
setRunning(true);
}
public void setRunning(boolean run){
this.run = run;
}
#Override
public void run(){
while(run){
try{
Canvas c = null;
try {
c = holder.lockCanvas(null);
synchronized (holder) {
map.onDraw(c);
}
} finally {
if (c != null) {
holder.unlockCanvasAndPost(c);
}
}
}
}
}
SOLUTION
https://gamedev.stackexchange.com/questions/8127/android-game-scrolling-background
Use the SurfaceView implementation draw on the screen. It allows you more control of what to draw and when.
The SurfaceView is a special subclass of View that offers a dedicated drawing surface within the View hierarchy. The aim is to offer this drawing surface to an application's secondary thread, so that the application isn't required to wait until the system's View hierarchy is ready to draw.
The basic design is to have a surfaceview that draws continuously in a while loop. Then add an if-statement whose condition is to be true if a timer thread tells you its time to draw. Say, every 30ms, draw the bitmap. This will give you about 33 fps.
Now you may also have another timer thread that tells you when to update the the bgX or bgY values. Say at every 60ms, it will set a boolean updateFlag = true; Then in your main thread, you have an if-statement check this flag, set it to false, and update your bgX and bgY values. By accurately controlling the timer and the bgX/bgY increments, you should be able to produce smooth animations.
It would be a good idea to look at the LunarLander source code provided by Google.
One thing to keep in mind is that sleep is very inaccurate. To work around this, you can keep track of exactly how much time passed during the sleep and update how much you move things accordingly.
Its not clear from you code, but you need to make sure that all of your UI updates happen in the UI thread.
You do need to do your timing outside of the UI thread, because otherwise the UI will never update. There are other methods of timing, like using a Handler that can be a little bit cleaner, but I think the overhead on them might be a bit much for what you are trying to do. I think a simple thread has the least amount of overhead.
I am using this method on the second level of my SpaceQuestAlpha game. This makes a seemless scroll.
I used the 2 lines below to set original position.
moony=0;
moon2y=-(heighty);
Then these lines increment both versions of the background image. One starts at 0 and one starts at negative screen height. Every time one of the images goes below the bottom of the screen it is moved up twice the height to move it back into position. I am using surface view with no latency issues.
moony+=5;
moon2y+=5;
if(moon2y>=heighty) {moon2y=moon2y-(heighty*2);}
canvas.drawBitmap(lavabackground, 0, moon2y, null);
if(moony>=heighty){moony=moony-(heighty*2);}
canvas.drawBitmap(lavabackground, 0, moony, null);

Android loading and showing a lot of images in ImageView(frame by frame animation) hangs in certain moments

I've created an application that show around 250 images in ImageView. Images are loaded one after another, 15-30 images per second. Basically the whole thing gives an illusion of a rotating 3D object, at least it should.
The problem is next, app hangs when loading certain images(i.e. I see a few seconds of fluid animation and then animation hangs, jump 10-15 frames(images) ahead and continues. It always happens at the same places in animation cycle.
I though that Android might not have enough resources to handle something like this, so I've resized images to half their size, but it did't help. I've tried buffering images but that did't help either(actually, maybe a little, I think that animation looks a little bit smoother).
And now the weirdest thing. I use the touch screen to allow users to "rotate" the 3D object on those images, and while rotating I again experience those hangs at exactly the same places as with the animation.
All images are in .png format and their size vary from 15kB to 40kB.
I use the following code for the animation:
new Thread(new Runnable() {
#Override
public void run() {
while (!stopStartupAnimation && li < images_360.length) {
final int fli = li;
handler.post(new Runnable() {
#Override
public void run() {
//Bitmap b = BitmapFactory.decodeResource(getResources(), R.drawable.icon);
//imageCanvas.setImageResource(images_360[fli]);
imageCanvas.setImageBitmap(imageStackNext.pop());
System.out.println("rawX = " + fli);
}
});
int ti = fli +25;
if(ti > images_360.length-1){
ti = ti - images_360.length;
}
imageStackNext.push(BitmapFactory.decodeResource(getResources(), images_360[ti]));
synchronized (this) {
try {
wait(1000 / 25);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
li++;
li++;
if (li >= images_360.length) {
li = 0;
}
}
}
}).start();
First, 15-40KB is their compressed form. Uncompressed, as Bitmaps, they are probably substantially larger. 250 of them may be using many MB of RAM, which is not a good idea.
Second, given a choice between using OpenGL for 3D (which is its purpose), or the 2D drawing primitives on the Canvas, or using ImageView, you chose the worst-performing option.
Third, postRunnable() does not take effect immediately, but rather puts things on a message queue for the main application thread to process when it gets a chance. If it gets tied up -- say, handling touch events -- it may well skip over some seemingly redundant ImageView redraws, or have them go by so fast they appear to not happen. All your 40ms wait() does is ensure that you are only raising events every 40ms, not that they will paint every 40ms. Besides, you could have more easily just used postDelayed() for your 40ms timing.
Bitmaps should be loaded efficiently.
Refer example on official page: https://developer.android.com/training/displaying-bitmaps/index.html

Categories

Resources