衝突検出により画面の描画が遅くなる


8

私は最近ゲーム開発を趣味として追求しており、ゲーム開発のインとアウトを学ぶためには、ゲームを作成し、すべてを自分でレンダリングする必要があると判断しました(ゲームエンジンを使用せずに)。これはかなり複雑であることがわかりましたが、私は大きな進歩を遂げています。ただし、Androidフォンがグラフィックをレンダリングする方法に関連している可能性があると思われる問題が発生しました。この問題についての説明が必要です。

問題

私のゲームには、大砲に一連のボールが含まれています。ユーザーが画面を押すと、大砲がボールを発射し、エンジン(実装中)が位置情報の更新とそこからの衝突検出を処理します。さて、衝突検出を実装する前は、ゲームは非常にスムーズに応答しましたが、境界内にある場合にのみビードを描画し、それ以外の場合は壁から「跳ね返る」ようにエンジンに指示すると、エンジンはループの実行時間が大幅に長くなりました。

これは、ユーザーエクスペリエンスに提供しているレイテンシがなければ、問題ありません。たとえば、画面に触れたとき、ボールが画面内を移動しているように表示されるまで約2秒かかり、まったく表示されない場合もあります。以前は、反応は瞬間的でした。

さらに、物理エンジンの衝突検出部分をコメントアウトすると、通常の応答動作が再開されます。

私がこの行動を引き起こしていると思うこと

注:私はこの仮定を取り消しました(以下の「デバッグ情報」を参照してください)。

私のゲームにはフレームリミッターが実装されておらず、ハードウェアで可能な限り高速にレンダリングされているため、画面に非常に多くの古いフレーム(バッファー内など)を描画していると思います物理を更新している間、描画に忙しい。これまでの私のデバッグでは、これが当てはまることを示していませんが、他の結論に達することはできません。

いくつかのコード

このコードは、すべてが何をするのかを知らないことを理解するのがかなり混乱することに注意してください。誰かがいくつかのコードを操作することにこだわった場合に備えて、単にそれを含めました。変数は抜粋の下で明確にされています。

PhysicsEngine.updateBeadPositions(float)

private void updateBeadPositions(float delta){

    //Update all of the beads currently on the board.
    beads = control.getBoard().getValues();

    temp_x = 0.0f;
    temp_y = 0.0f;

    //For each row...
    for(Bead[] row : beads){

        //For each bead...
        for(Bead bead : row){

            //If this bead exists...
            if(bead != null){

                temp_y = (float) (bead.getYCoordinate() * bead.getYVelocity() * delta);

                //If the coordinates are within the bounds of the game
                if(outwithVerticalBounds(temp_y, control.getBoard())){

                    //Set the X coordinate equal to the distance * the time differential (delta).
                    bead.setXCoordinate(temp_x);

                    //Set the X coordinate equal to the distance * the time differential (delta).
                    bead.setYCoordinate(temp_y);
                }
            }
        }
    }

    //If the cannon Bead has been set...
    if(control.getCannon().getReleased() != null){

        //Update the cannon bead
        if(control.getCannon().getReleased().getXVelocity() == PhysicsEngine.VELOCITY_STATIC && control.getCannon().getReleased().getYVelocity() == PhysicsEngine.VELOCITY_STATIC){

            control.getCannon().getReleased().setXCoordinate(control.getCannon().getX());
            control.getCannon().getReleased().setYCoordinate(control.getCannon().getY() - Cannon.PIVOT_Y_OFFSET);
        }
        else{

            temp_x = control.getCannon().getReleased().getXCoordinate() + (control.getCannon().getReleased().getXVelocity() * delta);
            temp_y = control.getCannon().getReleased().getYCoordinate() + (control.getCannon().getReleased().getYVelocity() * delta);

            //TODO: Commented out collision checkers!

            //If the horizontal coordinates are within the bounds of the game
            if(!outwithHorizontalBounds(temp_x, control.getBoard())){

                //If the vertical coordinates are within the bounds of game
                if(!outwithVerticalBounds(temp_y, control.getBoard())){

                    //Set the X coordinate equal to the distance * the time differential (delta).       
                    control.getCannon().getReleased().setXCoordinate(temp_x);

                    //Set the X coordinate equal to the distance * the time differential (delta).
                    control.getCannon().getReleased().setYCoordinate(temp_y);
                }
                //Otherwise...
                else{

                    //Bounds off the wall in the y direction
                    control.getCannon().getReleased().setYVelocity(-1.0f * control.getCannon().getReleased().getYVelocity());
                }
            }
            //Otherwise...
            else{

                //Bounce off the wall in the x direction (flip the x velocity)
                control.getCannon().getReleased().setXVelocity(-1.0f * control.getCannon().getReleased().getXVelocity());
            }
        }
    }
}

