代码之家  ›  专栏  ›  技术社区  ›  jorelli

AS3:getTimer()方法和timer类有多精确?

  •  3
  • jorelli  · 技术社区  · 15 年前

    我正在制作一个游戏(shmup),我开始质疑ActionScript中计时器的准确性。当然,当你想以几秒或分秒的顺序计算时间时,它们是足够精确的,但是当你达到更精细的范围时,它的性能似乎相当差。这使得做像宇宙飞船每秒发射100个激光这样的事情相当困难。

    在下面的示例中,我测试了1000个计时器滴答之间的间隔时间(平均)为30毫秒。一次又一次,结果是~35-36毫秒。减少时间,我发现计时器延迟的下限是~16-17毫秒。这给了我~60的最大fps,这在视觉上很好,但也意味着我不可能发射超过60次。每秒激光器:-(.我在100和1000个循环中运行了几次这个测试,但是对于30毫秒测试和1毫秒测试,结果没有改变。我在末尾打印到一个文本字段,因为使用trace()并在调试模式下启动swf似乎会对测试产生负面影响。所以我想知道的是:

    • 这个测试是对计时器类性能的一个很好的度量,还是我的结果有问题?
    • 这些结果会在其他机器上发生显著变化吗?

    我知道这取决于getTimer()方法的精度,但是我在这个主题上找到的讨论通常集中在getTimer()在更大的间隔上的精度上。

    package 
    {
    import flash.display.Sprite; import flash.events.TimerEvent; import flash.text.TextField; import flash.utils.getTimer; import flash.utils.Timer;
    public class testTimerClass extends Sprite
    {
        private var testTimer:Timer = new Timer(30, 1000);
        private var testTimes:Array = new Array();
        private var testSum:int = 0;
        private var testAvg:Number;
        private var lastTime:int;
        private var thisTime:int;
    
        public function testTimerClass()
        {
            testTimer.addEventListener(TimerEvent.TIMER, step);
            testTimer.addEventListener(TimerEvent.TIMER_COMPLETE, printResults);
            lastTime = getTimer();
            testTimer.start();
        }
    
        private function step(event:TimerEvent):void
        {
            thisTime = getTimer();
            testTimes.push(thisTime - lastTime);
            lastTime = thisTime;
        }
    
        private function printResults(event:TimerEvent):void
        {
            while (testTimes.length > 0)
            {
                testSum += testTimes.pop();
            }
            testAvg = testSum / Number(testTimer.repeatCount);              
            var txtTestResults:TextField = new TextField();
            txtTestResults.text = testAvg.toString();
            this.addChild(txtTestResults);  
        }       
    }
    

    }

    我想最好的方法是在同一帧中用不同的位置画出多个激光器,避免有多个定时器对象。

    编辑:我使用stage.framerate更改渲染帧速率,并在几个帧速率上运行测试,但没有更改。

    5 回复  |  直到 15 年前
        1
  •  4
  •   Luke    15 年前

    Tinic Uro(Flash播放器工程师)已经编写了 interesting blog 关于这个问题的帖子。

        2
  •  2
  •   Jacob Poul Richardt    15 年前

    在使用timer类的过程中,我将把更新代码放入并输入frame eventliewer。

    然后使用getTimer(),找出自上次更新以来经过的时间,然后使用一点数学计算移动、激光“产卵”等。这样,无论您获得60fps或10fps,游戏都应该执行相同的操作。

    这也可以防止奇怪的游戏行为,如果FPS暂时下降,或如果游戏运行在一个缓慢的机器上。

    在大多数情况下,数学是相当简单的,如果不是,你通常可以“抄近路”,仍然可以得到一个足够好的结果,一场比赛。 对于简单移动,您可以简单地将移动偏移量乘以自上次更新以来的时间。对于加速度,你需要一个二次方程,但可以简化为再乘以。

    针对以下Jorelli评论:

    更好的代码可以解决碰撞检测问题,不仅可以检查当前状态,还可以检查前一状态和当前状态之间发生的情况。 我从来没有遇到过键盘问题。也许你应该试试这个漂亮的小班: http://www.bigroom.co.uk/blog/polling-the-keyboard-in-actionscript-3

        3
  •  1
  •   fenomas    15 年前

    我刚刚尝试运行您的示例代码,除了作为一个框架脚本之外,其他代码都是一样的,我所坐的计时器的工作方式和您所期望的完全一样。用一个30毫秒的计时器,平均值约为33-34,用一个3毫秒的计时器,平均值约为3.4或3.5。有了一个1毫秒的计时器,我可以在1000多次试验中获得1.4到1.6。它在闪存和浏览器中都是这样工作的。

    因此,关于准确性,请参见《卢克答案》中天宁公司的博客帖子。但是对于频率的上限,如果你的事件间隔不超过16毫秒,只有你发布的示例代码,那么可能是一些奇怪的事情,或者可能是你的浏览器给出闪光计时信息的速度的上限。如果您在实际的游戏中得到这些结果,我认为您只需要使用同步代码来阻止计时器事件。

    还有一件事-我知道这不是你所要求的,但是用一个输入帧处理程序处理游戏逻辑会更明智。不管产生激光的代码是每30毫秒运行一次还是每3毫秒运行一次,屏幕每帧只重绘一次(除非你强迫它更频繁地更新,这可能是你不应该的)。因此,屏幕刷新之间发生的任何事情都只是开销,会降低整体帧速率,因为只要稍微聪明一点,就可以获得与更频繁执行的计时器完全相同的结果。例如,您可以每隔30毫秒生成10个激光器,而不是每隔3毫秒生成一个激光器,并沿其飞行路径移动每个激光器一定距离,就好像它是3、6或9毫秒前创建的一样。

    另一种让你的逻辑脱离框架事件的自然方法是制作一个“理论上”每T毫秒运行一次的游戏循环。然后,在你的 ENTER_FRAME 处理程序,只需迭代该循环f/t次,其中f是自上一个帧事件以来经过的毫秒数。因此,如果你想让游戏理论上每5毫秒更新一次,而你想让屏幕以30帧的速度更新,你只需以30帧的速度发布,并在 肠衣架 处理程序,你会连续5-7次调用你的主游戏循环,这取决于从上一帧到现在已经有多长时间了。在屏幕上,这将给您提供与使用5毫秒计时器事件相同的结果,并且它将免除大部分开销。

        4
  •  1
  •   Tim Kerchmar    13 年前

    BitmapData.Scroll和BitmapData.CopyPixels是当前在Flash中呈现的最快方式,尽管在一些系统中,使用带有GPU加速的movieclips速度稍快。在OpenGL中,每一个四边形都被渲染为一个单独的纹理,因此它不是普通GPU加速应用程序所期望的。我知道,因为我在我的游戏中对这两种方式都进行了描述。您可以做的一件事是从输入事件处理程序调用游戏更新来提高响应时间。这样,即使在游戏的帧速率较低的情况下,您也能听到正确的定时声音,应用程序也会感觉到更灵敏的响应。

        5
  •  0
  •   Ryan Guill    15 年前

    这给了我60秒的最大fps,这在视觉上很好,但也意味着我不可能每秒发射超过60个激光器:-(

    我想说,你很幸运能得到这样的fps,而且你的大多数用户(假设你的用户是互联网上的广大用户)将很可能无法达到这种帧速率。

    我同意,flash播放器的能力可能不足以满足你想要达到的目标。