如何制作“流畅”动画?我正在开发一款关于android的游戏。我知道做平滑动画的默认方式不是最好的:
perFrame() {
time = highrestime();
frameTime = time - lastTime;
lastTime = time;
// now you could use frameTime as delta. this will lead to not real
// smooth animations
}
我读了一些关于这个主题的文件。特别是如果你使用物理模拟。着名的文章似乎是这样的:http://gafferongames.com/game-physics/fix-your-timestep/ 我创建了一个基本类,如下所示:
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);
}
}
我真的不是游戏开发方面的专家,但我希望我理解本文的基础知识。 .simulate经常被调用以具有固定的时间步长。问题是复杂系统中的动画仍然不顺畅。我的计划中的FPS约为60FPS。
测试应用程序是用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();
}
}
随机睡眠总和将是最大值。 13毫秒。这似乎是极端的,但对于给定的系统,你不应该感觉到差异。 (我试图模拟我的游戏系统,找出为什么我的实际游戏引擎中的动画不平滑;所以我使用的是最糟糕的情况)
编辑:如果没有直接答案,也许有人可以指出我如何找出“错误”的位置。我能做些什么来分析这些事情是正确的?
答案 0 :(得分:8)
所以,最后!两周后,我找到了一个简单的解决方案!问题是我使用了System.currentTimeMillis();看起来这个计时器的分辨率不够高,无法做到流畅的动画。我重写了计时器类,现在它完美无缺。对于任何人,如何遇到类似的问题,并希望使用我的代码:
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);
}
}
如果你愿意,我可以随意投票:)谢谢。
答案 1 :(得分:0)
我认为这一行有一个拼写错误:frameTime = lastTime - time;应该是frameTime = time - lastTime;虽然我认为你的真实代码没有那个问题,否则事情真的会消失。
想到一个问题,您的模拟步骤需要多长时间?你确定那不是瓶颈吗?也许模拟无法跟上你的渲染器?