Better timing in Flash (actionscript 3)
I am trying to make a metronome in flash cs3. It is not very consistent using a Timer.
Was wondering if anyone knew some class someone may have wrote for better timing capability.Or even with the new dynamic sound generation available with Flash Pl开发者_JAVA百科ayer 10 is there a way?
good question. i've always assumed that not being able to achieve accurate timing in Flash was a crutch of the VM and have accepted it. however, i just googled and found the following recipe on Adobe Developer Connection CookBooks. judging from the recorded results comparison and the user comments it seems to work well:
Adobe Developer Connection CookBooks: Accurate Timer
test it out and post your results, i'd be interested in reading them.
You can't get perfect timing within the current Flash Player because you are restricted to only running code when events fire (either ENTER_FRAME or a TimerEvent).
As the previous answer alludes to, you can have your application record when these events happen (either by making a new Date instance, or calling getTimer()) and then calculate the time delta between frames. Using those deltas, you can usually make your application behave as if it has accurate time information, but there is no way to perfectly execute code every 50 milliseconds because events don't fire with that accuracy.
As far as using the sound generation possibilities: The Sound class has an Event.SAMPLE_DATA event that could be used instead of an ENTER_FRAME or TimerEvent, but it does not react as quickly. If you don't pass in enough data to the buffer, the event ceases to fire. And the amount of data to fill the buffer is more than you could get from the accuracy of ENTER_FRAME or a TimerEvent. Code to support:
public class Tester extends Sprite
{
private const MAXIMUM_LOG_LINES:uint = 30;
private var _timer:Timer;
private var _sound:Sound;
private var _textField:TextField;
public function Tester()
{
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
_textField = new TextField();
_textField.defaultTextFormat = new TextFormat(null, 12);
_textField.multiline = true;
_textField.wordWrap = true;
_textField.width = stage.stageWidth;
_textField.height = stage.stageHeight;
addChild(_textField);
_timer = new Timer(1, 0);
_timer.addEventListener(TimerEvent.TIMER, onTimerTick, false, 0, true);
_timer.start();
_sound = new Sound();
_sound.addEventListener(SampleDataEvent.SAMPLE_DATA, onSoundSampleData, false, 0, true);
_sound.play();
addEventListener(Event.ENTER_FRAME, onEnterFrame, false, 0, true);
}
private function onTimerTick(event:TimerEvent):void
{
log("onTimerTick(event) @"+getTimer());
}
private function onEnterFrame(event:Event):void
{
log("onEnterFrame(event) @"+getTimer());
}
private function onSoundSampleData(event:SampleDataEvent):void
{
log("onSoundSampleData(event) @"+getTimer());
for (var c:int=0; c<2048; c++)
{
event.data.writeFloat(0);
event.data.writeFloat(0);
}
}
private function log(message:String):void
{
trace(message);
_textField.appendText(message+"\n");
if (_textField.numLines > MAXIMUM_LOG_LINES)
{
var indexOfFirstLine:int = _textField.text.indexOf("\r");
while(indexOfFirstLine >= 0 && _textField.numLines > MAXIMUM_LOG_LINES)
{
indexOfFirstLine++;
_textField.text = _textField.text.substring(indexOfFirstLine, _textField.text.length);
indexOfFirstLine = _textField.text.indexOf("\r");
}
}
}
}
`
I just released a libary called Metronome which solves this issue. I thought I'd post it here since this is were my initial search took me before I decided to tackle the problem myself.
You can download it from http://cote.cc/projects/metronome (there's also a link to the GitHub repo).
Hope this helps!
P.S. I also wrote a blog post detailing how the library came about. It provides insights into how timing works in ActionScript: http://cote.cc/blog/accurate-timing-in-actionscript
精彩评论