2011-05-01 113 views
3

如何創建「平滑」動畫?我正在開發一款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); 
} 
} 

我真的不是在遊戲開發方面的專家,但我希望我的理解這篇文章的基礎知識。仿真會根據需要經常調用以獲得固定的時間步長。問題在於複雜系統中的動畫仍然不流暢。我的程序中的FPS約爲60FPS。

測試該應用程序是用Java編寫的針對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毫秒。這似乎是極端的,但對於給定的系統,你不應該感受到差異。 (我試圖模擬我的遊戲系統,找出爲什麼我的實際遊戲引擎中的動畫不平滑;所以我使用的是最壞的情況)

編輯:如果沒有direkt答案,也許有人可以指出我如何才能找出「bug」可能在哪裏。我能做些什麼來分析這件事情是正確的?

回答

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); 
} 
} 

我如果你喜歡它,感覺自由投票:)謝謝。

0

我認爲這行有一個錯字:frameTime = lastTime - time;應該是frameTime = time - lastTime;儘管我認爲你的真實代碼沒有這個問題,否則事情真的就沒有了。

想到一個問題,您的模擬步驟需要多長時間?你確定這不是瓶頸嗎?也許模擬不能跟上你的渲染器?

+0

是的,你說得對,應該是frameTime = time - lastTime;我糾正了錯誤。嗯,我不確定。如果我記得traceview中的每個調用(模擬和渲染)都顯示正確的值大約是600.問題是600. [ms]是不可能的。它比System.currentTimeMillis()的調用略長。但也許我讀錯了表。您應該記住,目前仿真中只有大約3個對象幾乎不做任何功能調用。 – SACO 2011-05-02 08:43:08