Stopwatch based on timer showing wrong time AS3 - actionscript-3

I have created stopwatch which consist of two classes. First is stopwatchModel. Second is stopwatchView. My stopwatch is working but it is showing less time than how much time it last for real. It looks like my stopwatch is slower than reality.
StopwatchModel
private function initStopwatchModel():void{
timer = new Timer(100,0);
timer.addEventListener(TimerEvent.TIMER,onTimer);
}
private function onTimer(e:TimerEvent):void{
decsec++;
if (decsec == 10){
sec++;
decsec=0;
if (sec == 60){
sec = 0;
min++;
}
}
playerTimeString = min + ":" + sec + ":" + decsec + "0";
dispatchEvent(new Event("NEW_TIME"));
}
StopwatchView
private function initModelEventListeners(){
_model.addEventListener("NEW_TIME",onNewTime);
}
//update textoveho pola, vzdy ked sa zmeni cas
private function onNewTime(e:Event):void{
textFieldStopWatch.text = _model.playerTimeString;
}
Thank you for answer

Because timer is not fully accurate but it is somehow dependent on the frame rate so it finds the closest interval that is multiple to one frame time.
I would recommend you to save getTimer() return using http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/utils/package.html#getTimer() when the application starts and then measure it on timer and calculate the difference - this will work for sure.
The problem is also documented at http://www.computus.org/journal/?p=22

You should be using the getTimer function, not the Timer class. See for example https://stackoverflow.com/a/12495538/842685

Related

Accuracy of Task.Delay

