Actionscript 3.0: What is the difference between using the ENTER_FRAME event and a TIMER event for the update method? - actionscript-3

Im looking for some comparison between ENTER_FRAME and TIMER methods when using them for an update method. I have looked around the internet for some answers but I'm still finding it hard to understand.
Would anyone be able to help with simplifying the different between them?

Timer events can dispatch independent of the framerate of the swf (to a point). They can happen more often or less often than an ENTER_FRAME event, and should be used if you care about the precision of calculations as they happen between the span of time covered by ENTER_FRAME. The most common use case for this is a physics engine, where you may want to be as precise as possible and therefore wish to perform your simulation at a rate faster than Flash's fps.
Also, timers can be useful if you want a specific action to occur after a given delay. For example, a Timer lets you perform an action after 10 seconds easily. You simply pass 10000 milliseconds into your Timer's constructor and then the Timer event will be dispatched 10 seconds later. If you were to use ENTER_FRAME you would need to manually track the time elapsed on every frame update if you wanted to know when 10 seconds had passed.
ENTER_FRAME events are tied to the rendering cycle of the timeline and more or less match the framerate you've specified. For instance, if you have a framerate of 30fps then you'll receive approximately 30 ENTER_FRAME events per second. You may receive fewer if you have a particularly complex display list, or if your logic takes a particularly long time to execute.

"enterFrame" is dispatched on every frame.
Suppose your SWF is 24fps: "enterFrame" will be dispatched up to 24 times every second.
"timer" is dispatched at a set interval.
Suppose you start a Timer with a delay of 50 milliseconds: "timer" will be dispatched up to 20 times every second.
The actual frequency of these events will depend on the host environment as well as what's going on inside your application. For example, if you have a for loop inside your "timer" handler where you're iterating over a 1,000-element array and performing some string manipulation on each element, then you'll likely get fewer "timer" events than if your array contained only 10 elements. Likewise, if the user's system is low on free memory, then Flash Player may have trouble executing your SWF and it might slow down the rate at which these events are dispatched.
"enterFrame" depends directly on the frame rate. "timer" depends somewhat indirectly on the frame rate.
Because you (or someone else) will invariably ask what I mean by "somewhat indirectly," here's a small AS3 app that tests both events:
package
{
import flash.display.*;
import flash.events.*;
import flash.utils.*;
public class Test extends Sprite
{
private var timer:Timer = null;
private var timerEventCount:int = 0;
private var enterFrameEventCount:int = 0;
private var startTime:Number = 0;
public function Test()
{
timer = new Timer(20, 0);
timer.addEventListener("timer", timerHandler);
timer.start();
addEventListener("enterFrame", enterFrameHandler);
startTime = new Date().time;
}
private function timerHandler(event:Event):void
{
timerEventCount++;
var timeElapsed:Number = new Date().time - startTime;
//for (var i:int = 0; i < 4000; i++)
// trace("i", i);
if (timeElapsed >= 1000) {
// Stop timer after 1 second.
timer.stop();
removeEventListener("enterFrame", enterFrameHandler);
trace(timerEventCount + " timer events and "
+ enterFrameEventCount + " enterFrame events in "
+ timeElapsed + " milliseconds.");
}
}
private function enterFrameHandler(event:Event):void
{
enterFrameEventCount++;
}
}
}
Compile at 12fps:
mxmlc Test.as -default-frame-rate=12
Output:
45 timer events and 12 enterFrame events in 1001 milliseconds.
Compile at 60fps:
mxmlc Test.as -default-frame-rate=60
Output:
29 timer events and 58 enterFrame events in 1010 milliseconds.
As you can see, a higher frame rate actually slows down the timer. I'm running this in Flash Player Debugger 10.3.181.34 (10.3); your mileage may vary.
Finally, if you uncomment the for loop and run it again with 60fps, you'll see what I'm talking about.
Output:
3 timer events and 3 enterFrame events in 1145 milliseconds.

