帮助:使用setInterval()以可变速度播放MovieClip

时间:2011-03-10 19:56:25

标签: flash actionscript-3

我正在尝试使用setInterval逐帧播放MovieClip。总的来说,我试图通过改变setInterval时间来模仿加速和减慢MovieClip的速度。

基本上,当用户移动Slider时,MovieClip需要根据Slider值加速或减速。

编辑:上面的代码在一定程度上起作用。如滑块更新updateClip()和MovieClip确实以一种速度播放。但是MovieClip不会以速度变量值播放。如果我删除ClearInterval(),MovieClip只能以一种速度播放,但是当Slider改变时,它会加倍。我正在寻找的是MovieClip以与速度值相同的速度播放。

抱歉,如果我没有意义。我不是一个Flash家伙。


编辑:最终版本更新(感谢大家的帮助)

// Import classes
import fl.controls.Slider;
import fl.controls.SliderDirection;
import fl.events.SliderEvent;
import flash.utils.Timer;
import flash.events.TimerEvent;

// Set variables and types
var slow:Number=0;
var speed:Number=0;
var update:Number=0;
var frame:Number=0;
var timer:Timer=null;

// Add event listener to slider
hand_control.addEventListener(SliderEvent.CHANGE, updateClip);

function updateClip(e:SliderEvent):void {

    // Set frame to slider value
    frame=e.target.value;

    // Update hanle movie clip
    handle_motion_small_mc.gotoAndStop(frame);
    handle_motion_large_mc.gotoAndStop(frame);

    // Set timer if not set
    if (timer==null) {
        setTimer();
        trace('Timer is null');
    }

    // Invert slider value
    update=70-frame;

    // Output values for debugging
    trace('Actual Speed: ' + update);
    trace('Chosen Speed: ' + frame);

}

// Set and start timer
function setTimer() {
    timer=new Timer(update,1);
    timer.addEventListener(TimerEvent.TIMER_COMPLETE, updateGrass);
    timer.start();
}

// Update grass movie speed
function updateGrass( ev:TimerEvent ) {
    var current:Number=grass_mc.currentFrame+1;
    grass_mc.gotoAndStop(current);
    setTimer();
}

4 个答案:

答案 0 :(得分:1)

使用ActionScript 3时,应使用Timer类而不是setInterval。

// add imports

import flash.utils.Timer;
import flash.events.TimerEvent;

//  add to variable declarations

var timer : Timer = null;

//  this goes instead of clearInterval and setInterval, after you've set "speed"

if (timer == null) setTimer();

//  and here is the function

function setTimer() 
{
    timer = new Timer (speed, 1);
    timer.addListener (TimerEvent.TIMER_COMPLETE, updateGrass);
    timer.start();
}
//  and the updateGrass method

function updateGrass( ev:TimerEvent ) 
{
    if (grass_mc.currentFrame>249) grass_mc.gotoAndStop(1);
    else grass_mc.nextFrame();
    setTimer();
}

答案 1 :(得分:1)

只要它有效,它就没问题了。 我确实有一些可能会有所帮助的建议:

  1. 您可能希望使用Timer而不是setInterval,因为它为您提供了一些方便的额外选项。
  2. 尝试远离复制和粘贴代码,请按照DRY
  3. 让我们把它分解成它的部分:   - 原始帧速率(每秒帧数比率)   - 任意影片剪辑( n 帧)   - 更新播放的变量

    这个想法很简单,您必须根据变量更新影片剪辑的当前帧。您可以使用该变量来控制更新频率(您的间隔),或 控制一个跟踪动态帧的变量。

    以下是关于如何控制时间/间隔的示例:

    var metro:Number = 1000/stage.frameRate;//'metronome' - convert fps to millis
    slider.addEventListener(Event.CHANGE, sliderUpdate);//slider values must be > 0 (e.g. 0.01)
    var updater:Timer = new Timer(metro);
    updater.addEventListener(TimerEvent.TIMER, frameUpdate);
    updater.start();
    
    function frameUpdate(event:TimerEvent):void {
        clip.gotoAndStop(updater.currentCount%clip.totalFrames);//loop at total frames (a frame variable + if(frame > totalFrame) might be faster
    }
    function sliderUpdate(event:Event):void{
        updater.delay = metro / slider.value;
    }
    

    因此,影片剪辑不会一直更新,您可以使用滑块更新的变量来控制它。请注意,帧速率从“帧测量单位”转换为毫秒。

    这是一个修改版本,它考虑了滑块的负值和零值:

    var metro:Number = 1000/stage.frameRate;
    slider.addEventListener(Event.CHANGE, sliderUpdate);
    var updater:Timer = new Timer(metro);
    updater.addEventListener(TimerEvent.TIMER, frameUpdate);
    updater.start();
    
    function frameUpdate(event:TimerEvent):void {//if it's negative value - go backwards/subtract from total
        clip.gotoAndStop(slider.value < 0 ? (clip.totalFrames-updater.currentCount%clip.totalFrames) : updater.currentCount%clip.totalFrames);
    }
    function sliderUpdate(event:Event):void{//watchout for 0 value
        updater.delay = metro / Math.abs(slider.value == 0 ? 0.001 : slider.value);
    }
    

    使用这种方法,您可以独立于您可能拥有的任何其他enterframe循环更新剪辑。

    以下是基于框架而非时间更新方式的粗略示例:

    var frame:Number = 0,roundFrame:Number;
    this.addEventListener(Event.ENTER_FRAME, frameUpdate);
    function frameUpdate(event:Event):void {
        frame += slider.value;
        roundFrame = Math.floor(Math.abs(frame))%clip.totalFrames;
        if(slider.value > 0) clip.gotoAndStop(roundFrame);  
        else                 clip.gotoAndStop(clip.totalFrames-roundFrame);
    }
    

    HTH

答案 2 :(得分:0)

对于小于几百毫秒的时间间隔,定时器是个糟糕的主意。我会使用ENTER_FRAME事件和getTimer获取当前时间(以毫秒为单位),然后使用stop()nextFrame()手动控制剪辑。

答案 3 :(得分:0)

我同意alxx - 使用Timer似乎很优雅,但我认为ENTER_FRAME方法更好,特别是如果你想要比SWF的帧速率更快地运行你的MovieClip。我写了一篇关于我是如何做到的博客文章:http://www.eqsim.com/blog/?p=329