萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 軟體知識 >  >> 影像處理 >> Flash 教學

Flash 動態播放速度控制:基於滑鼠距離的幀率倍數實時調節算法

前言:打破固定幀率,讓動畫「聽話」

Flash 默認固定幀率 (fps) 全局生效,無法單獨控制某個 MovieClip 的播放速度。本文實現一套**針對單一 MovieClip、基於滑鼠距離動態調整播放幀率倍數**的系統,核心思路:**在 onEnterFrame 中按倍數跳幀**,將「空間距離」映射為「時間流速」。

核心算法雙函數架構

1. 幀跳躍執行器 playRateCtr

function playRateCtr(movie:MovieClip, rate:Number):Void {
    // 參數防禦
    if (rate == undefined) rate = 1;
    if (movie == undefined) movie = this;

    var cFrame:Number = movie._currentframe;
    var nFrame:Number = cFrame + rate; // 核心:當前幀 + 倍數 = 目標幀
    movie.gotoAndPlay(nFrame);
}

原理: gotoAndPlay(nFrame) 直接跳轉到目標幀並繼續播放。
• rate=1:正常播放 (每幀前進 1)。
• rate=3:三倍速 (每幀跳過 2 幀,實際播放幀率 3×)。
• rate=0.5:半速 (需配合邏輯處理小數幀,或改用 setInterval 控制)。
• rate<0:倒放。

2. 距離映射倍數函數 DtoRate

function DtoRate(movie:MovieClip, rate_max:Number, tran:Number):Number {
    if (movie == undefined) movie = this;
    if (rate_max == undefined) rate_max = 3;
    if (tran == undefined) tran = 50;

    var dx:Number = movie._xmouse; // 滑鼠相對 movie 中心的 x 距離
    var dy:Number = movie._ymouse; // y 距離
    var dist:Number = Math.sqrt(dx*dx + dy*dy); // 歐氏距離
    var dr:Number = Math.min(rate_max, Math.floor(dist / tran)); // 距離轉倍數,封頂
    return (rate_max - dr + 1); // 距離越近 → dr 越小 → 返回值越大 → 播放越快
}

映射邏輯:
• 滑鼠在 MovieClip 中心 (dist=0) → dr=0 → 返回 rate_max + 1 (最快)。
• 滑鼠遠離 → dr 增大 → 返回值遞減。
• dist >= rate_max * tran → dr = rate_max → 返回 1 (正常速度)。
• tran 為「距離單位」,控制衰減曲線陡峭度。

完整整合:滑鼠控制箭頭旋轉速度

// 假設箭頭動畫 MC 實例名 logo_part_1,共 192 幀
logo_part_1.onEnterFrame = function() {
    var rate:Number = _root.DtoRate(this, 15, 35); // 最大15倍速,距離單位35像素
    _root.playRateCtr(this, rate);
};

效果: 滑鼠靠近箭頭中心 → 箭頭狂轉 (最高 15×);滑鼠遠離 → 緩緩轉動 (1×);滑鼠移出區域 → 恢復正常。極具互動趣味性。

進階優化與擴展

1. 平滑插值:消除幀跳躍的「卡頓感」

直接 gotoAndPlay 跳幀會導致畫面突變。改用「目標幀 + 緩動插值」:

var targetFrame:Number = movie._currentframe; // 目標幀 (浮點)
movie.onEnterFrame = function() {
    var rate = _root.DtoRate(this, 15, 35);
    targetFrame += rate;
    if (targetFrame > movie._totalframes) targetFrame -= movie._totalframes; // 循環
    // 緩動追趕當前幀
    movie._currentframe += (targetFrame - movie._currentframe) * 0.3;
    // 若需精確控制子元件,需改用自定義播放器模式
};

或使用 Tween 引擎 (TweenLite/GTween) 驅動 currentFrame 屬性。

2. 邊界與循環處理

function playRateCtr(movie:MovieClip, rate:Number):Void {
    var cFrame:Number = movie._currentframe;
    var nFrame:Number = cFrame + rate;
    var total:Number = movie._totalframes;
    // 循環邏輯
    if (nFrame > total) nFrame = nFrame - total;
    else if (nFrame < 1) nFrame = total + nFrame; // 倒放循環
    movie.gotoAndPlay(nFrame);
}

