关于游戏中主循环结构与定时的问题。
这是一段J2ME的游戏定时器与调度器的代码,可能很多人见过的。只是在下看的不是很明白,思路理不清楚。所以上来问问。
package game.engine.core;
public class Clock {
// Clock是否运行:
private boolean running;
// 当前hardware clock:
private int thisTime;
// record the last hardware clock when calling stop():
private int lastTime;
// systemTime从0开始递增,和硬件时钟同步:
private int systemTime;
// systemOffset就是硬件时钟和systemTime的差:
private int systemOffset;
// 上一次停止的systemTime:
private int pauseAt;
// virtualTime starts from 0.
private int virtualTime;
// virtualOffset records how long the clock paused:
private int virtualOffset;
private int frameStart;
private int frameEnd;
private int frameCount;
/** Creates a new instance of clock */
public Clock() {
reset();
}
public void reset() {
running = false;
// get the hardware clock:
thisTime = (int)System.currentTimeMillis();
lastTime = thisTime;
// and systemTime starts from 0:
systemTime = 0;
systemOffset = thisTime;
pauseAt = 0;
// init virtual time:
virtualTime = 0;
virtualOffset = 0;
// init frame time:
frameStart = 0;
frameEnd = 0;
frameCount = 0;
}
// 同步hardware clock:
private void update() {
lastTime = thisTime;
thisTime = (int)System.currentTimeMillis();
// increase the systemTime:
systemTime += (thisTime - lastTime);
}
// 启动Clock:
public void start() {
if(!running) {
running = true;
update();
virtualOffset += (systemTime - pauseAt);
System.out.println("[start]");
}
}
// 停止Clock:
public void stop() {
if(running) {
running = false;
update();
pauseAt = systemTime;
System.out.println("[stop] at " + pauseAt);
}
}
// Clock是否运行:
public boolean isRunning() {
return this.running;
}
// 开始Frame:
public void beginFrame() {
if(running) {
update();
frameCount++;
frameStart = frameEnd;
frameEnd = systemTime - virtualOffset;
virtualTime = frameStart;
System.out.println("[beginFrame] virtual time = " + virtualTime + ", systemTime = " + systemTime);
}
}
// 将virtual time提前到Frame结束:
public void advanceToEnd() {
if(running) {
virtualTime = frameEnd;
System.out.println("[advanceToEnd] virtual time = " + virtualTime);
}
}
public int getVirtualTime() {
return virtualTime;
}
// 获取系统时间:
public int getSystemTime() {
update();
return systemTime;
}
// 获取Frame开始时间:
public int getFrameStart() {
return frameStart;
}
// 获取Frame结束时间:
public int getFrameEnd() {
return frameEnd;
}
public int getFrameCount() {
return frameCount;
}
}
package game.engine.core;
import game.engine.core.*;
public class Scheduler {
public static void main(String[] args) {
Scheduler scheduler = new Scheduler();
scheduler.start();
int time = 1000;
do {
scheduler.waitUntil(time);
time += 1000;
scheduler.executeFrame();
} while(scheduler.getSystemTime()<10000);
}
/** Creates a new instance of Scheduler */
public Scheduler() {
}
// clock:
private Clock clock = new Clock();
// 启动Scheduler:
public void start() {
clock.start();
}
// 停止Scheduler:
public void stop() {
clock.stop();
}
public int getSystemTime() {
return clock.getSystemTime();
}
public int getVirtualTime() {
return clock.getVirtualTime();
}
// 执行完整的一帧:
public void executeFrame() {
System.out.println("-- start execute frame --");
clock.beginFrame();
int started = clock.getSystemTime();
// do time task:
System.out.println("doing time tasks...");
try {
Thread.sleep(500);
}catch(InterruptedException ie) {}
clock.advanceToEnd();
// do frame task:
System.out.println("doing frame tasks...");
try {
Thread.sleep(200);
}catch(InterruptedException ie) {}
// do render task:
int end = clock.getSystemTime();
int elapsed = end - started;
int frameLength = clock.getFrameEnd() - clock.getFrameStart();
System.out.println("elapsed: " + elapsed + ", frame: " + frameLength);
System.out.println("cpu usage: " + (elapsed * 100 / frameLength) + "%");
// cleanup:
System.out.println("-- end execute frame --\n");
}
public void waitUntil(int time) {
try {
while(clock.getSystemTime()<time)
Thread.sleep(1);
}
catch(InterruptedException ie) {}
}
}
我们还没有真正的任务要执行,所以只好用两个Thread.sleep()来表示执行任务,分别是500ms和200ms,在main()方法中每1s执行一次executeFrame()方法,可以看到如下输出:
-- start execute frame --
[beginFrame] virtual time = 0, systemTime = 1002
doing time tasks...
[advanceToEnd] virtual time = 992
doing frame tasks...
elapsed: 701, frame: 992
cpu usage: 70%
-- end execute frame --
-- start execute frame --
[beginFrame] virtual time = 992, systemTime = 2003
doing time tasks...
[advanceToEnd] virtual time = 1993
doing frame tasks...
elapsed: 701, frame: 1001
cpu usage: 70%
-- end execute frame --
...
CPU使用率是70%,如果把任务时间延长大于1s,比如700ms和500ms,虚拟时间就变慢,因为CPU不能在1s内处理完任务,输出的CPU使用率100%(除了第一次计算):
-- start execute frame --
[beginFrame] virtual time = 0, systemTime = 1002
doing time tasks...
[advanceToEnd] virtual time = 992
doing frame tasks...
elapsed: 1201, frame: 992
cpu usage: 121%
-- end execute frame --
-- start execute frame --
[beginFrame] virtual time = 992, systemTime = 2203
doing time tasks...
[advanceToEnd] virtual time = 2193
doing frame tasks...
elapsed: 1202, frame: 1201
cpu usage: 100%
-- end execute frame --
-- start execute frame --
[beginFrame] virtual time = 2193, systemTime = 3415
doing time tasks...
[advanceToEnd] virtual time = 3405
doing frame tasks...
elapsed: 1202, frame: 1212
cpu usage: 99%
-- end execute frame --
...
有一些微小的误差,因为调度器自身的代码也会占用一点时间,并且currentTimeMillies()只能精确到毫秒级,不过用户是感觉不出来的,只有当CPU使用达100%时,游戏才会变慢
。