Scheduler負責以固定的頻率執行每一幀,所需的時鐘由Clock提供,Scheduler還可以計算每幀所需時間和CPU占用率,以便可能的話動態調整任務。
以下的Scheduler的實現參考自Marshall "Game Programming Gems 3"中的C++代碼:
package game.engine.core;
public class 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()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);
}
}
我們還沒有真正的任務要執行,所以只好用兩個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%時,游戲才會變慢。