3

Android 開発者の皆様、こんにちは。

OpenGLES 1.0 を使用して、Eclipse で Android 用の簡単なゲームを開発しています。開発用デバイスとして Samsung Galaxy S2 Android(2.3) を使用しています。

デュアルコアとフレームレート一定化について質問です。

そのため、GLSurfaceView の作成を管理し、LogicUpdate(deltatime) 関数と Render() 関数を呼び出す onDrawFrame() 関数をオーバーライドしました。

はい、今のところすべてシングル スレッドです。

私が得ている問題は、デュアルコアにあります。[設定] -> [省電力] に移動してデュアル コアを無効にし、[システムの省電力] をチェックすると、レンダリングが 30 FPS で自動的にロックされることがわかります。しかし、[システムの省電力] のチェックを外してデュアル コアを有効にすると、レンダリングが 60 FPS でロックされていることがわかりますが、電話が熱くなり、バッテリーの消耗が非常に速くなります。

したがって、バッテリーを節約するために、ゲームを 30 FPS で実行し続けるという考えです。

これを行うには、以下のコードを使用します。

ロジックの更新を行う前に、このコードの平和を呼び出します。これはすべて onDrawFrame() で行われることを思い出してください。

if( CONST_FPS > 0 && StartTime > 0 )
{           
    /////////////////////////////////////////////////////////////////
    // Get frame time
    ////////////////////////////////////////////////////////////////
    long endTime  = System.currentTimeMillis(); 
    long time     = endTime - StartTime;
    //              
    long wantedtime = 1000 / CONST_FPS;
    //
    long wait = 0;
    if( time < wantedtime )
    {
        wait = wantedtime - time;
        //                  
        Thread.sleep(wait);
    }
    else
    {
        //Time to big game will slow down
    }                           
}

CONST_FPS = 30 の場合

その後

StartTime = System.currentTimeMillis(); //

UpdateLogic(1.0 / CONST_FPS);
Render();

主に FPS をロックする必要がないため、30 FPS でのゲームプレイは非常にスムーズです。しかし、60FPS を 30 FPS にロックしようとすると、どもりが発生します。私はいくつかの調査を行い、Thread.Sleep() が正確ではないことがわかりました。これは本当ですか?60FPS から 30FPS にロックする場合、ゲームプレイをよりスムーズにするために他に何ができますか?

答えてくれてありがとう...

4

2 に答える 2

7

経過時間を使用してすべての動きをスケーリングし、さまざまなFPSレートで動きがスムーズに保たれるようにする必要があります。次のように経過時間を取得できます。

long currentTime = System.currentTimeMillis();
float elapsed = (System.currentTimeMillis() - lastFrameTime) * .001f;//convert ms to seconds
lastFrameTime = currentTime; 

次に、速度を1秒あたりの単位で表し、次のように位置を更新します。

sprite.x += (sprite.xspeed * elapsed);
于 2012-07-11T04:20:25.603 に答える
3
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    GLES20.glClearColor(0.1f, 0.1f, 0.1f, 1);
    GLES20.glEnable(GLES20.GL_DEPTH_TEST);
    GLES20.glDepthFunc(GLES20.GL_LEQUAL);
    GLES20Renderer.programLight = GLES20.glCreateProgram();
    int vertexShaderLight       = GLES20Renderer.loadShader(GLES20.GL_VERTEX_SHADER, GLES20Renderer.vertexShaderCodeLight);
    int fragmentShaderLight     = GLES20Renderer.loadShader(GLES20.GL_FRAGMENT_SHADER, GLES20Renderer.fragmentShaderCodeLight);
    GLES20.glAttachShader(GLES20Renderer.programLight, vertexShaderLight);
    GLES20.glAttachShader(GLES20Renderer.programLight, fragmentShaderLight);
    GLES20.glLinkProgram(GLES20Renderer.programLight);
    System.gc();
}

public void onSurfaceChanged(GL10 gl, int width, int height) {
    gl.glViewport(0, 0, width, height);
    float ratio = (float) width / height;
    Matrix.setLookAtM(GLES20Renderer.ViewMatrix, 0, 0, 0, 5f, 0, 0, 0, 0, 1, 0);
    Matrix.frustumM(GLES20Renderer.ProjectionMatrix, 0, -ratio, ratio, -1, 1, 2, 8);
    Matrix.setIdentityM(LightModelMatrix, 0);
    Matrix.translateM(LightModelMatrix, 0, -1.0f, 0.0f, 3f);
    Matrix.multiplyMV(LightPosInWorldSpace, 0, LightModelMatrix, 0, LightPosInModelSpace, 0);
    Matrix.multiplyMV(LightPosInEyeSpace, 0, ViewMatrix, 0, LightPosInWorldSpace, 0);

    System.gc();
}

public void onDrawFrame(GL10 gl) {
    long deltaTime,startTime,endTime;
    startTime   = SystemClock.uptimeMillis() % 1000;
    gl.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
    synchronized (this) {
        updateModel(GLES20Renderer._xAngle, GLES20Renderer._yAngle, GLES20Renderer._zAngle);            
    }
    renderModel(gl);
    endTime     = SystemClock.uptimeMillis() % 1000;
    deltaTime   = endTime - startTime;
    if (deltaTime < 30) {
        try {
            Thread.sleep(30 - deltaTime);
        } catch (InterruptedException e) {
            //e.printStackTrace();
        }
    }

    System.gc();
}

注意:

  1. UI スレッドでスリープを使用しないでください。それは非常に非常に悪いです
  2. 静的を使用する: これは悪い OOP プラクティスですが、ここでは便利です
  3. 頂点バッファ オブジェクトを使用する
  4. onsurfacechanged で初期化し、ここでも場所 (glget__location) を取得します
  5. Froyo ガベージ コレクターが悪く、Gingerbread ではタッチ ドライバーがあまりにも多くのイベント (Google this) を起動するので、Android センサーのようなタッチを使用しないアプリ/ゲームの他の入力方法に徐々に切り替えてください。
  6. ジンジャーブレッドにアップグレード
于 2012-08-03T05:38:11.397 に答える