2014-05-30 2 views
2

게임을 만들고 있는데 게임 루프를 제외하고는 모두 잘 돌아갑니다. SurfaceView와 2D Sprites (Bitmaps)를 사용하고 있습니다. 현재 게임은 소행성 필드를 통과하는 우주선입니다. 우주선은 화면 중앙에 머물러 있으며 소행성을 움직이기 위해 전화가 어느 방향 으로든 기울어 져 있습니다 (소행성이 플레이어 대신 위치를 변경 함). 오래된 소행성이 스크린에서 떨어져서 무한한 소행성 필드 느낌을 만들어 내면서 새로운 소행성이 생성됩니다.터치 이벤트가 발생하지 않으면 Android SurfaceView가 느려집니다.

Nexus 5에서 약 3 초가 지나면 게임 루프가 60fps로 실행 되더라도 화면 아래로 움직이는 소행성이 고르지 않게되었습니다.

@Override 
public void run() { 
    Canvas canvas; 
    long startTime; 
    long timeTaken; 
    long sleepTime; 

    while (running) { 
     canvas = null; 

     //Update and Draw 
     try { 
      startTime = System.nanoTime(); 
      canvas = gameView.getHolder().lockCanvas(); 

      //Update 
      gameModel.update(gameController.getPlayerShots(), gameController.getCurrentTilt()); 

      //Game Over? 
      if (gameModel.isGameOver()) { running = false; } 

      //Draw 
      synchronized (gameView.getHolder()) { gameModel.drawToCanvas(canvas); } 
     } 
     finally { 
      if (canvas != null) { 
       gameView.getHolder().unlockCanvasAndPost(canvas); 
      } 
     } 

     //Sleep if needed 
     timeTaken = System.nanoTime() - startTime; 
     sleepTime = FRAME_TIME - timeTaken; 
     try { 
      if (sleepTime > 0) { 
       sleep(Math.abs((int)sleepTime/1000000), Math.abs((int)sleepTime % 1000000)); 
      } 

     } 
     catch (InterruptedException e) {} 
    } 

    //Load menu after game over 
    if (gameModel.isGameOver()) { 
     gameController.launchContinueMenu(); 
    } 
} 

내가 내 서피스 뷰 SurfaceView의의 onDraw() 메소드를 사용하지 않은 문제가 내 모델 캔버스 드로잉을하는 것을 할 수있다 생각하고 있음 : 다음 코드이었다. 이전처럼 onDraw() 및 동일한 결과를 사용하도록 리팩토링되었습니다. 각 프레임의 수면 시간을 인쇄 한 결과 내 스레드가 일관되게 5-10ms (프레임에서 16.667ms) 동안 잠자고 있었기 때문에 내 넥서스가 컴퓨팅 성능면에서 부족하지 않았습니다.

나는 viewholder에서 synchronize()를 사용하지 말아야한다고 stackoverflow에서 읽었습니다. 아직도 운이 없다.

그런 다음 Thread.sleep()을 사용하면 항상 정확한 것은 아니기 때문에 문제가 발생할 수 있습니다. 나는 아래와 같이 주요한 리펙 터를 만들었다.

@SuppressLint("WrongCall") 
@Override 
public void run() { 
    Canvas canvas; 

    while (running) { 
     canvas = null; 

     //Update and Draw 
     try { 
      canvas = gameView.getHolder().lockCanvas(); 

      //Calc and smooth time 
      long currentTimeMS = SystemClock.uptimeMillis(); 
      double currentDeltaTimeMS; 
      if (lastTimeMS > 0) { 
       currentDeltaTimeMS = (currentTimeMS - lastTimeMS); 
      } 
      else { 
       currentDeltaTimeMS = smoothedDeltaTimeMS; // just the first time 
      } 
      avgDeltaTimeMS = (currentDeltaTimeMS + avgDeltaTimeMS * (avgPeriod - 1))/avgPeriod; 

      // Calc a better aproximation for smooth stepTime 
      smoothedDeltaTimeMS = smoothedDeltaTimeMS + (avgDeltaTimeMS - smoothedDeltaTimeMS) * smoothFactor; 

      lastTimeMS = currentTimeMS; 

      //Update 
      gameModel.update(smoothedDeltaTimeMS/1000.0d, gameController.getCurrentTilt()); 

      //Game Over? 
      if (gameModel.isGameOver()) { running = false; } 

      //Draw 
//    synchronized (gameView.getHolder()) { 
//     gameModel.drawToCanvas(canvas); 
       gameView.onDraw(canvas); 
//    } 
     } 
     //Release canvas 
     finally { 
      if (canvas != null) { 
       gameView.getHolder().unlockCanvasAndPost(canvas); 
      } 
     } 
    } 

    //Load menu after game over 
    if (gameModel.isGameOver()) { 
     gameController.launchContinueMenu(); 
    } 
} 

