blob: 7ee47dd093945ded2f698957d662d765e08edc58 [file] [log] [blame]
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.replica.replicaisland;
import android.os.SystemClock;
import android.view.KeyEvent;
/**
* The GameThread contains the main loop for the game engine logic. It invokes the game graph,
* manages synchronization of input events, and handles the draw queue swap with the rendering
* thread.
*/
public class GameThread implements Runnable {
private long mLastTime;
private ObjectManager mGameRoot;
private GameRenderer mRenderer;
private Object mPauseLock;
private boolean mFinished;
private boolean mPaused = false;
private int mProfileFrames;
private long mProfileTime;
private static final float PROFILE_REPORT_DELAY = 3.0f;
public GameThread(GameRenderer renderer) {
mLastTime = SystemClock.uptimeMillis();
mRenderer = renderer;
mPauseLock = new Object();
mFinished = false;
mPaused = false;
}
public void run() {
mLastTime = SystemClock.uptimeMillis();
mFinished = false;
while (!mFinished) {
if (mGameRoot != null) {
mRenderer.waitDrawingComplete();
final long time = SystemClock.uptimeMillis();
final long timeDelta = time - mLastTime;
long finalDelta = timeDelta;
if (timeDelta > 12) {
float secondsDelta = (time - mLastTime) * 0.001f;
if (secondsDelta > 0.1f) {
secondsDelta = 0.1f;
}
mLastTime = time;
mGameRoot.update(secondsDelta, null);
CameraSystem camera = mGameRoot.sSystemRegistry.cameraSystem;
float x = 0.0f;
float y = 0.0f;
if (camera != null) {
x = camera.getFocusPositionX();
y = camera.getFocusPositionY();
}
BaseObject.sSystemRegistry.renderSystem.swap(mRenderer, x, y);
final long endTime = SystemClock.uptimeMillis();
finalDelta = endTime - time;
mProfileTime += finalDelta;
mProfileFrames++;
if (mProfileTime > PROFILE_REPORT_DELAY * 1000) {
final long averageFrameTime = mProfileTime / mProfileFrames;
DebugLog.d("Game Profile", "Average: " + averageFrameTime);
mGameRoot.sSystemRegistry.hudSystem.setFPS((int)(1000 * mProfileFrames / mProfileTime));
mProfileTime = 0;
mProfileFrames = 0;
}
}
// If the game logic completed in less than 16ms, that means it's running
// faster than 60fps, which is our target frame rate. In that case we should
// yield to the rendering thread, at least for the remaining frame.
if (finalDelta < 16) {
try {
Thread.sleep(16 - finalDelta);
} catch (InterruptedException e) {
// Interruptions here are no big deal.
}
}
synchronized(mPauseLock) {
if (mPaused) {
SoundSystem sound = BaseObject.sSystemRegistry.soundSystem;
if (sound != null) {
sound.pauseAll();
BaseObject.sSystemRegistry.inputSystem.releaseAllKeys();
}
while (mPaused) {
try {
mPauseLock.wait();
} catch (InterruptedException e) {
// No big deal if this wait is interrupted.
}
}
}
}
}
}
// Make sure our dependence on the render system is cleaned up.
BaseObject.sSystemRegistry.renderSystem.emptyQueues(mRenderer);
}
public void stopGame() {
synchronized (mPauseLock) {
mPaused = false;
mFinished = true;
mPauseLock.notifyAll();
}
}
public void pauseGame() {
synchronized (mPauseLock) {
mPaused = true;
}
}
public void resumeGame() {
synchronized (mPauseLock) {
mPaused = false;
mPauseLock.notifyAll();
}
}
public boolean getPaused() {
return mPaused;
}
public void setGameRoot(ObjectManager gameRoot) {
mGameRoot = gameRoot;
}
}