3. 多目標統一管理器

class SpeedController {
    private var targets:Array = [];
    private var centerMC:MovieClip;

    public function SpeedController(center:MovieClip) {
        centerMC = center;
        centerMC.onEnterFrame = driveAll;
    }
    public function addTarget(mc:MovieClip, maxRate:Number, distUnit:Number):Void {
        targets.push({mc:mc, maxRate:maxRate, distUnit:distUnit});
    }
    private function driveAll():Void {
        for each (var t:Object in targets) {
            var dx:Number = t.mc._xmouse; // 注意:_xmouse 相對各自 MC
            var dy:Number = t.mc._ymouse;
            var dist:Number = Math.sqrt(dx*dx + dy*dy);
            var dr:Number = Math.min(t.maxRate, Math.floor(dist / t.distUnit));
            var rate:Number = t.maxRate - dr + 1;
            _root.playRateCtr(t.mc, rate);
        }
    }
}
// 使用
var ctrl:SpeedController = new SpeedController(logo_part_1);
ctrl.addTarget(gear1_mc, 10, 40);
ctrl.addTarget(gear2_mc, 5, 60);

4. AS3 版本重寫 (現代項目必備)

package {
    import flash.display.MovieClip;
    import flash.events.Event;
    import flash.events.MouseEvent;

    public class DynamicSpeedMC extends MovieClip {
        public var maxRate:Number = 3;
        public var distUnit:Number = 50;

        public function DynamicSpeedMC() {
            addEventListener(Event.ADDED_TO_STAGE, onAdded);
        }
        private function onAdded(e:Event):void {
            removeEventListener(Event.ADDED_TO_STAGE, onAdded);
            addEventListener(Event.ENTER_FRAME, onFrame);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, onStageMove); // 全局滑鼠更新
        }
        private function onFrame(e:Event):void {
            var dx:Number = this.mouseX;
            var dy:Number = this.mouseY;
            var dist:Number = Math.sqrt(dx*dx + dy*dy);
            var dr:int = Math.min(maxRate, int(dist / distUnit));
            var rate:Number = maxRate - dr + 1;
            nextFrameByRate(rate);
        }
        private function nextFrameByRate(rate:Number):void {
            var targetFrame:Number = currentFrame + rate;
            var total:int = totalFrames;
            if (targetFrame > total) targetFrame -= total;
            else if (targetFrame < 1) targetFrame += total;
            gotoAndPlay(int(targetFrame));
        }
        private function onStageMove(e:MouseEvent):void {
            // 可選:用舞台滑鼠位置計算距離,需 globalToLocal 轉換
        }
    }
}

應用場景啟發

  • 互動儀表盤: 滑鼠靠近儀表 → 指針轉動加速,模擬「關注度驅動」。
  • 遊戲技能預覽: 滑鼠懸停技能圖標 → 技能動畫加速演示細節。
  • 時間軸 scrubber: 滑鼠 X 軸控制主時間軸播放速度/方向 (DJ 擦盤感)。
  • 背景氛圍動畫: 滑鼠活躍區域動畫加速,閒置區域緩慢呼吸,節省 CPU。

性能與兼容性提示

  • gotoAndPlay 頻繁調用會觸發幀腳本重複執行,**確保關鍵幀無副作用代碼** (如重複 addEventListener、new Object)。
  • 大量 MC 同時用此法會增加 CPU 負載,建議統一由一個 SpeedController 驅動。
  • AS3 中 currentFrame 為只讀屬性,**不能直接賦值**,必須用 gotoAndStop/Play 或 play()/stop() 配合 nextFrame()/prevFrame() 循環控制。
  • 移動端觸控事件 TouchEvent 替換滑鼠邏輯,距離計算同理。

總結

「距離映射倍數 + 幀跳躍執行」雙函數模型,用 20 行代碼實現了**空間交互控制時間流速**的核心體驗。這不只是技巧,更是「交互即編程」思維的縮影:將用戶輸入 (位置) 映射為系統參數 (速度),構建即時反饋回路。 理解這個模型,你就擁有了從「播放速度」延伸到「時間倒流、局部慢動作、音高同步變速」等所有時間操控能力的鑰匙。

copyright © 萬盛學電腦網 all rights reserved