保持 Flash Player 背景運作 FPS 技巧
最近處裡另一個時間上的問題時,偶然發現的技巧
可以讓背景模式下 Flash Player Plugin 維持原本 FPS 運作
突破 2 FPS (或 8 FPS) 的節流限制 (Throttle Mode)
參考之前的文章 Flash Player 10.1 維持 8 FPS 小技巧
這次一樣是用 Sound 物件來做到的
只有一點不同,就是要自己合成聲音資料
測試程式如下:
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.SampleDataEvent;
import flash.events.TimerEvent;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.net.URLRequest;
import flash.utils.getTimer;
[SWF(width = "300", height = "200", frameRate = "30")]
public class Test extends Sprite {
public var snd:Sound = new Sound();
public var sndCh:SoundChannel;
public function Test() {
addEventListener(Event.ENTER_FRAME, onEnterFrameHandler);
/*/ 強迫至少保持 8 FPS
snd = new Sound(new URLRequest(""));
snd.play();
snd.close();
//*/
//*/ 強迫保持原本設定 FPS
snd.addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleDataHandler, false, 0, true);
sndCh = snd.play();
//*/
}
public function onSampleDataHandler(e:SampleDataEvent):void{
e.data.position = e.data.length = 4096 * 4;
}
public var lastFrameTime:int = getTimer();
public function onEnterFrameHandler(e:Event):void{
var currFrameTime:int = getTimer();
var timeElapsed:int = currFrameTime - lastFrameTime;
trace("[", e.type, "] elapsed:", timeElapsed, "ms, fps:", ~~(1000 / timeElapsed + 0.5));
lastFrameTime = currFrameTime;
}
}
}
編譯測試以上的程式,然後用瀏覽器執行,並切換到背景
從輸出 Log 可以發現一直都能保持原本設定的 30 FPS 左右
假如把聲音程式註解掉,跑起來就會變成這樣了
[ enterFrame ] elapsed: 47 ms, fps: 21 [ enterFrame ] elapsed: 26 ms, fps: 38 [ enterFrame ] elapsed: 49 ms, fps: 20 [ enterFrame ] elapsed: 20 ms, fps: 50 [ enterFrame ] elapsed: 32 ms, fps: 31 [ enterFrame ] elapsed: 33 ms, fps: 30 [ enterFrame ] elapsed: 34 ms, fps: 29 [ enterFrame ] elapsed: 32 ms, fps: 31 [ enterFrame ] elapsed: 35 ms, fps: 29 // 切換到背景 [ enterFrame ] elapsed: 510 ms, fps: 2 [ enterFrame ] elapsed: 507 ms, fps: 2 [ enterFrame ] elapsed: 508 ms, fps: 2 ...
讓聲音一直在那邊跑感覺很怪,所以寫成公用類別
加上一些自動偵測的功能,不需要用的時候可以停止
等到將來 Flash Player 提供 Throttle Event 時候
就不需要自己偵測了
package com.ticore.time.utils {
import flash.display.Shape;
import flash.events.Event;
import flash.events.SampleDataEvent;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.utils.getTimer;
/**
* 利用 Sound SampleData 事件
* 迫使 Flash Player 背景執行時,仍以指定 FPS 運作
*
* 使用方式
*
* 1. 建立 FPSUnthrottler 實體,直接呼叫 activate 啟動
*
* 或是
*
* 2. 將 FPSUnthrottler 實體加入到 DisplayList
* 它會自動偵測目標 FPS 與實際 FPS,決定啟動或是停止
*
* @author Ticore Shih
*/
public class FPSUnthrottler extends Shape {
public function FPSUnthrottler() {
snd.addEventListener(SampleDataEvent.SAMPLE_DATA, onSameplDataHandler, false, 0, true);
addEventListener(Event.ADDED_TO_STAGE, onAddStageHandler, false, 0, true);
addEventListener(Event.REMOVED_FROM_STAGE, onRemoveStageHandler, false, 0, true);
}
protected function onAddStageHandler(e:Event):void{
addEventListener(Event.ENTER_FRAME, onEnterFrameHandler, false, 0, true);
}
protected function onRemoveStageHandler(e:Event):void{
removeEventListener(Event.ENTER_FRAME, onEnterFrameHandler, false);
}
protected var recentFrameTimes:Array = [];
protected function onEnterFrameHandler(e:Event):void{
var throttleFrameTime:int = 100;
var targetFrameTime:int = 1000 / stage.frameRate;
// 原本設定的 FPS 就已經低於 Throttle FPS 了
if (targetFrameTime > throttleFrameTime - 20) {
deactivate();
return;
}
var currTime:int = getTimer();
var lastFrameTime:int = currTime - recentFrameTimes[0];
recentFrameTimes.unshift(currTime);
var maxSampleLen:int = 300;
var sampleLen:int = recentFrameTimes.length = Math.min(recentFrameTimes.length, maxSampleLen);
var avgFrameTimeTotal:int = (recentFrameTimes[0] - recentFrameTimes[sampleLen - 1]) / sampleLen;
// trace("FrameTimes:", targetFrameTime, lastFrameTime, avgFrameTimeTotal);
if (lastFrameTime > throttleFrameTime) {
// 最後一次影格事件突然小於 2 FPS
activate();
} else if (avgFrameTimeTotal <= targetFrameTime) {
// 連續平均影格事件 FPS 小於等於目標 FPS
deactivate();
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
protected var snd:Sound = new Sound();
protected var sndCh:SoundChannel;
protected function onSameplDataHandler(e:SampleDataEvent):void{
e.data.position = e.data.length = 4096 * 4;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public function activate():void{
if (sndCh) return;
trace("FPSUnthrottler.activate();");
sndCh = snd.play();
}
public function deactivate():void{
if (!sndCh) return;
trace("FPSUnthrottler.deactivate();");
sndCh.stop();
sndCh = null;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
}
以上的技巧,大略在 Windows 7 + Chrome + Flash Player 11.1 測試過 OK
假如其它環境有問題,也請告知一下
除此之外,好像還可以用 Flash Player mm.cfg 設定方式取消 Throttle Mode
Flash Player 10.1でバックグラウンド動作をとめない方法
FullFramerateWhenInvisible=1
2012/03/28 更新
發現根本不需要花力氣寫入聲音資料
直接把 data 長度拉成 4096 * 4,然後 position 移動到最後面就好了
相關連結:
Flash Player 10.1 維持 8 FPS 小技巧
轉載請註明出處 http://ticore.blogspot.com/2012/03/maintain-fps-throttle-mode.html
本文出自 传播、沟通、分享,转载时请注明出处及相应链接。
本文永久链接: https://www.nickdd.cn/?p=1899