I'm trying to write a simple game in AS3 / Flex 4, and I'm trying to find the best way from the get-go to handle timed execution of code.
The most natural approach would be to use a bunch of Timer objects throughout the program. However that's supposedly pretty expensive on CPU cycles, compared to ENTER_FRAME.
However I'm not sure how natural it would be to base all of a program's timed execution off of ENTER_FRAME, and I have read on stackoverflow that it's got issues - that Timer doesn't - with regards to dragging down animation and framerate when the complexity of the program increases.
Another option that comes to mind is to simply use one Timer object in the program, whose event handler will go through and check on everything in one go around - kind of like blending the usual Timer and ENTER_FRAME approaches.
My question is this: What's really kind of the best idea for a video game in AS3/Flex 4, and why? Thanks!
It depends entirely on when you want to update values, check collisions, manage input and so on vs when you want to actually see something happen on the screen.
ENTER_FRAME will make your update logic and the rendering of your game synchronous.
Every time an ENTER_FRAME event is dispatched, the scene is redrawn. What this means is that all your game update logic is always immediately followed by the screen being rendered. If the frame rate in your game drops due to complex graphics on the screen taking a long time to render, so will the rate at which your game updates. ENTER_FRAME dispatches are erratic, meaning they're not good for update tasks that you need to perform with even intervals between them.
Timers will cause your update logic and the rendering of your game to become asynchronous.
Timers can trigger far more or far less frequently than an ENTER_FRAME handler would. This means that your update loop could run multiple times before the scene is redrawn, or that the scene could be redrawn multiple times with no changes. Timers are less erratic than ENTER_FRAME handlers, making them better at doing something at set intervals. With that said though, there will still be a little bit of offset between updates:
Depending on the SWF file's framerate or the runtime environment (available memory and other factors), the runtime may dispatch events at slightly offset intervals. For example, if a SWF file is set to play at 10 frames per second (fps), which is 100 millisecond intervals, but your timer is set to fire an event at 80 milliseconds, the event will be dispatched close to the 100 millisecond interval. Memory-intensive scripts may also offset the events.- help.adobe.com | flash.utils.Timer
Personally I have always used ENTER_FRAME vs Timers. To me it is logical that if I make changes to the objects within a game, those changes should be immediately represented on-screen.
Timers are good if you want to be able to update components within your game faster than the frame-rate is able to manage. Timers are also good if you expect a given amount of updates to be completed within a certain timeframe, because they're not bound by the rate at which the screen is able to be redrawn like ENTER_FRAME is.
As for actual implementation, you preferably want to pick one and implement one handler. This means that you should only have a single function in the entire game that will be triggered by either a Timer or ENTER_FRAME. You do not want to be creating individual handlers in every single class that should be updated. Instead, you want to have your top level class (or a close relative of that class) define the handler. You also want to create a list within that class which will represent everything in the game that needs to be updated.
From there, you will create a small collection of methods that will deal with listing and de-listing updatable instances from that class. Each updatable instance will either implement an interface or extend a class that defines an update() method. It could look like this:
public interface IUpdatable
{
function update();
}
From there, the update handler within the updater class will simply iterate over all of the updatables in the list and call their update() method, like this:
for each(var i:IUpdatable in updateList)
{
i.update();
}
A final note is that this approach means that if you do decide to switch from using an ENTER_FRAME handler to a Timer or vice versa, it's a simple switch in the updater class and doesn't require you to change any other part of the game code. If you go around creating handlers in each class that needs to be updated, your change of heart will mean making changes to every single class.
Related
So, if I'm checking for something in the enterframe event listener, and I want to check (if something happens) do this. But somehow checking every frame was too slow. Is there a way to check in infinite speed and not every frame, so that when it checks something, it instantly changes to that position?
Technically, there is no way to check something faster than once per frame, if you have your frame rate already at 60fps. Timer is limited to trigger at most 60 times per second, and this is the same speed you can get by setting stage.frameRate too. But, if you are checking, for example, the collision of something that flies very fast and an obstacle, which is before that obstacle in the current frame, and past it the next frame, you can use a derivative of axis-aligned bounding box collision detection, and also transition collision detection (a probable example is here), which is checking if the path intersects a bounding box in the time between two frames.
If you are checking for a process that depends on certain factors and time, and you can check its condition in this frame and the previous frame, you can interpolate that process between frames in a conventional enterframe listener and check if the condition you are seeking might happen in between, and if it might, you might check whether it did happen by interpolating at a smaller time intervals than a frame. Still, you'd better refrain from using hitTest in such interpolation, as this is very costly check, and you can receive faster negative results from AABB checks and other methods of optimizing collision detection.
I've been looking for a solution for this for a while now and I still haven't found it. Our app needs to poll a YouTube video object using player.getCurrentTime() to drive some screen animations. Using the flash API this was great because we could poll the player at 40ms intervals (25 FPS) and get very accurate current player time values. We have now started to use the iFrame API which unfortunately does not allow anything near that level of accuracy. I did some research and it seems that because it's an iFrame, a postMessage is used to expose the players state to the player.getCurrentTime() call. Unfortunately this post message event is fired very infrequently - sometimes as low as 4 times a second. Worse, the actual rate the message fires seems to be dependent on the render engine for the browser.
Does anybody know if it is possible to force the render engine to fire those messages more frequently so that greater time resolution can be achieved polling the player? I tried requestAnimationFrame and it doesn't solve the problem. Has anybody successfully managed to get the iFrame player to report more accurate times and more frequently?
I've come up with a workaround for my original problem. I wrote a simple tween function that will poll the iFrame player at the frequency I desire and interpolate the time instants in between. The player itself only updates the current time every 250 ms or so depending on the render engine and platform. If you poll it more frequently than that, it will return the same current time value on several consecutive polls. However, if you apply some logic, you can detect when the player returns a new current time and update your own timer accordingly. I run the function below on a timer with a 25 ms interval. On each iteration, I add 25 ms to the current time except in the case where I detect a change in the current time reported by the player. In that case I update my own timer with the new "actual" current time. There maybe a small jump or non linearity in the time when you do this but if you poll the player at a high enough rate, this should be imperceptible.
window.setInterval(tween_time, 25);
function tween_time() {
time_update = (ytplayer.getCurrentTime()*1000)
playing=ytplayer.getPlayerState();
if (playing==1){
if (last_time_update == time_update)
{
current_time_msec += 25;
}
if (last_time_update != time_update)
{
current_time_msec = time_update;
}
}
do_my_animations();
last_time_update = time_update;
}
In HTML5 it is likely that the getCurrentTime() function and postMessage event in Youtube API are linked to the currentTime property and timeupdate event of the HTML5 media element specification.
The rate at which the timeupdate event fires varies between browsers and as of today cannot be tuned for the level of precision you are looking for (Flash is still a bit ahead on this one). According to the specification:
If the time was reached through the usual monotonic increase of the current playback position during normal playback, and if the user agent has not fired a timeupdate event at the element in the past 15 to 250ms and is not still running event handlers for such an event, then the user agent must queue a task to fire a simple event named timeupdate at the element. (In the other cases, such as explicit seeks, relevant events get fired as part of the overall process of changing the current playback position.)
The event thus is not to be fired faster than about 66Hz or slower than 4Hz (assuming the event handlers don't take longer than 250ms to run). User agents are encouraged to vary the frequency of the event based on the system load and the average cost of processing the event each time, so that the UI updates are not any more frequent than the user agent can comfortably handle while decoding the video.
For the currentTime property the precision is expressed in seconds. Any precision below of the second is browser specific implementation and should not be taken for granted (in reality you will get sub second precision in modern browsers like Chrome but with fluctuating efficiency).
On top of that the Youtube API could be throttling all of those things up to get to the larger common ground of 250ms precision and make all browsers happy (hence 4 events per second and what you did notice in your tests). For your case scenario you better off trying to scale your animations to this 250 ms precision notion and allow for some margin of error for a better user experience. In the future browsers and HTML5 media will get better and hopefully we will get true milliseconds precision.
I'm developing a flex game which is really jerky and not smooth at all on mobile devices.
I changed the application frameRate to 60 in my mxml file and it seems to run smoother (but not as it should). Does this have any impact on performance?
Is there any other way to do this? I don't have long and complex operations and I'm saying this because I found some open source libraries through which I can use async threads. But I read that this has downsides also.
I'm really confused because the only objects I have on stage are:
15 Image objects, each one with a Move object attached and an OnClick listener.
4 timers that repeat each 500 ms, 1 second, 2 seconds and 5 seconds.
The longest operation in the listeners and timers is O(n) where n = image count = 15, but most of them are O(1)
All the objects are created on view creationComplete event and I reuse them throughout the entire time.
Memory is managed correctly, I checked using memory profiler.
Can you point me in some directions?
I am facing the follow problem :
- There is a calculation which is calculated complex maths during the loading of the application, and it is toking considerable long time ( about 20 seconds ) on which time the CPU is used nearly on 100% and the application look like it is frozen.
Since it is a mobile application, this must be prevented, even with the costs of extending the initial loading time, but there is not direct access to the calculating code since it is inside 3rd party library.
Is there a way to prevent AIR application most of CPU generally ?
On desktop, you would use the Workers API. Its pretty new, I'd recommend it for AS3 only projects. If you use flex, its better to wait a few months.
Workers is a multi-threading API, what allows you to make a UI and a Working thread. This will still use 100% of CPU, but UI won't stuck.. Here are some links to get you started:
Thibault Imbert - sneak peek,
Intro to as 3 workers,
AS3 Workers livedocs
However, on Mobile, you can't use workers, so you'd have to break your function apart, and insert some delays there, like callLater, or setTimeout. Its hard to compose a function like that, but if it has a loop, you can insert a callLater method after every x iteration. you can parametrize both x, and the delay of callLater function to achieve perfect solution. After callLater is called, the UI will be rendered, events will be generated and catched. If you don't need them, remove their listeners, or stop their propagation with a higher priority handler. If you need, I can post some source example of callLater in a loop.
I have a script that relies on ENTER_FRAME event to run every time. I have noticed on some slower computers there can be some lag when a flash movie is playing.
Does ENTER_FRAME run on every frame, even if its on a slow computer?
If the flash movie lags, does the ENTER_FRAME event still run and the rendering just try to catch up?
Is running code on ENTER_FRAME a reliable way to execute code every time a frame is entered?
Yep. Every frame, no exceptions. If something is slowing a movie down (either heavy scripts or heavy graphics), it Event.ENTER_FRAME handlers are still being executed before a frame is rendered.
Hence, it's generally a good idea to use a Timer instance with TimerEvent.TIMER, even if it's delay is set to be equal to 'ideal' frame duration for your movie's fps. Because timer handler is not bound to be triggered at exactly uniform rate.
See the following link for more in-depth explanation: The Elastic Racetrack
if you have a framerate set to 30fps, then the event will fire 30 times per second, as long as you don't put a load on the processor, making the frame rate drop. Therefor, if the framerate is fluctuating, you might get more consistent results with a timer Event.
on a side note, be aware that...
Using many Event handlers can create performance issues too (if you have too many)
Every time it is called, flash has to create an event object at the very least. That means you have memory that needs to be allocated every time the event fires. That memory then needs to be garbage collected at a later time, and the garbage collection will also use resources to execute.
If you have have many movie clips or sprites it could be worthwhile to have one controller that manages all of them, rather than each one having it's own EnterFrame handler.
The general answer to general question.
If you want to improve performance of Flash Player then consider following points,
Do not use strokes unless if it is required. (Strokes are more cpu
intensive)
Use less gradient colors if possible.
Use optimized bitmaps if any.
Make effective use of addChild(yourObject), addChildAt(yourObject, index), removeChild(yourObject), removeChildAt(index).
Listen to Event.ADDED_TO_STAGE and Event.REMOVED_FROM_STAGE
respectively.
Listen to addEventListener(somelistener, somefunction);
removeEventListener(somelistener, somefunction);
Listen to Event.ACTIVATE and Event.DEACTIVATE.
If objects are loaded externally then make sure to use
unloadAndStop() to completely remove unnecessary objects
from
the stage.
Check this out for anyone looking for a framerate independent solution... this guy's really smart and has a technique for both animating consistently across multiple framerates (slower devices, desktops, etc) and keeping your object's framerate independent of your timeline's framerate. Check it out here. Tips 4 & 5. Hope that helps!
I found that the timer class is actually very inconsistent when mashing buttons, sometimes the timer just fails to complete a cycle and the TIMER.COMPLETE event never gets reached, if I had 5 cycles of 100ms, it would just stop after 3 cycles... Also, framerate will fire every frame but IT IS NOT CONSISTENT!!! If you have lag on the CPU, your framerate will drop and hence you will not have anything updating at regular intervals, but rather whatever the current framerate is. Check out that link, there's even some framerate code you can use on your projects to check it.