Android's API 15 Animation class contain this:
public boolean getTransformation(long currentTime, Transformation outTransformation) {
... code ...
}
The method calculate the delta time and send it to an Interpolator which in turn based on the time the Animation has run, returns a value which in turn is applied to the Transformation.
When I build my own custom Views I use the post(Runnable) method and then call my logic update, invalidate and then post(Runnable) again if some condition is not met. The logic call takes 1 ms, the overriden onDraw(Canvas) also takes 1 ms. What is bugging me is the invalidate() call which often make my delta time go up to values above 40 (40 ms is 25 frames per second) and it is not advisable to get values higher than that. Using delta time to calculate where to draw the next frame often stutters and is not possible. I have to not use delta time and rely on how fast the phone can update the view individually, making it go faster and slower on different phones which is not a good idea.
SurfaceViews are something I cannot work with because their structure are not in cohesion with other Views (mostly Z depth problems).
Now to my question, how did Android solve the Animations? They do not stutter and they use delta time. Somewhere they must have some magic but I cannot seem to find where. Any help is very much appreciated.
Related
I am making a custom ProgressBar which has a bitmap that just rotates. if I use the View.invalidate the FPS will stutter; the deltaTime will go up 40+ many times. The logic and render is almost instantaneous but the invalidate call makes it slow. So I am trying the SurfaceView, problem is I have had problems earlier assemble SurfaceViews with other Views and I would like not to use it. Are there any alternative to SurfaceView and View.invalidate or am I stuck with them?
EDIT:
To clarify some more, I am making a custom View that is an intermediate ProgressBar. So the View is the ProgressBar. I am also not downloading anything now, I am only trying to get max FPS for my View. Some code:
MyProgressBar extends View implements Runnable
And the run()
calculateNewRotation();
invalidate();
post(this);
Where calculateNewRotation()
long now = SystemClock.uptimeMillis();
int deltaTime = (int) (now - mLastRender);
mLastRender = now;
mSpinRotation += deltaTime * SPIN_SPEED_PER_MILLISECOND_CLOCKWISE;
Post(this) refer to MyProgressBar and it will loop for all eternity until I say otherwise.
In my onDraw()
mCamera.save();
mCamera.rotateZ(mSpinRotation);
mCamera.getMatrix(mMatrix);
mCamera.restore();
mMatrix.preTranslate(-mTranslatePivotX, -mTranslatePivotY);
mMatrix.postTranslate(mTranslatePivotX + mCenterX, mTranslatePivotY + mCenterY);
canvas.drawBitmap(mSpinBitmap, mMatrix, mSpinBitmapPaint);
Time for calculateNewRotation() = 1 ms.
Time for onDraw() = 1 ms.
Problem is the overall time is often above 40 ms. My solution is to then use a SurfaceView, but I do not like the idea to have a View with it's surface drawn with transparent pixels so the underlying surface will be shown instead. What I am looking for is a View that I may get the canvas whenever I want, preferably every 16 ms to get 60 FPS. Now, is there such a View?
Are you doing a long operation (typically the reason for needing a progress bar) on the UI thread? Your UI thread should be updating the progress bar while another thread or an async task handles the long operation.
What I did in the end was when I have drawn the image I update the rotation value by 1. On fast and slow phones it will look smooth, but the speed will be different. On a fast phone it might draw 60 frames per second which is 60 degrees a second, when a slow phone with 10 frames per second will make the spin go 10 degrees a second. So in the end it is all about if I want them to rotate at the same speed or make it look good, I choose the latter one.
EDIT
I suppose I could put in a max frames per second so fast phones will be throttled and thus making the gap between fast and small phones smaller.
So in my game my View gets drawn an inconsistent rates. Which in turn makes it glitchy. Ive been running into alot of problems with the invalidate(); meathod. Any simple ideas- Everywhere i look I get thrown up on by tons of intense code.
You haven't provided us with much information, specifically code.
A few things you could do are:
Set the initial frame rate to the lowest value you observe your application runs at, i.e., if currently set to 1/60, but the frame rate continuously dips to 1/30, set to 1/30 etc.
Rework your drawing calls to be more efficient.
Try to combine multiple transformations into a single transformation by multiplying matrices, i.e. if you need to scale, translate, and rotate, multiply those three matrices together and apply that single transformation to the vertices instead of applying three separate transformations.
Try not to iterate through entire lists/arrays if unnecessary.
Attempt to use the lowest level / most primitive structure possible for anything you have to process in the loop to avoid the overhead of unboxing.
[edit on 2012-08-27]
helpful link for fixing you timestep: http://gafferongames.com/game-physics/fix-your-timestep/
It sounds like your game loop doesn't take into account the actual time that has passed between iterations.
The problem is the assumption that there is a fixed amount of time between loop iterations. But this time can be variable depending on the number of objects in the scene, other processes on the computer, or even the computer itself.
This is a common, somewhat subtle, mistake in game programming, but it can easily be remedied. The trick is to store the time at the end of each draw loop and then take the difference of the last update with the current time at the start. Then you should scale all animations and game changes based on the actual elapsed time.
I've wrote more about this on my blog a while back here: http://laststop.spaceislimited.org/2008/05/17/programming-a-pong-clone-in-c-and-opengl-part-i/
Part II specifically covers this issue:
http://laststop.spaceislimited.org/2008/06/02/programming-pong-in-c-and-opengl-part-ii/
Can you please help me answer the following questions?
How do people usually implement a timed event in games?
Example: You reach some point in time and something happens like a new wave of enemies appears or something similar.
What is the best way to make sprite animations?
Example: Explosions in an android game.
1) Every time round your game loop you will want to record the elapsed time (or delta time.) This means you could keep track of the time past since the game start and the time it took to execute one iteration of your loop (the latter is good for time based movement.)
2) Depends really, I'm assuming this is 2D so I personally use sprite maps (google it) and then after x seconds I will change the image that is being rendered to the next on in the animation sequence. Animation sequences normally consist of "frames" and after x seconds have passed then move to the next frame
1 - Each frame/cycle of your game, record the time, then get the difference between the previous cycle's and the current cycle's time. This is how much time has elapsed since the last frame/cycle. Objects can then have timers that subtract the elapsed time each cycle, and do things when their timers are <= 0.
2 - My preference for game development is flixel, which does a lot of the dirty work for you. If you want to use pixel images instead of vector graphics, you should take a look at flixel. It has a framework that makes working with images and spritesheet animations a breeze. At the very least you can figure out how flixel handles them and write your own methods based on what you learned. If you want vector graphics, however, you'll need some other solution.
It would be really cool to benchmark how many times per second an animation actually gets drawn to the screen in an android app. Is there a way to do it?
ie. I can set an animation to run over a 250ms period, but I want to benchmark how smooth it is objectively.
If you have a game loop running, you can calculate the framerate as follows:
FrameRate= 1000/LoopTime
Where LoopTime is the time it takes to execute an Update call and Draw call.
if i call invlidate() at the end of onDraw() function in a View, at what rate does the system refreshers?.
In emulator it takes around 1 second to call the method.
What are you using the canvas for? If you're doing a game or something that needs to be refreshed constantly you should really use a SurfaceView. That will take care of calling the draw method at regular intervals without you having to call invalidate. That said the refresh rate of a SurfaceView really depends on what you're drawing. If all you're doing is clearing it then it can do many hundreds of frames per second.