게임을 만들고 있는데 게임 루프를 제외하고는 모두 잘 돌아갑니다. 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을 사용하여 서브 픽셀 이동을 시뮬레이션합니다. 아직도 운이 없다. 내가 해봤 것들
요점을 되풀이하다 :
- 사용 된 onDraw() gameModel 지난 업데이트 이후 시간을 사용하여 뷰의 소유자
- 에 동기화()를 사용하지 마십시오 캔버스
- 드로잉 대신 각 update() 호출마다 하나의 프레임을 전달하는 대신 다음 프레임을 업데이트합니다. 전화를 충전하는 동안
- 가 Thread.sleep를 제거()이 모든 후
- 서브 픽셀 운동
을, 나는 게임 실행 좋은 것으로 나타났습니다. 3 초 후에 전화가 끊어지면 게임이 다시 고르지 않게됩니다. 그런 다음 게임이 고르지 않게되었을 때 화면을 탭하면 모든 것이 다시 3 초 동안 부드럽게 움직이는 것으로 나타났습니다. 내 SurfaceView 성능에 영향을 미치는 배터리 절약 기능이 있다고 생각하니? 여기서 무슨 일이 일어나고 있으며 어떻게 비활성화 할 수 있습니까? 이것은 매우 미치겠습니다. ...
호기심 (첫 번째 코드 블록)에서 첫 번째 게임 루프를 테스트하고 화면을 두드려서 모든 것이 원활하게 실행되었습니다. 사람 ... 아무 것도 복잡성을 더하는 모든 일. 좋은 학습 경험이라고 생각합니다. 내 SurfaceView를 최대 속도로 작동시키는 방법에 대한 아이디어? 도움말 크게 감사드립니다.
:
여기서는 연구 노력이 부족하지 않습니다. p +1 – keyser