2009-09-22 10 views
13

私はアンドロイドゲームを作ろうとしています。なぜ、view.invalidateが、アンドロイドゲームで画面を直ちに再描画しないのですか?

私はアクティビティを拡張し、すべてのユーザー入力を処理するゲームクラスを持っています。次に、私は、ビューを拡張し、画面上にレベルを描画するmissionViewクラスを持っています。

ユーザーがドアをクリックすると、アニメーションを追加したいと思います。

何が起こるか:ゲームはdoor.openを呼び出します。 view.onDraw関数がドアを半開きにするように状態を変更します。ゲームはview.invalidateを呼び出し、画面を再描画します。その後、ゲームは0.5秒間スリープ状態になります。それから、再びdoor.openを呼び出します。 2回目に関数が呼び出されると、状態を変更するので、view.onDraw関数はドアを完全に開くようにします。その後、ゲームはview.invalidateを再度呼び出します。

問題は、view.invalidateになると画面を再描画しないことです。行にブレークポイントを設定し、デバッガを実行してstepをクリックすると、view.onDraw関数に入ることはありません。実行中のコードを表示することさえできません。

私は何を持っていることは次のとおりです。 ドアクラス:

public boolean open() 
{ 
    if (doorState == DoorState.Closed) 
    { 
     doorState = DoorState.Opening; 

     return true; 
    } 
    else if (doorState == DoorState.Opening) 
    { 
     doorState = doorState.Open; 
     return true; 
    } 
    else 
    { 
     return false; 
    } 
} 

ゲームクラス:

if (tile instanceof DoorTile) 
{ 
    DoorTile doorTile = (DoorTile) tile; 
    Door door = doorTile.getDoor(); 

    if (door.isClosed()) 
    { 
     door.open(); 
     selectedEntity.openDoor(); 
     view.invalidate(); // This line does not work 

     try 
     { 
      Thread.sleep(500); 
     } 
     catch (InterruptedException e1) 
     { 
      // TODO Auto-generated catch block 
      e1.printStackTrace(); 
     } 
     door.open(); 

     // Handled touch event so break switch statement 
     break; 
    } 
} 
+0

私はこのディスカッションを読んだことがありますが、自分のコードを動作させるために何をすべきか理解していませんでした。 "Handler"と "Message"の使い方を理解できませんでした。 –

+0

http://stackoverflow.com/questions/2801877/android-why-wont-invalidate-update-my-buttons-immediatelyで関連するディスカッションをお楽しみになることがあります。 –

答えて

22

ビュー#無効化はメインスレッドとすぐに(onDraw経由)ビューを再描画するようにシステムに指示しますアイドル状態になります。つまり、invalidateを呼び出すと、他のすべての即時処理が完了した後にビューが再描画されるようにスケジュールが設定されます。 Gameクラスのコードがメインスレッドから呼び出されていて、そのスレッドをスリープ状態にすると、レンダリングを一時停止するだけでなく、入力処理をすべて一緒に一時停止します(通常は悪い考えです)。経験則として、あなたが何をしているのか分からない限り、あなた自身が産んでいないスレッドをスリープさせることは決してありません。

ゲームロジックをThread#sleepで定期的に遅延させたい場合は別のスレッドで実行し、view.postInvalidate()を使用してメインスレッドが起床してonDrawを呼び出すよう通知します。

+2

自分のスレッドはすべてUIスレッドで実行されます。このスレッドで眠ったり計算したりすると、レスポンスの少ないUIが表示され、最終的にはANR(Application Not Responding)ボックスが表示されます。 – Will

14

ゲームでは、私は実際にグラフィックスへのアクセスを低くします。 GoogleのLunarLanderはその優れた例です。基本的には次の2つのことを行う必要があります。SurfaceViewから

  • 代わりにビューの利用SurfaceViewの
  • GETハンドラを
  • private void repaint() { 
        Canvas c = null; 
        try { 
        c = surfaceHolder.lockCanvas(); 
        paint(c); 
        } finally { 
        if (c != null) { 
         surfaceHolder.unlockCanvasAndPost(c); 
        } 
        } 
    } 
    
    を含んでいるでしょうカスタムメソッドの再描画()とview.invalidate()を置き換えます

Paintメソッドは、現時点ではあなたがView.onDrawに持っているものが含まれます

+0

私はあなたが言ったことをしました。それは...一種の作品です。ドアは現在アニメーションされていますが、画面上をスクロールするとグラフィックスのグリッチが発生します。ユーザーが指でスクロールしたときに画面を再描画するゲームクラスにジェスチャーリスナーがあります。地図をスクロールすることができます。それは細かい描画するために使用されます。しかし、今は画面の半分が描画され、残りの半分は半分の時間が更新される前に更新されていません。 –

+2

異なるビュークラスを使用しても、この「問題」は解決されません。メインスレッドでスリープを呼び出すことは決してないことを理解する必要があり、その無効化はすぐに描画をトリガするのではなく、UIスレッドが次に行うときに再描画が必要な領域を「記憶」する。 – Zordid

0

私は自分のアプリケーションで同じ問題に直面しました。

私の場合はメソッド[AsyncTask][2]からinvalidate()を呼び出そうとしていました。

この問題は、invalidate()[onProgressUpdate()][3]の方法AsyncTaskに移動することで解決しました。私。doInBackground()メソッドのUIをAsyncTaskから更新することはできません。それはAndroidのドキュメントで言及されていますが、それを忘れるのは簡単です...だから、それを確認することを忘れないでください。

関連する問題