創建遊戲循環我跟着this excellent tutorial。但是我認爲下一個顯示FPS的教程有點不確定,所以我試着單飛。我對我製作的trackFps()
方法有信心;它在計算幀之間的時間差之後被調用,在每次運行時測量預測的FPS,將這些預測的FPS值存儲在ArrayList
中,然後每秒一次加上那些預測的FPS併除以所添加的值的數量以得到平均FPS 。如何計算我的空遊戲中的FPS?
當我通過它與它的功能精細調試器中運行,但是當我通過它運行正常,我得到以下異常:
FATAL EXCEPTION: Thread-11
java.lang.IndexOutOfBoundsException: Invalid index 26, size is 6
at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:257)
at java.util.ArrayList.get(ArrayList.java:311)
at biz.hireholly.engine.GameLoop.trackFps(GameLoop.java:120)
at biz.hireholly.engine.GameLoop.run(GameLoop.java:73)
這是很說明和發生在這條線fps += fpsStore.get(fpsTrackCount-1);
。但是我看不到fpsTrackCount
變量的變化可能高達26,它應該只與存儲在ArrayList
fpsStore
中的變量的數量一樣高。
有人會看我的GameLoop
班,特別是底部的trackFps()
方法嗎?我會提供整個事情。它有很多評論,但沒有太多的東西,對於你們中的一些人應該非常熟悉。
GameLoop
(包含在底部計算的FPS trackFps()
法):
package biz.hireholly.engine;
import android.graphics.Canvas;
import android.view.SurfaceHolder;
import java.util.ArrayList;
/**
* The GameLoop is a thread that will ensure updating and drawing is done at set intervals.
* The thread will sleep when it has updated/rendered quicker than needed to reach the desired fps.
* The loop is designed to skip drawing if the update/draw cycle is taking to long, up to a MAX_FRAME_SKIPS.
* The Canvas object is created and managed to some extent in the game loop,
* this is so that we can prevent multiple objects trying to draw to it simultaneously.
* Note that the gameloop has a reference to the gameview and vice versa.
*/
public class GameLoop extends Thread {
private static final String TAG = GameLoop.class.getSimpleName();
//desired frames per second
private final static int MAX_FPS = 30;
//maximum number of drawn frames to be skipped if drawing took too long last cycle
private final static int MAX_FRAME_SKIPS = 5;
//ideal time taken to update & draw
private final static int CYCLE_PERIOD = 1000/MAX_FPS;
private SurfaceHolder surfaceHolder;
//the gameview actually handles inputs and draws to the surface
private GameView gameview;
private boolean running;
private long beginTime = 0; // time when cycle began
private long timeDifference = 0; // time it took for the cycle to execute
private int sleepTime = 0; // milliseconds to sleep (<0 if drawing behind schedule)
private int framesSkipped = 0; // number of render frames skipped
private double lastFps = 0; //The last FPS tracked, the number displayed onscreen
private int fpsTrackCount = 1; // number we'll divide the fpsSTore by to get average
private ArrayList<Double> fpsStore = new ArrayList<Double>(); //For the previous fps values
private long lastTimeFpsCalculated = System.currentTimeMillis(); //used in trackFps
public GameLoop(SurfaceHolder holder, GameView gameview) {
super();
this.surfaceHolder = holder;
this.gameview = gameview;
}
public void setRunning(boolean running) {
this.running = running;
}
@Override
public void run(){
Canvas c;
while (running) {
c = null;
//try locking canvas, so only we can edit pixels on surface
try{
c = this.surfaceHolder.lockCanvas();
//sync so nothing else can modify while were using it
synchronized (surfaceHolder){
beginTime = System.currentTimeMillis();
framesSkipped = 0; //reset frame skips
this.gameview.update();
this.gameview.draw(c);
//calculate how long cycle took
timeDifference = System.currentTimeMillis() - beginTime;
//good time to trackFps?
trackFps();
//calculate potential sleep time
sleepTime = (int)(CYCLE_PERIOD - timeDifference);
//sleep for remaining cycle
if (sleepTime >0){
try{
Thread.sleep(sleepTime); //saves battery! :)
} catch (InterruptedException e){}
}
//if sleepTime negative then we're running behind
while (sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS){
//update without rendering to catch up
this.gameview.update();
//skip as many frame renders as needed to get back into
//positive sleepTime and continue as normal
sleepTime += CYCLE_PERIOD;
framesSkipped++;
}
}
} finally{
//finally executes regardless of exception,
//so surface is not left in an inconsistent state
if (c != null){
surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
/* Calculates the average fps every second */
private void trackFps(){
long currentTime = System.currentTimeMillis();
if(timeDifference != 0){
fpsStore.add((double)(1000/timeDifference));
}
//If a second has past since last time average was calculated,
// it's time to calculate a new average fps to display
if ((currentTime - 1000) > lastTimeFpsCalculated){
int fps = 0;
int toDivideBy = fpsTrackCount;
while ((fpsStore != null) && (fpsTrackCount > 0)){
fps += fpsStore.get(fpsTrackCount-1);
fpsTrackCount--;
}
lastFps = fps/toDivideBy;
lastTimeFpsCalculated = System.currentTimeMillis();
fpsTrackCount = 1;
fpsStore.clear();
}
else{
fpsTrackCount++;
}
}
/* So That it can be drawn in the gameview */
public String getFps() {
return String.valueOf(lastFps);
}
}
我沒有看到你的TextDrawable電話,您可以張貼在您使用它來繪製的FPS值的代碼?啊,找到它了。 – Shark 2012-07-31 11:32:31
對不起,那是在我上傳到Pastebin的GameView上,因爲我不想讓我的問題混亂。 – Holly 2012-07-31 11:51:02