I'm developing Windows 10 Universal App in C#/Xaml, I'm using await Task.Delay(delayInMilliseconds) to suspend a method for given time. My scenario is somewhat realtime, so it's very sensitive to time changes, and I need to make sure that when i suspend a method for let's say 8 millisecods it is suspended for 8 millisecods. I have noticed that the actual time span for which ** Task.Delay ** suspends the method differes from what is passed as delay parameter, for 1 up to 30 ms, the length of "deviation" being different in each call. So, when I want to sleep for 8 milliseconds, my system sleeps for 9 to 39 milliseconds, and this completly ruins my scenario.
So, my question what is the best way to substitute ** Task.Delay ** and to achieve good precision? For the time being I use this method:
public static void Delay1(int delay)
{
long mt = delay * TimeSpan.TicksPerMillisecond;
Stopwatch s = Stopwatch.StarNew();
while (true)
{
if (s.Elapsed.TotalMilliseconds > delay)
{
return;
}
}
}
but it guees it consumes a lot of resources, that is 100% of a processor's core. If an user has small number of processor's cores, this would be very insufficient.
According to msdn it's not possible to achieve more accuracy due to system clock resolution:
This method depends on the system clock. This means that the time
delay will approximately equal the resolution of the system clock if
the millisecondsDelay argument is less than the resolution of the
system clock, which is approximately 15 milliseconds on Windows
systems.
Seems like I've found a sattisfactory solution: using ManualResetEvent(false).WaitOne(delay) instead of await Task.Delay(delayInMilliseconds).
I've used following code to test both methods:
async void Probe()
{
for (int i = 0; i < 1000; i++)
{
// METHOD 1
await Task.Delay(3);
// METHOD 2
new System.Threading.ManualResetEvent(false).WaitOne(3);
}
}
The code above should take exactly 3 seconds to execute. With METHOD 2 it took around 3300 ms, so the error is 0.3 ms per call. Acceptable for me. But the METHOD 1 took around 15 seconds (as mentioned by others and explained above) to execute which gives totally unacceptable error for my scenario.
EDIT: WaitOne() is a blocking call, so you'll probably want to run it as a task to get it off the UI thread (or any other thread with a message pump). #Abel has pointed out another high-res timer approach that is already baked into a task and will run in an alternate thread as shown here: (https://stackoverflow.com/a/62588903/111575). That approach makes cpu-intensive calls to Thread.Spinwait() and Thread.Sleep(0) for small intervals.
You should use multi-media timers. Those are much accurate.
Take a look here:
https://social.msdn.microsoft.com/Forums/vstudio/en-US/2024e360-d45f-42a1-b818-da40f7d4264c/accurate-timer
After working hard I found a solution to sleep the thread for specific time and the error is just 3 to 4 microseconds on my Core 2 Duo CPU 3.00 GHz.
Here it is:
Here is code.(C# code is also given at the end.) Use "ThreadSleepHandler":
Public Class ThreadSleepHandler
Private Stopwatch As New Stopwatch
Private SpinStopwatch As New Stopwatch
Private Average As New TimeSpan
Private Spinner As Threading.SpinWait
Public Sub Sleep(Time As TimeSpan)
Stopwatch.Restart()
If Average.Ticks = 0 Then Average = GetSpinTime()
While Stopwatch.Elapsed < Time
If Stopwatch.Elapsed + Average < Time Then
Average = TimeSpan.FromTicks((Average + GetSpinTime()).Ticks / 2)
End If
End While
End Sub
Public Function GetSpinTime() As TimeSpan
SpinStopwatch.Restart()
Spinner.SpinOnce()
SpinStopwatch.Stop()
Return SpinStopwatch.Elapsed
End Function
End Class
Here is example code:
Sub Main()
Dim handler As New ThreadSleepHandler
Dim stopwatch As New Stopwatch
Do
stopwatch.Restart()
handler.Sleep(TimeSpan.FromSeconds(1))
stopwatch.Stop()
Console.WriteLine(stopwatch.Elapsed)
Loop
End Sub
For c# programmers here is code (I have converted this code but I am not sure):
static class Main
{
public static void Main()
{
ThreadSleepHandler handler = new ThreadSleepHandler();
Stopwatch stopwatch = new Stopwatch();
do {
stopwatch.Restart();
handler.Sleep(TimeSpan.FromSeconds(1));
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed);
} while (true);
}
}
public class ThreadSleepHandler
{
private Stopwatch Stopwatch = new Stopwatch();
private Stopwatch SpinStopwatch = new Stopwatch();
private TimeSpan Average = new TimeSpan();
private Threading.SpinWait Spinner;
public void Sleep(TimeSpan Time)
{
Stopwatch.Restart();
if (Average.Ticks == 0)
Average = GetSpinTime();
while (Stopwatch.Elapsed < Time) {
if (Stopwatch.Elapsed + Average < Time) {
Average = TimeSpan.FromTicks((Average + GetSpinTime()).Ticks / 2);
}
}
}
public TimeSpan GetSpinTime()
{
SpinStopwatch.Restart();
Spinner.SpinOnce();
SpinStopwatch.Stop();
return SpinStopwatch.Elapsed;
}
}
Note:
"ThreadSleepHandler" is thread unsafe. You cannot use a single "ThreadSleepHandler" for multiple threads.
The first sleep time will not be enough accurate.
In my tests, I found that DispatcherTimer at 20ms intervals will deliver sufficiently smooth animation if you must do it in code. Doing it in XAML is another alternative as already mentioned.

Need info on how to solve a function

What am i doing wrong? The program is meant to move a picture of a plane over the screen. The speed of the plane is increasing over time. The stage has a timer that runs the function 10 times per second
private function myTimer(e) {
var speed:int = 0;
plane.x = plane.x + speed
speed = speed + 10
}
You are defining the speed variable inside the function, this causes it to be initialized to 0 on every call, and since you only add to the speed after changing the x of the plane it never moves.
If you move the var speed:int = 0; definition outside of the function the changes will not be overwritten on each call.

5 Minute Countdown With Buttons

