Whats the easiest way to animate 2D graphics on a surfaceview? - android

Currently I have a cartoon character that takes up almost the full screen of a surfaceview, and my little app is only to animate this 2D character during ontouch event at different coordinates.
What I am doing now is to redraw the whole character every single time, and this way I need to have a specific graphic for every single frame.
I am just wondering if its better to split the character into different parts, e.g. heads, hands, legs, and whenever a ontouch event happens, I only need to re-draw the specific part?
What do you think the pros and cons would be? Is it less CPU intensive?

This really comes down to how your images are set up.
Having a single image taking up the whole screen means that every frame has to redraw the whole screen, something which an android device should be capable of doing. If you break your character into different parts it may look as if you only have to redraw a small part of the screen but if you just redraw one part around then it will still be in its old position unless you draw over it meaning you may have to do a full redraw anyway. Sometimes you can be clever and work out what areas of the screen need to be redrawn and then only redraw those but this can get very complicated.
Another think worth thinking about is memory usage though, if you have a large number of full screen images in memory some phones may not have enough available memory and may crash. By breaking the image up into small parts you should reduce the chance of this.

Related

Choice of drawing and animation technique for an animated music staff

I'm working on an app where I must have on a part of the screen an animated music staff. That's:
5 static lines
A dozen of music notes (each one is basically an oval and a line)
A few additional symbols (clefs)
I must have a precise control of the size of each element, and have to smoothly animate position and alpha of the notes and clefs so the notes are moving right to left (disappearing when on the left of the screen, and appearing when on the right, hence the alpha). I also have to change sometimes the color of the notes.
I think I can't use standard "Animations" class, as it's an endless animation with the speed and the notes depending on real time factors.
So what is/are the best way(s) to do that and to achieve a smooth animation?
Different Views? (VectorDrawables?) Single SurfaceView where I manually draw each shape at each frame? (or TextureView?)
(Note: minimum API is set to 15)
Thank you for helping me choosing the right technique.
So you're wrong about the Animations class being infinite. It doesn't need to be. However EVERYTHING in Android will depend on real life factors- Android is not a RTOS (real time OS), there is no guarantee of execution time.
However, if you absolutely need total control, I would just jump to total control- hook the Choreographer so you get a call every 1/60th of a second, and each frame invalidate your view(s) that need to change and redraw them. If the phone is running slow for some reasons like other apps you may drop a frame or run slightly slower than 1/60th of a second, but this is as close as you can get (and what Animation classes use behind the scenes).
With animators you can animate smoothly around 5 different views on average phone. So in your case (with dozen of notes and so on) it will have around 10fps. So slightly better will be SurfaceView and handdrawing all that you want. Maybe GLSurfaceView worth considering.
In order to test this I recommend you to create some test app first, where will be 10 views flying around, and look at performance.

scaling images in libgdx only once

In my android game, I am using images of fixed resolution lets say 256x256. Now for different device screens, I am rendering them by calculating their width and height as appropriate for that device.
Assume that on galaxy note2 I calculated width=128 and height=128... similarly for different devices, width and height will vary.
This is how I created texture..
....
imageTexture = new Texture(...);
....
in render()..
....
spriteBatch.draw(imageTexture,x,y,width,height);
....
So, every time when I call draw() method, does libgdx/opengl scale image from 256x256 to 128x128, which I think, yes!
Is there any way to tell opengl/libgdx to calculate all scaling only once ?
I have no idea how images were rendered? loaded into memory? scaled etc ?
How does Sprite in libgdx work? I tried understanding the code of Sprite and looks to me like they are also getting image width and height and then scale it every time, even though they have setScale() method.
First rule of optimizing: get some numbers. Premature optimization is the root of many problems. That said, there are still some good rules of thumb to know.
The texture data will be uploaded by libgdx/OpenGL to the GPU when you invoke new Texture. When you actually draw the texture with spriteBatch.draw instructions are uploaded to the GPU by OpenGL that tell the hardware to use your existing texture and to fit it to the bounds. The draw call just uploads coordinates (the corners of the box that defines the Sprite) and a pointer to the texture. The actual texture data is not uploaded.
So, in practice your image is "scaled" on every frame. However, this is not that bad, as this is exactly what GPUs are designed to do very, very well. You only really need to worry about uploading so many textures that the GPU has trouble keeping track of them all, you do not need to worry much about scaling the textures beforehand.
The costs of scaling and transforming the four corners of the sprite are relatively trivial next to the costs of sending the data to the GPU and the cost of refreshing the screen, so they probably are not worth worrying about too much. The "batch" in SpriteBatch is all about "batching up" (or gathering together) a lot of coordinates to send up to the GPU at once, as roughly, each call out to the GPU can be expensive. So, its always good to do as much work within a single batch's begin/end as you can.
Again, though, modern machines are stupidly fast, and you should be able to do whatever is easiest to get your app running first. Then once you have something working correctly, you can figure out which parts are actually slow and fix those. The parts that are "inefficient" but are not actually measurably impacting your application can be left alone.