ここでは、変数は次のように定義されています。

  • control私のゲームコントローラへの参照です。ゲームコードの大部分をパッケージ化しています。

  • beads 現在ボード上のビーズを含む2D配列への参照です(動いているものを除く)。

  • delta 物理エンジンへの以前の呼び出しと現在の呼び出しの間の時間差です

他の説明については、コード内のコメントを参照してください。

PhysicsEngine.outwithHorizo​​ntalBounds(float、Board)

private boolean outwithHorizontalBounds(float x, Board board){

    //If the horizontal values are within the bounds...
    if(x > (board.getRight() - bead_radius)){

        return true;
    }

    if(x < (board.getLeft() + bead_radius)){

        return true;
    }

    //Otherwise, it is not.
    return false;
}

メソッドoutwithVerticalBounds(float, Board)は同等の機能ですが、y方向です。


私の質問

衝突検出については、画面のレンダリングが大幅に抑制されますか?私はそれが非常に集中的な操作であることを知っていますが、私のデバッグは、物理の更新が描画と同時に完了することを示しています。

デバッグ情報

最終更新日:2013年1月29日16:27 EST

これは、これまでに入手したデバッグ情報の集約です。時間の経過に応じてこれを更新します。

  • update()私のエンジン内のメソッドは、平均して、.018 ms実行するだけです。通常、0.020 ms画面をタップしてビードを離すと、遅延は最大にジャンプします。

  • ドローとゲームの更新の時間を比較した後、私は正しかったように見えます:それらは同時に発生しています。したがって、これは問題ではありませんよね?

  • FPSゲームのは大体ある87それは(ローエンドで)にランダムにスパイク、60 FPSしかし、このスパイクがされていないビーズの解放に関連します。これFPSを行うことには欠点はありません。ビードが解放された後に複雑さが増すのはupdate()呼び出しだけなので、これは理にかなっています。描画は依然として可能な限り速く行われます。

  • さらなるテストの後、これはスクリーンが物理学より遅れているという事実ではないことが明らかになりました。私はこれに触れたときに画面の背景が白くなる単純なブール値フラグでこれをテストしましたこれはすぐに発生します。したがって、ビードが描画されない原因は他にもあるはずです。すぐに更新します。

補足情報

これが私の状況を理解するのに役立つ補足情報です。

  • これをGoogle Nexus 7でテストしています。

  • マップ上に一度に更新されているビーズがかなりあります(約30)が、移動しているのは1つだけです。

  • 通常、ビードが動き始めた後(最初の遅延の後、実際に描画された場合)は、非常にスムーズに動き続けます。

  • タッチイベントに反応して更新される他のUI要素が画面上にあることに注意してください。たとえば、大砲にロードされたビーズは、画面がタッチされたときに(リリースされたことを示す)新しいビーズになりますが、モバイルビーズは描画されません。


ドローに合わせた物理の更新を示すデバッグが不正確であると思いますか?このコードで他のプロファイリングを行いましたか?
MichaelHouse

私はコンソール(LogCat)への出力を使用していくつかの広範なデバッグを行いましたが、これより複雑なものはありません。私のデバッグステートメントが正しくない場合がある可能性があります。今すぐ確認します。
Squagem 2013年

また、バウンディングケースを追加するときにFPS(Frames Per Second)が変更される場合や、問題がプログラムの実行速度に関係しない場合も興味深いです。
Qqwy 2013年

私はあなたが提起したポイントに答えるために私の質問を編集しました。
Squagem 2013年

回答:


8

率直に言って、私は問題の解決に何時間も費やしていたので、自分の問題の解決策を発表するのはかなり恥ずかしいです。明るい面では、さらにパフォーマンスを向上させるために最適化できる他のいくつかのコードを見つけることになりました。

ソリューション

ビーズを発射していた大砲は、私のプレイ可能領域の下限より下にありました。

これは誤解を招くものでした。私の演奏領域の下限が電話の実際の画面の下部より少し上にあるからです。つまり、基本的に、物理エンジンはそれを画面にレンダリングする前に、約5秒間、それを4度とわずかに(人間の目には見えない)バウンドさせていました。

大砲を50ピクセル高く移動しました。


助けてくれてありがとう!私はあなたの思慮深い提案なしにはここに来なかっただろう。


3
+1は適切にフォーマットされた質問の場合、+ 1は自分で回答する場合
RoughPlace

おっと、この質問を忘れました!みんなありがとう:)
Squagem 2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.