I have to make a 5 minute countdown clock as an assignment. I was given the basis of a as3 and told to add 'Start' - 'Reset' - 'Stop' buttons. So far I have a respectable countdown going, but no way to control it. I'm new to as2 and flash so I hope this isn't one of those "If you know that, you should know your answer" situations. Anything i try to find on the web as far as tuts don't really help me so if anyone could just tell me if I'm on the right path or eve if it's possible to ass buttons to this code to do whats stated above. Thanks in adv :)
var secs = "0" + 0;
var mins = 5;
timerDisplay.text = mins + ":" + secs;
var timerInterval = setInterval(countDown,1000);
//DISPLAYS DYNAMIC TEXT
function countDown()
{
secs--;
if (secs < 0)
{
secs = 59;
mins--;
}
if (secs < 10)
{
var secs2 = "0" + secs;
}
else
{
var secs2 = secs;
}
if (mins == 0 && secs == 0)
{
clearInterval(timerInterval);//STOPS TIME # ZERO
}
timerDisplay.text = mins + ":" + secs2;
}
As this is an assignment, I won't give you any code, just some ideas to get you on your way to writing your own.
You may want to add two (possibly three) buttons to the stage. One button could be the reset button and another could be a button that trades off between being start and stop (depending on whether the timer is currently running).
The only code necessary for a reset button, is something that sets your min variable and your secs variable back to their original values (possibly plus 1 second because of your interval code). If you need help getting started with buttons clicks throwing functions check out the mc.onPress method.
The only code necessary for a stop button, is something that stops your interval counter from continuing to count. I believe you already have something doing that when "clear" your timer at zero.
The only code necessary for a start button, is something that restarts your interval counter. You do something of the sort when you first start your timerInterval.
This won't work if someone decides to click on the start button after you have finished the countdown or if someone decides to click the start button multiple times.
In the first case, the countdown will continue into negative numbers, so you may want to write an if statement that doesn't allow that to happen (inside of the start button function).
And in the second case, the countdown will get faster and faster each time the button is pressed. Creating a boolean that keeps track of whether the program is stopped could possibly help with that problem.
To clarify a statement I made above about the interval code: Your code will forever decrement every 1000 milliseconds. The text box is only ever being refreshed when you decrement, so if you try to reset with exactly 5 minutes and zero seconds, you will see the numbers jump to 4:59 and then keep decrementing. If you reset to 5 minutes and 1 second, the numbers will appear to jump to 5:00 and then decrement from there.
I hope this helps!
package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class Test extends MovieClip {
private var _timer:Timer = null;
private var _repeatCount:int = 0;
private var _totalMinutes:int = 5;
public function Test() : void {
addEventListener(Event.ADDED_TO_STAGE, _Init);
}
private function _Init(e:Event) : void {
_repeatCount = _totalMinutes * 60;
_timer = new Timer(1000, _repeatCount);
_timer.addEventListener(TimerEvent.TIMER, _OnTimerFired);
_timer.start();
}
private function _OnTimerFired(e:TimerEvent) : void {
var minRem:int = (_repeatCount - _timer.currentCount) / 60 ;
var secRem:int = (_repeatCount - _timer.currentCount) % 60;
trace(minRem + ":" + secRem);
}
}
}

How to display the highest value from a random created list of numbers in AS3