Android - is there a possibility to make infinite canvas?

Currently I am doing app allowing user to draw. Simple think, just extend Canvas class and most of the thing is done.
That was my initial thinking and idea. But as the canvas is rather small because this is only what user see on the screen there is not much possible space to draw. Going through documentation I found translate() method allowing me to move canvas. What I did find out is when I move it, there is some kind of blank space just as you would move piece of paper. I understand that this is totally normal, as I've said before - canvas is only "the screen".
My question is - is there a possibility to make something like infinite canvas so you can make a huge painting and move everything around?
Before this question I was thinking about two things how something like this can be done:
Move all objects on canvas simultaneously - bad idea, because if you have a lot of them then the speed of moving is very bad.
Do something similar as it is done in ListView when you move it (or better see on the screen) only views that are on the screen together with one before and one after are loaded to memory and rest is uploaded dynamically when needed. I think this is the best option to achieve this goal.
EDIT:
Question/answer given by Kai showed me that it is worth to edit my question to clarify some of the things.
Basic assumptions about what can be done by user:
User is given opportunity to draw only circles and rectangles with some (around 80%) having drawable (bitmap) on them on canvas.
I assume that on all screens there will be maximum 500-800 rectangles or circles.
First of all thinking about infinity I was thinking about quite big number of screens - at least 30 on zoom 1x in each side. I just need to give my users bigger freedom in what they are doing.
On this screen everything can be done as on normal - draw, scale (TouchListener, ScaleListener, DoubleTapListener). When talking about scaling, there is another thing that has to be concerned and connected with "infinity" of canvas. When user is zooming out then screens, or more precise objects on the invisible "neighbours" should appear with proper scaling as you would zoom out camera in real life.
The other thing that I've just realised is possibility of drawing at small zoom level - that is on two or three screens and then zooming in - I suppose it should cut and recalculate it as a smaller part.
I would like to support devices at least from API 10 and not only high-end.
The question about time is the most crucial. I want everything to be as smooth as possible, so user wouldn't know that new canvas is being created each time.
I think it really depends on a number of things:
The complexity of this "infinite canvas": how "infinite" would it really be, what operations can be done on it, etc
The devices that you want to support
The amount of time/resource you wish to spend on it
If there are really not that many objects/commands to be drawn and you don't plan to support older/lower end phones, then you can get away with just draw everything. The gfx system would do the checking and only draws what would actually be shown, so you only waste some time to send commands pass JNI boundary to the gfx system and the associated rect check.
If you decided that you needs a more efficient method, you can store all the gfx objects' positions in 4 tree structures, so when you search the upper-left/upper-right/lower-left/lower-right "window" that the screen should show, it'll fast to find the gfx objects that intersects this window and then only draw those.
[Edit]
First of all thinking about infinity I was thinking about quite big
number of screens - at least 30 on zoom 1x in each side. I just need
to give my users bigger freedom in what they are doing.
If you just story the relative position of canvas objects, there's practically no limit on the size of your canvas, but may have to provide a button to take users to some point on canvas that they are familiar lest they got themselves lost.
When talking about scaling, there is another thing that has to be
concerned and connected with "infinity" of canvas. When user is
zooming out then screens, or more precise objects on the invisible
"neighbours" should appear with proper scaling as you would zoom out
camera in real life.
If you store canvas objects in a "virtual space", and using a "translation factor" to translate objects from virtual space to screen space then things like zoom-in/out would be quite trivial, something like
screenObj.left=obj.left*transFactor-offsetX;
screenObj.right=obj.right*transFactor-offsetX;
screenObj.top=obj.top*transFactor-offsetY;
screenObj.bottom=obj.bottom*transFactor-offsetY;
//draw screenObj
As an example here's a screenshot of my movie-booking app:
The lower window shows all the seats of a movie theater, and the upper window is a zoomed-in view of the same theater. They are implemented as two instances of the same SurfaceView class, besides user input handling, the only difference is that the upper one applies the above-mentioned "translation factor".
I assume that on all screens there will be maximum 500-800 rectangles
or circles.
It is actually not too bad. Reading your edit, I think a potentially bigger issue would be if an user adds a large number of objects to the same portion of your canvas. Then it wouldn't matter if you only draw the objects that are actually shown and nothing else - you'd still get bad FPS since the GPU's fill-rate is saturated.
So there are actually two potential sources of issues:
Too many draw commands (if drawing everything on canvas instead of just drawing visible ones)
Too many large objects in the same part of the screen (eats up GPU fill-rate)
The two issues requires very different strategy (1st one using tree structures to sort objects, 2nd one using dynamically generated Bitmap cache). Since how users use your app are likely to different than how you envisioned it to be, I would strongly recommend implementing the functions without the above optimizations, try to get as many people as possible to do testing, and then apply optimizations to each of the bottlenecks you encounter until the satisfactory performance is achieved.
[Edit 2]
Actually with just 500~800 objects, you can just calculate the position of all the objects, and then check to see if they are visible on screen, you don't even really need to use some fancy data structures like a tree with its own overheads.

