How can I create a "smooth" animation? I am developing a game on android. I know that the default way to do smooth animations is not the best:
perFrame() {
time = highrestime();
frameTime = time - lastTime;
lastTime = time;
// now you could use frameTime as delta. this will lead to not real
// smooth animations
}
I read some documents about this theme. Especially if you use physic simulations. Famous article seems to be this: http://gafferongames.com/game-physics/fix-your-timestep/ I created a 开发者_如何学编程basic class which looks like this:
public class TimeSystem {
private long mCurrentTime;
private long mAccumulator;
private Simulation mSimulation;
private Renderer mRenderer;
private static float mSimulationDelta = 1000f / 60f;
public TimeSystem(Simulation simulation, Renderer renderer) {
mCurrentTime = System.currentTimeMillis();
mAccumulator = 0;
mSimulation = simulation;
mRenderer = renderer;
}
public void notifyNextFrame() {
long newTime;
long frameTime;
newTime = System.currentTimeMillis();
frameTime = newTime - mCurrentTime;
mCurrentTime = newTime;
if(frameTime > 250)
frameTime = 250;
mAccumulator += frameTime;
// while full steps of simulation steps can be simulated
while(mAccumulator >= mSimulationDelta) {
mSimulation.simulate(mSimulationDelta);
mAccumulator -= mSimulationDelta;
}
// render
mRenderer.render(frameTime / 1000.0f); // frameTime in seconds
}
public interface Simulation
{
void simulate(float delta);
}
public interface Renderer
{
void render(float delta);
}
}
I am really not an expert in game development but I hope I understand the basics of this article. .simulate is called as often as needed to have a fixed timestep. The problem is that the animation in a complex system is still not smooth. FPS in my program is about 60FPS.
The application for testing is written in java for android:
public float x = 40;
public float y = 40;
public float xmove = 0.1f;
public float ymove = 0.05f;
public void simulate(float delta) {
x += xmove * delta;
y += ymove * delta;
if(xmove > 0)
{
if(x > 480)
xmove = -xmove;
}
else if(xmove < 0)
{
if(x < 0)
xmove = -xmove;
}
if(ymove > 0)
{
if(y > 480)
ymove = -ymove;
}
else
{
if(y < 0)
ymove = -ymove;
}
RandomSleep(8);
}
Random rnd = new Random();
public void doDraw(Canvas canvas, float delta) {
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.FILL);
paint.setTextSize(30);
canvas.drawColor(Color.BLUE);
canvas.drawCircle(x, y, 10, paint);
canvas.drawText("" + FPSConverter.getFPSFromSeconds(delta), 40, 40, paint);
RandomSleep(5);
}
public void RandomSleep(int maxMS)
{
try {
Thread.sleep((int)(rnd.nextDouble()*maxMS));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
The random sleeps in sum will be max. 13ms. Which seems to be extrem but with the given system you should not feel the difference. (I am trying to simulate my game system to find out why the animations in my actual game engine are not smooth; so i am using a worst case scenario)
EDIT: If there is no direkt answer maybe someone can point out how I can find out where the "bug" might be. What I could do to analyse this things correct?
So, finally! After two weeks I found a simple solution! The problem was that i used System.currentTimeMillis(); It seems the resolution of this timer is not high enough to do smooth animations. I rewrite the timer class and now it works perfect. For anyone how have a similar problem and would like to use my code:
public class TimeSystem
{
private long mOldTime;
private long mAccumulator;
private long mNewTime;
private long mFrameTime;
private Simulation mSimulation;
private Renderer mRenderer;
private static final long mSimulationDelta = 1000 * 1000 / 10;
private static final float mSimulationDeltaInMilliseconds = mSimulationDelta / 1000;
private static final long mMaxFrameTime = mSimulationDelta;
public TimeSystem(Simulation simulation, Renderer renderer)
{
mSimulation = simulation;
mRenderer = renderer;
mAccumulator = 0;
mOldTime = System.nanoTime();
}
public void notifyNextFrame()
{
mNewTime = System.nanoTime();
mFrameTime = mNewTime - mOldTime;
mOldTime = mNewTime;
// if FPS is to slow don't produce even more CPU usage
if (mFrameTime > mMaxFrameTime)
mFrameTime = mMaxFrameTime;
mAccumulator += mFrameTime;
// while full steps of simulation steps can be simulated
while (mAccumulator >= mSimulationDelta)
{
mSimulation.simulate(mSimulationDeltaInMilliseconds);
mAccumulator -= mSimulationDelta;
}
// render
mRenderer.render(mFrameTime / 1000f*1000f);
}
public interface Simulation
{
void simulate(float delta);
}
public interface Renderer
{
void render(float delta);
}
}
I if you like it feel free to vote :) Thanks.
I think there is a typo in in this line: frameTime = lastTime - time; should be frameTime = time - lastTime; though I think your real code doesn't have that problem or else things would really be off.
One question that comes to mind, how long does your simulation step take? Are you sure that that is not the bottleneck? Maybe the simulation just can't keep up with your renderer?
精彩评论