谈谈对游戏速度和游戏输入的控制

    游戏的速度控制和对键盘输入的处理是游戏的关键环节,许多人都不知道如何去做,我在这里谈谈我对方面的一些心得和看法。

    有许多人都采用delay函数和清键盘缓冲来处理游戏速度和游戏输入,实际上是一个误区。

    游戏编程中,一般都不使用延迟函数等来控制游戏的速度,这种方法是最愚蠢的,因为延迟函数实际上就是无谓的占用CPU,是对CPU资源的一种浪费,如果能将CPU的延迟时间解放出来,而采用另外一种机制去控制游戏速度,那么游戏对CPU资源的利用率就会比较高了,这样游戏对各种事件的响应速度也就会更快了:

    看如下的代码:

main()
{
    int key;

    while(1)
        {
        while(!kbhit())
            {
            //没有键盘输入的游戏循环代码
            //以下用一个延迟函数来控制游戏速度
            delay(10000);
            }

        key=getch();

        //一下是处理键盘输入的代码
        switch(key)
            {
            case 'a':
                break;
            case 'b':
                break;
            default :
                break;
            }
        }
}

    上面的代码是我早期使用过的一个游戏循环代码,使用这个代码可以实现游戏循环的功能,并且可以响应键盘输入。但是这是一种极为愚蠢的办法,其最大的缺点在于对游戏速度的控制上面。在内层的while循环中,如果没有键按下,则程序始终在这个while循环中执行,由于为了控制游戏速度,在这个while循环中加了delay函数,做延迟。如果延迟的时间是0.5秒,那么整个while循环的执行时间至少是0.5秒。如果程序由于没有键盘输入而进入了这个while循环,那么这个时候,无论你怎么敲击键盘,在while循环里的代码执行完以前,都不会有响应,这样你的键盘输入就被存入了键盘缓冲区里面去了。当while里的代码执行完后,已经过了0.5秒,这时候程序又回到while(!kbhit())一句执行,如果这时候你按下了键盘,程序才会跳到key=getch()一句去执行。如果while(!kbhit())一句的执行时间是0.0001秒的话(实际上比这个还短),那么整个可以响应输入的可能性就只有0.0001/(0.5+0.0001),这是相当小的几率。所以大多数的按键都没能被及时处理,而被送入了键盘缓冲区里。所以会出现游戏的响应跟不上的问题。许多人认为需要清键盘缓冲,这实际上是一个误区。问题的根本不在于键盘缓冲区,而在于程序的结构本来就有问题。这种程序结构的效率是相当低下的.

    通常的延迟函数都是如下的一个循环:

void delay(long time)
{
    while(--time!=0)
        {
        }
}

    这样的延迟,实际上就是在不停的循环,在游戏中用这样的延迟函数简直就是浪费宝贵的CPU资源。如果你的一个游戏循环的代码只执行0.005秒,但是这样的速度对玩家来说必然太快,你为了把游戏循环的速度稳定到0.5秒一次而使用了delay函数来控制游戏速度,这样大部分的CPU资源实际上是分给了delay函数,delay函数占据了大量的CPU时间,而只有极少的时间被用到了你的游戏循环代码上,来完成对游戏数据的计算和对输入事件的响应。这样的结果必然导致游戏各方面的性能都受到严重的影响,特别是对按键输入的响应。这是任何一个有水平的游戏编程者都不能容忍的。即便你采用了清键盘缓冲技术,这个问题依然无法解决,因为这个是程序结构上的缺陷,除了修改程序的结构,没有别的办法。可以看到,就算清了键盘缓冲,依然会响应不及时,只是避免了延迟响应,就是对以前的按键响应。不信,大家可以试试看。

    因此最根本的办法是改变程序的结构,有人提出了用键盘中断和时钟中断,这确实是一个不错的解决方案。但是实际上一点必要都没有,修改键盘中断的做法我不是很喜欢,一是麻烦,二是不安全,改时钟中断更是如此。以下是我的一个解决方案,效果一点不比改键盘中断差:

main()
{
    int timer;    //时钟周期
    int cur_time; //时钟计数器

    //以下初始化时钟
    timer=10000;
    cur_time=timer;

    while(1)
        {
        while(!kbhit())
            {
            //以下的代码对时钟进行计数
            if(cur_time==0)
                {
                cur_time=timer;
                }
            else{
                cur_time--;
                }

            //如果计数到1,则执行游戏循环
            if(cur_time==0)
                {
                //游戏循环代码
                }
            }

        key=getch();

        //一下是处理键盘输入的代码
        switch(key)
            {
            case 'a':
                break;
            case 'b':
                break;
            default :
                break;
            }
        }
}

    程序结构基本上和前一个程序一样,只是在控制游戏的速度上面,不再采用delay函数了,而是使用了一个时钟来实现。这个时钟有一个周期,就是timer变量的值,还有一个计数器,就是cur_time变量,学过8054定时器的人对此应该不会陌生。每次经历一个while循环,计数器的值就会减一,直到减为零,又回到新的计时起点。

    在这个新的结构中,如果cur_time不等于一,则while(!kbhit())循环中执行的仅仅是
            if(cur_time==0)
                {
                cur_time=timer;
                }
            else{
                cur_time--;
                }
这样一段短小的代码,所使用的时间是相当短的,这样就有更多的时间去检测键盘输入(程序执行到while(!kbhit())就是检测键盘输入),检测到输入后,立即转入switch语句进行处理。而由于计时器的引入,游戏的速度也得到了很好的控制,while(!kbhit())循环要每循环timer次,才会执行“//游戏循环代码”一次,这样通过修改timer的值就可以方便的控制游戏的速度。

    没有了delay函数带来的资源浪费,while(!kbhit())循环执行的时间相当的短,所以检测到玩家键盘输入的几率也相对的变大,所以响应的速度是相当快、相当理想了,根本就没有一点点延迟的感觉。

    为了精确的控制游戏的速度,还可以将这种方法结合修改时钟中断一起使用。其具体原理是,由时钟中断程序负责对时钟进行计数,而在while循环中就只负责判断计数是否到了1,如果到了1,就执行游戏循环,执行完后将计数值置为0;如果计数值没有到1就什么也不做了。

    通过时钟中断的精确计数,你的程序的速度控制就可精确无比了。在实际中通常就是采用的这种结合时钟中断的游戏控制方法,大家可以仔细想想,基本原理就是我上面说的那么多,动动脑筋就可以想出来的。

    这一办法已经在我做的一个游戏中得到验证,所以大家不必怀疑以上说法的正确性。由于这个游戏目前还没有完成,所以就不发布出来献丑了,如果真的想要看看的话可以发Email给我联系。

    以上就是我的处理办法,如果大家在游戏速度控制和键盘输入控制方面遇到了麻烦,不妨参考一下我的办法。以上办法也是参考了Crazy Bug的一些游戏代码总结出来的。当然如果你有更好的办法,也不妨写成文章在论坛上发表出来,和大家分享分享,不要太自私哦。


                              作者:RockCarry工作室 陈凯
                              20053.23
                              版权所有,请勿转载

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值