动作脚本3中的定时器延迟问题

时间:2011-07-06 21:59:51

标签: flash actionscript-3 timer flash-cs5

我正在使用动作脚本3进行汽车Flash游戏,如果我按下键盘上的“向上”,我希望道路线路更快,线路由定时器创建,其延迟由按下的键修改问题是,如果我按下按键,事件的计时器仍会刷新,并且在我停止按下之前它没有显示任何道路线。

这是关键的新闻代码:

if (upPressed)
{
    speed = speed*1.02;
    timerB.delay = timerB.delay/1.007;
    timerA.delay = timerA.delay/1.005;
}

任何提示?提前谢谢。

3 个答案:

答案 0 :(得分:0)

问题可能是每次更改延迟属性时Timer类重新启动的结果。

来自Adobe docs:

  

如果在定时器运行时设置延迟间隔,则定时器将以相同的repeatCount迭代重新启动。

http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/utils/Timer.html#delay

这基本上意味着计时器从0重新开始,但记住它重复了多少次。我意识到我的答案很长,所以我在底部提了一些参考。

解决方案:使用flash.utils.getTimer()而不是Timer对象。

http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/flash/utils/package.html#getTimer()

getTimer()函数返回一个整数,表示自.swf文件启动以来经过的毫秒数。如果每帧都检查此编号,则可以看到自上一帧以来经过了多长时间。只需添加每帧通过的毫秒数,直到该数字达到阈值,然后调用线条绘制功能并重置计数器。

当检查是否按下该键时,减少新的'myDelay'变量而不是Timer.delay属性。

    var ms:int;
    var timeStamp:int = flash.utils.getTimer();
    var myDelay:Number;    

    onEnterFrame() {

          // Track how much time has passed since the last frame
          ms += flash.utils.getTimer() - timeStamp;

          if (ms > myDelay)
          {
               // DRAW THE ROAD LINES
               drawLines();
               // RESET THE COUNTER 
               ms = 0;
          }

          //other stuff  

          // Record the timestamp of this frame so you can see the difference next frame
          timeStamp = flash.utils.getTimer();                 
    }

定时器重置的说明:

注意:我假设您每秒都要检查按键。如果你每帧都改变定时器的延迟属性(例如每秒24次)并且你的定时器发生的频率低于每秒​​24次,那么它将在它有机会发出一个事件来调用它的处理程序之前被重置。创建线条的功能。

如果你看一下下面的例子,启动和停止事件是防止它被重置的唯一方法,但即便这样,只有当延迟比两次之间的时间短时,才会调用定时器事件处理函数。改变了延迟。由于平均swf为24fps,这意味着在下一帧再次更改值之前,延迟需要短于41.6毫秒。

  package 
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.events.TimerEvent;
    import flash.utils.Timer;

    /**
     * ...
     * @author 
     */
    public class Main extends Sprite 
    {

        var timer:Timer;
        var keyPressed:Boolean = false;

        public function Main():void 
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }

        private function init(e:Event = null):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            timer = new Timer(50);
            timer.addEventListener(TimerEvent.TIMER, function ():void { trace (timer.delay); } );
            timer.start();

            stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown);
            stage.addEventListener(KeyboardEvent.KEY_UP, keyUp );

            addEventListener(Event.ENTER_FRAME, onEnterFrame);

        }

        function onEnterFrame (e:Event)
        {                   
            if (keyPressed)
            {
                timer.stop();
                timer.delay -= 1;
                timer.start();
            }
        }

         function keyDown (e:KeyboardEvent):void { keyPressed = true; } 


         function keyUp (e:KeyboardEvent):void { keyPressed = false; }
    }

}

答案 1 :(得分:0)

虽然Josh的回答似乎准确描述了您的错误来源,但应该注意解决问题的正确方法是完全停止使用计时器,并在EnterFrame中运行所有逻辑处理程序。

要了解为什么这是真的,请回想一下,flash播放器以给定的帧速率运行,并且每帧只重绘一次屏幕。假设您以与帧速率相同的速度运行计时器。这意味着您将在每次重绘屏幕之间获得一个Timer事件。现在假设您将计时器加速了10%。发生的一切都是,Timer事件和帧事件不同步,因此每帧可以获得一帧9帧,而在第十帧期间,Timer将触发两次。你的路线移动速度没有快10%,它以相同的速度移动9帧,而速度移动到第10帧,这与你想要的完全不同。

解决方案是,不是试图更频繁地移动道路线,而是希望每帧移动一次,但是移动它们的距离更大或更小。正确的方法是使用EnterFrame处理程序。

答案 2 :(得分:0)

EnterFrame是每次视图刷新(粗略)时由Flash运行时触发的事件。您可以向根显示对象添加事件侦听器,并触发“update()”方法。这将取代您当前在计时器中所做的事情。

您可以在游戏上下文中详细解释为什么EnterFrame比Timer更有用:

http://www.bit-101.com/blog/?p=910