我通过Surfaceview创建了游戏循环。
游戏中的动画在具有高配置的强大设备上运行得更快,在低配置设备上运行速度更慢。
所以我试着计算FPS,如果FPS很高那么应该有延迟,否则myThreadSurfaceView.onDraw(c);
没有延迟
这是我用于计算的游戏循环线程代码:
private long mLastTime;
/** Variables for the counter */
private int frameSamplesCollected = 0;
private int frameSampleTime = 0;
private int fps = 0;
@Override
public void run() {
while (myThreadRun) {
Canvas c = null;
try {
c = myThreadSurfaceHolder.lockCanvas(null);
synchronized (myThreadSurfaceHolder)
{
long now = System.currentTimeMillis();
if (mLastTime != 0) {
//Time difference between now and last time we were here
int time = (int) (now - mLastTime);
frameSampleTime += time;
frameSamplesCollected++;
//After 10 frames
if (frameSamplesCollected == 10)
{
//Update the fps variable
fps = (int) (10000 / frameSampleTime);
//Reset the sampletime + frames collected
frameSampleTime = 0;
frameSamplesCollected = 0;
}
}
mLastTime = now;
}
if(fps>25)
{
try {
myThreadSurfaceView.onDraw(c);
TimeUnit.MILLISECONDS.sleep(35);
//Thread.sleep(35);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else
{
myThreadSurfaceView.onDraw(c);
}
}
finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
myThreadSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
现在这段代码正如我想要的那样提供所需的输出有时FPS对于高配置和低配置都是相同的。设备。我想要的是游戏在高配置和低配置上运行相同。设备
那么我怎样才能实现目标呢?有没有更好的方法呢?
答案 0 :(得分:2)
首先:(回答你的问题)使用“时钟时间”调整帧速率而不是计算帧数。
帧计数总是依赖于CPU功率 - 硬件越快,它可以调用更新循环的次数越多。
因此,您希望根据执行一次循环所需的实际时间进行调整,然后根据结果调整睡眠。
最简单的方法是跟踪执行 更新代码所需的时间(例如,10毫秒)。
private static final long ourTarget_millisPerFrame = 33; // ~30 FPS
public void MyUpdate() {
long startTime = SystemClock.uptimeMillis();
// ... Do your stuff here ...
long stopTime = SystemClock.uptimeMillis();
// How much time do *we* require to do what we do (including drawing to surface, etc)?
long howLongItTakesForUsToDoOurWork = stopTime - startTime;
// So, say we took 10 millis
// ... that leaves (33 - 10 =) 23 millis of "time to spare"
// ... so that's how long we'll sleep
long timeToWait = ourTarget_millisPerFrame - howLongItTakesForUsToDoOurWork;
// But apply a minimum wait time so we don't starve the rest of the system
if ( timeToWait < 2 )
timeToWait = 2;
// Lullaby time
sleep(timeToWait);
}
第二部分:
另外......也许考虑使用Looper / Handler方法并发布延迟的“Runnable”消息来执行你的循环而不是睡眠线程。
它更灵活......你根本不需要处理线程睡眠......你可能想发布其他消息 无论如何你的线程(如暂停/恢复游戏)。
有关代码段示例,请参阅Android文档:
Looper很简单 - 它只是循环等待消息到数组,直到你调用myLooper.quit()。
要处理你的时间步更新循环调用postDelayed(myRunnable,someDelay),你在其中创建一个实现runnable的类。 或者,只需将MyUpdate方法放入类中,并在接收消息ID时调用它。 (Runnable版本效率更高)
class MyUpdateThread extends Thread {
public static final int MSGID_RUN_UPDATE = 1;
public static final int MSGID_QUIT_RUNNING = 2;
public MyMessageHandler mHandler;
private MyUpdateRunnable myRunnable = new MyUpdateRunnable();
private boolean mKeepRunning;
// The *thread's* run method
public run() {
// Setup the Looper
Looper.prepare();
// Create the message handler
// .. handler is auto-magically attached to this thread
mHandler = new MyMessageHandler();
// Prime the message queue with the first RUN_UPDATE message
this.mKeepRunning = true;
mHandler.post(myRunnable);
// Start the Looper
Looper.loop();
} // end run fun (of MyThread class)
class MyMessageHandler extends Handler {
@Override
public void handleMessage(final Message msg) {
try {
// process incoming messages here
switch (msg.what) {
case MSGID_RUN_UPDATE:
// (optional)
// ... could call MyUpdate() from here instead of making it a runnable (do either/or but not both)
break;
case MSGID_QUIT_RUNNING:
mKeepRunning = false; // flag so MyRunnable doesn't repost
Looper.myLooper().quit();
break;
}
} catch ( Exception ex ) {}
}
class MyUpdateRunnable implements Runnable {
public void run() {
try {
// ---- Your Update Processing ----
// -- (same as above ... without the sleep() call) --
// Instead of sleep() ... we post a message to "ourself" to run again in the future
mHandler.postDelayed ( this, timeToWait );
} catch ( Exception ex ) {}
} // end run fun (my runnable)
} // end class (my runnable)
}
以下文章是一个更精细的解决方案,试图弥补偶尔的“这一个时间步长”。它适用于Flash动作脚本,但很容易应用于您的Android应用程序。 (它有点先进,但它有助于平滑帧速率打嗝)
答案 1 :(得分:0)
我在教程中看过这个,在每一帧之后尝试sleep(),或类似的东西,这将允许手机上的其他进程工作,它应该让你的游戏运行速度与硬件无关,抱歉我不能给你一个更好的答案,但尝试表面视图教程