이 새로운 접근 방식은 이전과 마찬가지로 set 대신에 증가의 다음 프레임을 그릴 델타 시간을 사용하여 가능한 한 빨리 그릴 수 있어야합니다. 아직도 운이 없다.

비트 맵 위치를 Rect에서 새로운 위치 클래스로 변경했습니다. int 대신 double을 사용하여 서브 픽셀 이동을 시뮬레이션합니다. 아직도 운이 없다. 내가 해봤 것들

요점을 되풀이하다 :

  1. 사용 된 onDraw() gameModel 지난 업데이트 이후 시간을 사용하여 뷰의 소유자
  2. 에 동기화()를 사용하지 마십시오 캔버스
  3. 드로잉 대신 각 update() 호출마다 하나의 프레임을 전달하는 대신 다음 프레임을 업데이트합니다. 전화를 충전하는 동안
  4. 가 Thread.sleep를 제거()이 모든 후
  5. 서브 픽셀 운동

을, 나는 게임 실행 좋은 것으로 나타났습니다. 3 초 후에 전화가 끊어지면 게임이 다시 고르지 않게됩니다. 그런 다음 게임이 고르지 않게되었을 때 화면을 탭하면 모든 것이 다시 3 초 동안 부드럽게 움직이는 것으로 나타났습니다. 내 SurfaceView 성능에 영향을 미치는 배터리 절약 기능이 있다고 생각하니? 여기서 무슨 일이 일어나고 있으며 어떻게 비활성화 할 수 있습니까? 이것은 매우 미치겠습니다. ...

호기심 (첫 번째 코드 블록)에서 첫 번째 게임 루프를 테스트하고 화면을 두드려서 모든 것이 원활하게 실행되었습니다. 사람 ... 아무 것도 복잡성을 더하는 모든 일. 좋은 학습 경험이라고 생각합니다. 내 SurfaceView를 최대 속도로 작동시키는 방법에 대한 아이디어? 도움말 크게 감사드립니다.

:

+0

여기서는 연구 노력이 부족하지 않습니다. p +1 – keyser

답변

-1

나는 당신이 또한 이전 죽일 clear top 같은 의도 플래그를 사용할 수 있습니다, 게임에 대한 더 많은 전력 (배경 레이아웃 # 000을 사용하여) 게임을 어두워, 게임 더 많은 배터리 절약을 만들려고한다고 생각합니다 램, 배터리를 절약 삭제를위한 활동 (메모리 부족 방지)

하지만 상황에 당신은 wakelock

+0

이전 활동을 종료해도 아무런 영향이 없으며 (이전 앱이 백그라운드에서 실행되기로 결정되지 않은 경우) 배터리 수명에 영향을주지 않습니다. 웨이크 잠금 장치는 장치가 완전히 잠들지 않도록합니다. 낮은 클럭 주파수까지 스로틀 링하는 것을 방지하지 못합니다. – fadden

0

귀하의 관찰이 올바른지 사용할 수 있습니다. 즉, N5의 전원 관리가 전력을 적극적으로 억제합니다. 손가락이 화면과 접촉하면 시계의 속도가 빨라져 상호 작용이 원활 해집니다. (더 자세한 내용은 내 대답 this question을 참조하십시오.)

이 문제를 해결하는 가장 좋은 방법은 때때로 프레임을 삭제해야한다는 것을 인식하는 것입니다. Grafika의 "GL 앱 기록"활동은 Choreographer에서 간단한 트릭을 사용하여이를 수행합니다. 게임 루프에 대한 몇 가지 추가 생각은 this article을 참조하십시오.

관련 문제