I m building kind of a game in Flash (AS3) where sound input (microphone) trigger a equalizer (the micLevel.height controls the height of a mask (showing the equalizer). The activityLevel of the microphone gives me a number ( 0 - 100 ) wich is displayed in textfield prosent. The contestant shout in the microphone and try to reach 100 ( I use the mc.gain to make it hard to reach 100 ). So far so good! I m pretty new to AS3 so I feel kind of lost.
I need to display the highest number they manage to reach and I want to have a time limit on this. The highest sound level in lets say 5 seconds.
Here is the code so far:
var mic:Microphone = Microphone.getMicrophone();
Security.showSettings("privacy");
mic.setLoopBack(true);
if(mic != null)
{
mic.setUseEchoSuppression(true);
stage.addEventListener(Event.ENTER_FRAME, showLevel);
}
function showLevel(e:Event)
{
micLevel.height = mic.activityLevel * 6;
//mic.gain = 1;
//trace(mic.activityLevel);
prosent.text = "Activity: " + String(mic.activityLevel) + "%";
}
I just need some code that grab the highest number from the text field "prosent" (with a time limit) and display it in a new text field.
Im sorry if I m unclear, but if anyone could help me out I would be very happy!
Br Harald
Just create a variable that will be updated whenever the micLevel.height value is higher than it, e.g.
var highest:Number = 0;
function showLevel(e:Event):void
{
if(micLevel.height > highest)
{
// The mic level was higher than the previous highest level.
highest = micLevel.height;
// Change your other text field to show the value of 'highest'.
// ..
}
prosent.text = "Activity: " + String(mic.activityLevel) + "%";
}
Start a Timer to reset your highestLevel var. This will show you then the highest level every 5 seconds. You could add a timer start-stop button too if you wanted to keep one highest always showing.
Then in your showLevel function, use Math.max() to get the highest number (between current activity and recent highest)
var highestLevel:Number = 0;
var timer:Timer = new Timer(5000); // fires every 5 seconds
function initLevels(e:TimerEvent){
timer.stop(); // you could stop your timer here automatically and then use a button to start again
highestLevel = 0; // when timer fires restart your highestLevels var
}
function showLevel(e:Event) {
highestLevel = Math.max(mic.activityLevel * 6, highestLevel);
prosent.text = "Activity: " + String(highestLevel) + "%";
}
timer.start();
timer.addEventListener(TimerEvent.TIMER, initLevels);
addEventListener(Event.ENTER_FRAME, showLevel);

Difference between Date.getTime() and getTimer

How is the running time of the virtual machine calculated vs. how system time is calculated? I know I can get the current running time of the AVM by calling:
getTimer();
And I can get the current unix system time by doing:
new Date().getTime();
I know that the Timer class and Event.ENTER_FRAME event each come with their ups and downs, but I figured the 2 values I was comparing should stay consistently relative to each other. Here's how I'm testing it:
private var _appRunTime:int;
private var _appStartTime:int;
private var _systemTime:int;
private var _systemCurrentTime:int;
//called at application launch
protected function application1_creationCompleteHandler(event:FlexEvent):void
{
_systemTime = new Date().getTime();
_appStartTime = getTimer();
}
//called on button click to see values
protected function button1_clickHandler(event:MouseEvent):void
{
_systemCurrentTime = new Date().getTime();
_appRunTime = getTimer();
trace(_systemCurrentTime - _systemTime, _appRunTime - _appStartTime);
}
I don't understand why those numbers would slowly get out of sync. Using that code, I've found, at least on my computer, that the values grow apart from each other by about 3 milliseconds per minute, with the value coming from system time being the higher value and the value coming from AVM time being the lower.
Can anyone offer me an explanation what those are calculated on and why there would be that small, yet growing gap in their values as time passes?
On my system the same code gives no difference between getTimer() and getTime()
after ~10 mins the difference is always between 0 and 1 ms.
Maybe it's an issue of you system or the specific to the player you're running?
I'm running flash player 11 on Win 7 x64.
On my computer (Win 7 64-Bit), sometimes getTimer runs slower than Date.getTime() (system time), but sometimes getTimer() runs faster. The difference can range from -0.57ms/sec to 0.1ms/sec.
The result is independent of running in browser or Flash standalone player.
It will help you...
public static function getDaysBetweenDates(date1:Date,date2:Date):int
{
var one_day:Number = 1000 * 60 * 60 * 24
var date1_ms:Number = date1.getTime();
var date2_ms:Number = date2.getTime();
var difference_ms:Number = Math.abs(date1_ms - date2_ms)
return Math.round(difference_ms/one_day);
}