使用MIDP2.0开发游戏 (7) 设计Scheduler

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()                 Thread.sleep(1);
            }
        }catch(InterruptedException ie) {}
    }

    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%时,游戏才会变慢。

待续...

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值