Which way is better for taking User Input in an OpenGL Android Game?

I am developing an OpenGL Android Game and I am right now dealing with the User Input.
I have two main ideas for implementing it. The two of them I think that they work perfectly but I do not know which one is "better" (in performance/speed).
The basics are that there are several "buttons" drawn in Opengl (such as four arrow keys, action button...) on some specific positions around the screen. These buttons do not change of place during gameplay.
FIRST IDEA
My first implementation was to create a 2D-matrix with references to each button. Something like:
InputObject matrix = new InputObject[Width_of_screen][Height_of_screen]
At the loading stage each button inserts in the Matrix its references for each pixel where they appear.
So each time the user touches the screen I can look directly on the matrix which button he has clicked (with e.getX() and e.getY()).
Pros: "Fast" to know which button to call.
Cons: (At common screens) 800*480 ~ 300K references, with 80% of them being null (But memory heap already taken)
SECOND IDEA
My second plan is to make an ArrayList of the Input Objects and ask each one if its theirs. Something like:
for(InputObject ob : TheArrayList){
if (ob.for_him(e.getX(),e.getY())){
ob.do_it();
break; //They cannot overlap
}
}
Pros: Less heap space taken (no null references at all...)
Cons: Have to detect for each object if its for itself, so they need to do comparisons on for_him method. Taking more CPU time.
With these said, which one may be the best idea for Android Phones (and other Smartphones) due to having not much processor time for user input.
If there is a third and best approach please I would love to know about it.
Thanks in advance.

Android scrolling background of bitmap tiles