ENTER_FRAME is an event that is triggered every time the render loop of the virtual machine runs and this is relative to the framerate of the movie. For example, in the Flash CS IDE if you set the framerate to 30, then from the root display object or stage, 30 ENTER_FRAME events will be fired every second.
A timer on the other hand is just that, a timer. It runs solely based on the system clock time. For example, if you set a timer with a delay of 1 millisecond, then that timer will fire one millisecond after being started, and will continue to fire once every single millisecond if you enable it. What I think camus was trying to say in his answer is that this process runs independent of the framerate. It's based solely on checking the system clock and triggering events for timers that have had the requested delay satisfied. This is verified internally by storing the system time at which the timer was started and then checking the current system time repeatedly until it is greater than or equal to the saved time PLUS the timers delay. Example:
timer.start() //Lets say current system time is 1000
Timer duration is 1000, so we need to trigger this timer when the system time is greater than or equal to 2000.
checkTimers() //Loops, gets the current system
//If system time is greater than or equal to 2000, trigger timer with an event
dispatchEvent(Timer.TIME, etc, etc);
Note that the above "code" is just pseudo code to demonstrate the basic principles of the system.

ENTER_FRAME is relative to the movie's frame rate . TIMER events should be absolute.

Related

How to update as3 code faster?

Is it any way possible to update my code (as3) more than 1 time per frame? it doesnt have to do anything visual. I used before event.ENTER_FRAME. If there's a way to do so, could someone explain or give a link how to do that. Thanks.
You can use a timer to execute code at whatever rate you want :
// first parameter for Timer is duration in milliseconds 1000ms = 1 second.
var timer:Timer = new Timer(10,0);
timer.addEventListener(TimerEvent.TIMER, timerHandler);
timer.start();
function timerHandler(e:TimerEvent):void
{
// do something;
}
However, I'd question why you want to do this and determine if it's really needed.
If you app is running at 30fps you can set it to run at 60fps, then ENTER_FRAME will be called twice as much, or if you use a timer to update you can reduce its delay by half.

How to prevent cheating on a flash game by slowing down cpu?

I developed a flash game in AS3, similar to Music Challenge on Facebook, where you need to guess from a selection of songs, wich one is the one playing, score is based on how many did you guess in 30 seconds, this timeout, is handled by an instance of Timer.
Everything works good, but someone pointed out that by reducing cpu performance, timer goes slower, allowing users to play longer, guess more songs and ultimately get a higher score, then I did some research, and read that to prevent this, I need to use systems time, the problem is, I don't know how to do this.
Any help is very much appreciated.
You could have a repeating timer with a short interval, 100ms or so, and check new Date().getTime() on each tick. By default, a new Date has the current system time, and getTime() gives you the time in milliseconds for a simpler comparison. Compare that with a start time and end the game once at least 30 seconds have passed. Something like:
import flash.utils.Timer;
import flash.events.TimerEvent;
var ticker:Timer = new Timer(100, 0);
ticker.addEventListener(TimerEvent.TIMER, checkElapsedTime);
var startTime:Number = new Date().getTime();
ticker.start();
function checkElapsedTime(e:TimerEvent):void {
var now:Number = new Date().getTime();
if (now - startTime >= 30 * 1000) {
// End the game and stop the ticker.
ticker.stop();
ticker.removeEventListener(TimerEvent.TIMER, checkElapsedTime);
}
}
There is obviously still some slight lag if the timer is very slow, so just in case I would run the same check when an answer is submitted and ignore it if it was after the deadline.
Finally, to check if a user has changed their system clock you could store the previous now and make sure the new now is always larger.

Smooth 60fps frame rate independent motion in AS3

