2012-07-08 82 views
2

你好Android開發恆FPS的Android OpenGLES

我開發Android在Eclipse中使用OpenGLES 1.0一個簡單的遊戲。我使用三星Galaxy S2 Android(2.3)作爲開發設備。

我有一個關於雙核心,並使幀速率不變的問題。

所以我管理創建GLSurfaceView並重寫onDrawFrame()函數,我稱之爲LogicUpdate(deltatime)函數和Render()函數。

是的,現在都在單線程中。

我得到的問題是雙核心。如果我通過進入設置 - >節能並檢查系統省電功能來禁用雙核,我意識到渲染會自動鎖定在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(); 

遊戲以每秒30幀非常流暢,主要是因爲它並不需要鎖定FPS。 但是,當試圖鎖定60FPS到30 FPS我會口吃。我做了一些研究,發現Thread.Sleep()並不精確。這是真的?當鎖定60FPS到30FPS時,我還能做些什麼來使遊戲更加流暢。

感謝您的回答...

回答

6

您應該使用經過時間擴展所有的運動,使運動保持在不同的FPS率平穩。你可以得到經過的時間是這樣的:

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

然後表達以秒爲單位的速度,並更新這樣的位置:

sprite.x += (sprite.xspeed * elapsed); 
2
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. 使用靜:雖然這是不好的面向對象編程慣例,它是在這裏有用
  3. 使用vertexbuffer對象onsurfacechanged
  4. 初始化和抓取位置(glget__location)也在這裏
  5. 這不是你故障始終是因爲Froyo垃圾回收器不好,然後在薑餅觸摸驅動程序發射太多事件(谷歌這一點),所以逐漸切換到其他輸入方法爲您的應用程序/遊戲,不使用像Android傳感器的觸摸
  6. 升級到薑餅