I'm tried to determine the "best" way to scroll a background comprised of tiled Bitmaps on an Android SurfaceView. I've actually been successful in doing so, but wanted to determine if there is a more efficient technique, or if my technique might not work on all Android phones.
Basically, I create a new, mutable Bitmap to be slightly larger than the dimensions of my SurfaceView. Specifically, my Bitmap accomodates an extra line of tiles on the top, bottom, left, and right. I create a canvas around my new bitmap, and draw my bitmap tiles to it. Then, I can scroll up to a tile in any direction simply by drawing a "Surfaceview-sized" subset of my background Bitmap to the SurfaceHolder's canvas.
My questions are:
Is there a better bit blit technique than drawing a background bitmap to the canvas of my SurfaceHolder?
What is the best course of action when I scroll to the edge of my background bitmap, and wish to shift the map one tile length?
As I see it, my options are to:
a. Redraw all the tiles in my background individually, shifted a tile length in one direction. (This strikes me as being inefficient, as it would entail many small Bitmap draws).
b. Simply make the background bitmap so large that it will encompass the entire scrolling world. (This could require an extremely large bitmap, yet it would only need to be created once.)
c. Copy the background bitmap, draw it onto itself but shifted a tile length in the direction we are scrolling, and draw the newly revealed row or column of tiles with a few individual bitmap draws. (Here I am making the assumption that one large bitmap draw is more efficient than multiple small ones covering the same expanse.)
Thank you for reading all this, and I would be most grateful for any advice.
I originally used a similar technique to you in my 'Box Fox' platformer game and RTS, but found it caused quite noticeable delays if you scroll enough that the bitmap needs to be redrawn.
My current method these games is similar to your Option C. I draw my tiled map layers onto a grid of big bitmaps (about 7x7) taking up an area larger than the screen. When the user scrolls onto the edge of this grid, I shift all the bitmaps in the grid over (moving the end bitmaps to the front), change the offset of grid, and then just redraw the new edge.
I'm not quite sure which is faster with software rendering (your Option C or my current method). I think my method maybe faster if you ever change to OpenGL rendering as you wouldn't have to upload as much texture data to the graphics card as the user scrolls.
I wouldn't recommend Option A because, as you suggest, the hundreds small bitmap draws for a tiled map kills performance, and it gets pretty bad with larger screens. Option B may not even be possible with many devices, as it's quite easy to get a 'bitmap size exceeds VM budget' error as the heap space limit is set quite low on many phones.
Also if you don't need transparency on your map/background try to use RGB_565 bitmaps, as it's quite a lot faster to draw in software, and uses up less memory.
By the way, I get capped at 60fps on both my phone and 10" tablet in my RTS with the method above, rendered in software, and can scroll across the map smoothly. So you can definitely get some decent speed out of the android software renderer. I have a 2D OpenGL wrapper built for my game but haven't yet needed to switch to it.
My solution in a mapping app relies on a 2 level cache, first tile objects are created with a bitmap and a position, these are either stored on disk or in a Vector (synching is important for me, multithreaded HTTP comms all over the place).
When I need to draw the background I detect the visible area and get a list of all the tiles I need (this is heavily optimised as it gets called so often) then either pull the tiles from memory or load from disk. I get very reasonable performance even on slightly older phones and nice smooth scrolling with no hiccups.
As a caveat, I allow tiles not to be ready and swap them with a loading image, I don't know if this would work for you, but if you have all the tiles loaded in the APK you should be fine.
I think one efficent way to do this would be to use canvas.translate.
On the first drawing the entire canvas would have to be filled with tiles. New android phones can do this easily and quickly.
When the backround is scrolled I would use canvas.translate(scrollX, scrollY), then I would draw individualy one by one tile to fill the gaps, BUT, I would use
canvas.drawBitmap(tileImage[i], fromRect, toRect, null) which would only draw the parts of the tiles that are needed to be shown, by setting fromRect and toRect to correspond to scrollX and scrollY.
So all would be done by mathematics and no new bitmaps would be created for the background - save some memory.
EDIT:
However there is a problem using canvas.translate with surfaceView, because it is double buffered and canvas.translate will translate only one buffer but not the second one at the same time, so this alternating of buffers would have to be taken into account when depending on surfaceView to preserve the drawn image.
I am using your original method to draw a perspective scrolling background. I came up with this idea entirely by accident a few days ago while messing around with an easy technique to do a perspective scrolling star field simulation. The app can be found here: Aurora2D.apk
Just tilt your device or shake it to make the background scroll (excuse the 2 bouncing sprites - they are there to help me with an efficient method to display trails). Please let me know if you find a better way to do it, since I have coded several different methods over the years and this one seems to be superior. Simply mail me if you want to compare code.

Categories

Resources