I'm having trouble achieving frame rate independent motion in AS3 at 60fps. Every frame I measure the time since the previous frame, add it to an accumulator, and if the accumulator is greater than my target time, which is 16.666ms (60fps), a frame is simulated.
The problem is that the AS3 getTimer() only returns a time in milliseconds.
The delta times I get are often 16ms for the first frame, 16ms for the second, then 18ms for the third, and this pattern repeats. This averages out to 16.666. But in the first frame it is lower than the target time (16 < 16.666), so no frame is simulated. In the second frame the accumulator is higher than the target time, but slightly less than double it, so one frame is simulated. For the third frame 18ms pushes the accumulator over double the target time, so two frames are simulated.
So I'm getting this very jerky motion where no frames are rendered, then one, then two, then none, then one, then two, and this continues.
How would I get around this?
Wow... I thought I was only one who found that out.
Yes, the timer class in AS3 is not accurate. It will only trigger every ~16ms which causes MAJOR issues at times.
If want to see 2048 actions in 1000ms: FlashText Markup Language
(To test this, you'll need a method which takes 1ms to execute - just for even stats)
Notice the difference:
CORRECT: 1000ms | timer=0 == 1000 actions
AS3: 1000ms | timer=0 == 62.5 actions
I was able to write a class that works like this:
CORRECT: 1000ms | timer=0 == 1000 actions
RESHAPE TIMER: 1000ms | timer=0 == 1024 actions
NOTE:
it DOES NOT fire an action every ms
it DOES catch up to actions between the 16ms interval
an ACTION (the way I use it) is a method call, each method call can have its own body
The methodology I used to create this was catch-up... basically the first timer event will fire at 16ms... we know we have a full 16ms worth of code time to fire our own actions before the timer class fires again - thats where you inject sub-actions...
The highest I was able to produce was 2048 actions in 1000ms... more than 2 actions per ms.
Now... back to your problem
There is NO WAY to trigger a 0ms timer event. Based on my solution, if you want to by-pass the first 16ms of lag before the timer fires... you can dispatch an event which will fire within 2ms depending on the current system processes.
Possible Solution
If you take my approach for throwing your own actions within the 16ms, then you can build your own timer class. Use events for times under 16ms, when fired... fire 15 more - lol. Basically, you can create your own deltas between the 16ms.

Time Slow/Speed Up Power Up

I'm creating a collecting game, and I want to create a time slow/speed up powerup.
Any ideas on how to do that in Flash/AS3?
One way I thought of was simply changing the frame rate. I can slow down the frame rate. But when I try to increase the frame rate beyond 60, Flash caps it at 60.
Thank you in advance for your help.
I like to do time-based movement instead of frame-based movement for better consistency. The general concept is to check the amount of time passed between frames and base movement on that instead of frames which can alternate (e.g. you can have 60FPS for a bit and then it slows down to 30FPS). You can do a simple calculation based on time passed for movement, for instance player.x += player.speed * timeDiff but that can result in odd situations if the time passed between frames happens to be really large (for instance, the player can end up missing lots of collisions since you are moving him in one large movement). Instead, I like to use a game loop to move the player X times based on the amount of time that has passed between frames, ensuring that collisions and any other game loop events will be properly checked.
This also has the advantage that it is easy to adjust the speed.
Here is the basic concept:
private var speedMultiplier:int = 100;//100 normal speed, 0 paused
private var currRealTime:int = getTimer();
private var currGameTime:int = currRealTime;
private var globalLastTime:int = currRealTime;
private var totalTimeDiffRemainder:int = 0;
private var loopTime:int = 20;//every 20 ms run our actions
public function getGameTimer():int
{
return currGameTime;
}
private function updateGameTime():void
{
var realTime:int = getTimer();
currGameTime = currGameTime + speedMultiplier/100*(realTime - currRealTime);
currRealTime = realTime;
}
private function runEvents(event:Event):void
{//ENTER_FRAME event
var totalTimeDiff:int = getGameTimer() - globalLastTime + totalTimeDiffRemainder;
globalLastTime = getGameTimer();
while (totalTimeDiff > loopTime)
{//every 20 ms run all our actions
totalTimeDiff -= loopTime;
//run all your game loop events here, such as collision checks
}
totalTimeDiffRemainder = totalTimeDiff;
updateGameTime();
}
So every time an ENTER_FRAME event fires, we will check the time passed since the last ENTER_FRAME event and then run our actions once for each 20ms that has elapsed and pass the remainder over to the next ENTER_FRAME event. For instance, if it's been 47 ms since the last ENTER_FRAME, we will run our actions twice and pass over 7 remaining ms to the next ENTER_FRAME event.
In order to pause, slow down, or speed up the game, all you have to do is modify speedMultiplier. Changing speedMultiplier to 0 will pause the game, 50 is half speed 100 is normal speed, 200 double speed, etc.
I believe the general way to do this would be to use an MVC like setup where your model holds all the data for the game elements (character position/orientation, enemies, dynamic map elements) then the controller is modifying the model. With the controller modifying the model this way you could add a multiplier to the model, and use the multiplier when having the controller update the model for "physics" or other modifying dynamic elements in the game.
Roughly:
Model
public var speedMultiplier:Number=1;
public var playerXSpeed:Number;
public var playerYSpeed:Number;
Controller (I'm assuming you make a controller class and pass the view to the constructor and are listening for events from the view in the controller).
private function enterFrame_handler(event:Event):void
{
var playerSprite:Sprite = mainView.playerSprite;
playerSprite.x += playerXSpeed*speedMultiplier; //only problem I can see here is your player skipping past certain elements, to avoid this you could use a loop to make each motion and do checks but it's more CPU intensive
//var enemySprites:Vector<EnemySprite>;
//other game physics here, reduce speed due to drag, fix any invalid values etc.
}
Edit
Actually in thinking this through some more, although I do generally like using an MVC setup myself since it allows one to have a single sprite that does all the drawing; you could also use the same concept of a speedMultiplier shown here without necessarily changing around any software patterns. If you end up needing to do it with a loop because you need it to do checks for every spot it would hit as an object moves along, you may need to have your default speedMultiplier be something like 10 so you could set it down to 1 to get 1/10th speed with all the same checks as it would get at 10 being normal speed (again only issue here being it has to do whatever calculations 10 times for every update, in this case you may want to use a timer instead of the frame rate to control the overall calculation speed).

Starting many Timers at the same time in AS3

var LevelCode:Array = [10,20,30,40,50,60,70,80,...,990,1000];
var Piece0:Timer = new Timer(50, LevelCode[0]);
var Piece1:Timer = new Timer(50, LevelCode[1]);
...
var Piece98:Timer = new Timer(50, LevelCode[98]);
var Piece99:Timer = new Timer(50, LevelCode[99]);
I want to start Piece0 timer, Piece1 timer, etc., at the same time.
I tried Piece0+Piece1.start();, but it did not work.
Can you guys help me?
maybe you don't need many timers, since you're using identical 50 milliseconds timers.
why don't you just use one timer and handle the event int the function specified with addEventListener?
var myTimer:Timer = new Timer(50);
myTimer.addEventListener(TimerEvent.TIMER, timerElapsed);
myTimer.start();
function timerElapsed(event:TimerEvent):void
{
//handle your levels here
}
Running
Piece0.start();
Piece1.start();
Will start them near enough to the same time as to be beneath the threshold that they can resolve, so they'll be effectively the same time. Starting a timer is not a resource-intensive process.
You can not rely on timers triggering at the same time like this.
This is a very bad implementation and you need to think about a redesign.
ActionScript is not threaded and as such is asynchronous.
Because of this no two timer events will ever fire at the same time.
It will always be one after the other. You should follow the suggestion that vulkanino had made and consolidate everything into one call.
Plus having 100+ timer events is a lot of over head and can you be certain all 100 timer events would be processed in the 50 milliseconds you are giving them to run?
If not you risk some "overlapping issues" all dependent on the code you are doing in the callback functions.