【问题标题】:smooth animations in games游戏中的流畅动画
【发布时间】:2012-11-27 17:10:56
【问题描述】:

如何创建“流畅”的动画?我正在开发一款安卓游戏。我知道做平滑动画的默认方法不是最好的:

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 毫秒。这似乎是极端的,但对于给定的系统,你不应该感觉到差异。 (我正在尝试模拟我的游戏系统,以找出为什么我的实际游戏引擎中的动画不流畅;所以我使用的是最坏的情况)

编辑:如果没有直接的答案,也许有人可以指出我如何找出“错误”可能在哪里。我能做些什么来正确分析这些事情?

【问题讨论】:

    标签: animation frame-rate smooth


    【解决方案1】:

    所以,终于!两周后,我找到了一个简单的解决方案!问题是我使用了 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);
    }
    }
    

    如果您喜欢,请随时投票 :) 谢谢。

    【讨论】:

      【解决方案2】:

      我认为这行有一个错字:frameTime = lastTime - time;应该是 frameTime = time - lastTime;虽然我认为你的真实代码没有这个问题,否则事情真的会出错。

      想到一个问题,您的模拟步骤需要多长时间?你确定那不是瓶颈吗?也许模拟跟不上您的渲染器?

      【讨论】:

      • 对,你没看错,应该是frameTime = time - lastTime;我纠正了错误。嗯,我不确定。如果我记得每次调用(模拟和渲染)在 traceview 中显示正确,大约是 600。问题是什么 600。[ms] 是不可能的。它比调用 System.currentTimeMillis(); 稍长一些。但也许我读错了表格。您应该记住,目前模拟中只有大约 3 个对象,它们几乎没有做任何事情,只是几个函数调用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-31
      相关资源
      最近更新 更多