2012-04-28 15 views
1

は、Androidでの2Dゲームを描画するためのSurfaceViewを使用するにはAndroidのSurfaceViewでCPU速度とは無関係に描画、私はこれがで使う主な活動のonCreate()計算を作成し、

このクラスへの参照です
setContentView(new GameView(this)); 

public class GameView extends SurfaceView implements SurfaceHolder.Callback 

また、私はそのrun()機能付きのスレッドがあります

public void run() { 
    Canvas c; 
    while (_run) { 
     c = null; 
     try { 
      c = _surfaceHolder.lockCanvas(null); 
      synchronized (_surfaceHolder) { 
       _panel.updatePhysics(); 
       _panel.onDraw(c); 
      } 
     } 
     finally { // when exception is thrown above we may not leave the surface in an inconsistent state 
      if (c != null) { 
       _surfaceHolder.unlockCanvasAndPost(c); 
      } 
     } 
    } 
} 

私はいくつかの計算を行います。彼らは、もちろん、この簡単な例よりも複雑ですが、同じように動作:

public void updatePhysics() { 
    GraphicObject.Coordinates coord; 
    GraphicObject.Speed speed; 
    for (GraphicObject graphic : _allElements) { 
     coord = graphic.getCoordinates(); 
     speed = graphic.getSpeed(); 
     coord.setX(coord.getX() + speed.getX()); 
     coord.setY(coord.getY() + speed.getY()); 
     ... 
    } 
} 

をそしてonDraw()に、私はキャンバスにすべてを描く:

@Override 
public void onDraw(Canvas canvas) { 
    canvas.drawBitmap(BITMAP, xPos, yPos, null); 
    ... 
} 

は、これが正常に動作します - すべてを。私のデバイスでそれをテストしたところ、かなり見栄えが良かった。しかし、私が他の人にそれを渡して試合をしたとき、オブジェクトははるかに速く動いていました!なぜこれはそうですか?スレッドはできるだけ頻繁にupdatePhysics()を呼び出します。これは、高速デバイスがこの機能をより頻繁に呼び出すことを意味しますか?

どのように私はこれを防ぐ、すべてのデバイスに均等に高速なゲームを作ることができますか?このようなもの?

private long lastRun = System.currentTimeMillis(); 

public void updatePhysics() { 
    long millisPassed = System.currentTimeMillis()-lastRun; 
    ... 
    float newCoord = (coord.getX() + speed.getX()) * millisPassed/33; 
    coord.setX(newCoord); 
    ... 
} 

ありがとうございます!

+0

まさにあなたが提案したもののように。システムクロックを参照する必要があります。一定の間隔で更新する(フレームレートを制限し、それによって悪くなる可能性があります)、または時間に基づいて物事を計算してください。 – zapl

+1

フレーム依存ではなく提案(2)のように直接依存する時間にしてください。したがって、すべてのフレームが同じ期間を意味するわけではありません。 –

+0

ありがとう、ザップルとグスタボ!ですから、毎回の計算を '* milli_seconds_passed/40'のようなもので包む必要がありますか?そして定数「40」では、すべての速さが決まります。 – caw

答えて

3

あなたは、すべてあなたの物理学を計算する時刻を直接使用することができます。それは通常最もうまくいくでしょう。

あなたは時間に基づいて計算する方法がない場合ので、あなたはそれがちょうど基づいており、次のステップを生成することは、あなたが別のオプションを持っている多くの時間を取らないことを知っているのステップで何をしていますか。

次の2つのスレッドを作成します。最初のものは、固定レートで状態を進めます(そして、遅いデバイスでもこのレートで動作することを確認する必要があります)。 2番目のものは現在の状態を取り、それを描画します。 2番目のスレッドは、単純にいくつかの状態をスキップする(または、速い場合は同じ状態を何度か描く)ので、望みどおりに遅くすることができます。

小さな例を以下にいくつかの状態オブジェクトを進め、消費するスレッドが、それはまだあなたを与えるために失敗します

class GameState { 
    private int state = 0; 

    public GameState advanceState() { 
     GameState result = new GameState(); 
     result.state = this.state + 1; 
     return result; 
    } 
} 

class SurfaceViewImplementation extends SurfaceView { 

    // the current state 
    volatile GameState mState = new GameState(); 

    void somewhere() { 
     Thread fastProducer = new Thread(new Runnable() { 
      private static final long MAX_WAIT = 1000/60; 
      @Override 
      public void run() { 
       while (!Thread.interrupted()) { 
        long timeBefore = SystemClock.currentThreadTimeMillis(); 
        GameState newState = mState.advanceState(); 
        mState = newState; 
        long timeAfter = SystemClock.currentThreadTimeMillis(); 
        long timeSpent = timeAfter - timeBefore; 
        SystemClock.sleep(Math.max(0, MAX_WAIT - timeSpent)); 
       } 
      } 
     }); 
     fastProducer.start(); 
     Thread slowConsumer = new Thread(new Runnable() { 
      @Override 
      public void run() { 
       while (!Thread.interrupted()) { 
        GameState currentState = mState; 
        longRunningDraw(currentState); 
       } 
      } 
     }); 
     slowConsumer.start(); 
    } 
} 

を変更します状態のオブジェクトのことを心配する必要はありませんので、参照を毎回代わる一つのスレッドを持っています生成スレッドが所望の速度で実行できない場合には速度に依存しない結果となる。

+0

この代替ソリューションをありがとう!あなたの紹介は決定が容易になりました。私が選択する解決策は時間依存のものになります。 – caw

-1

私はフレームのレンダリングを開始するとき(あなたの場合はupdatePhysics()です)、次にこの時点までになったときは、どれだけの時間が経過したかを知っています。 Thread.Sleep();

+2

'sleep 'は上限(たとえば60fps)が必要な場合にのみ機能しますが、デバイスがあなたの制限よりも遅い場合でも同じ問題があります。 – zapl

+0

あなたがあなたのデザインを改善しようとしている以外は何もしていない、より速く、より速いときだけ眠ることはありません。openglを試してみてください –

+2

しかし、例えば1フレームまたは2フレームで35fpsに落とすと、あなたの物理学はすべて台無しになる。どのくらいの時間が経過したかに基づいて物理学を更新することは、標準的で最良の解決策です。 –

関連する問題