building animation in flex - apache-flex

I am trying to build animation based on mathematical formulae(speed varying with time as per equations)- hence am charting x,y coordinates with formulae on user provider values, rather than inbuilt functions
In doing that, am struggling to get the timer right. for e.g if I set
timer=new timer(1),
object.x=object.x+1
the object doesn't zoom past screen within a second (or 600 milliseconds)- takes closer to 6-7 second to cover the 600 odd pixels. presume screen update doesnt work as fast as timer ticks
Is there a way for me to set up, such that I can predict speed on screen so animation takes abt 30 seconds?

Its better to use ENTER_FRAME listener and do animation there, based on current time (getTimer()).
Update: see getTimer() docs:
http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/flash/utils/package.html#getTimer%28%29
Note the time when animation started. On each frame, subtract start time from current time. You get number of milliseconds passed. Compute coordinates/colors/rotations based on that number.

Related

Averaging when events are slower than measurement time

I'm trying to come up with a better way of providing an instantaneous average when input signal is very slow. This seems like a math-y kinda question so if it should be over there let me know.
I have events that are measured as a pulse. Normally I can collect the pulses in a counter and then read the counter value at a fixed interval, say 1/4 second. I can then take the count value and divide by the number of seconds so n/0.25 and get a rate. I then apply a low pass filter to clean up the average and that works great normally.
What do I do when the events happen once every 1-60 seconds? The obvious choice is to wait until I have a sufficient number of counts and divide by total time. However, I need to provide the user with a reading every few seconds so waiting is not an option. I need some way to estimate the value.
I've thought of one solution that's kinda hard to explain. I was wondering if there was a standard way of doing this. I'm pretty sure I have to utilize a different kind of "data," the lack of an event. The goal is to estimate until enough time/events have passed to really calculate a rate and to transition from estimate to real rate seamlessly.

Problems with the Enterframe Event

I have been developing a game using Flex, and used the Timer class to keep the main loop going.
However, when I tried using the enterFrame event to do the main loop, there were a few problems.
First of all, physics simulation seemed way too fast. Is the enterFrame event called more than once per frame? I set the application's global frame rate to 24, so shouldn't the application set off the event every 1/24 of a second?
And the second problem is that when the game runs like this, some MXML components that are added are not shown. I have absolutely no idea why this happens.
Help me please?!?
Thanks.
Don't count on the framerate to be even, or that the enterframe is called at a fixed interval. Even the timer-class isn't 100% accurate.
When doing timings, always use the delta between frame-updates and use that delta for your calculations. Also be sure to put in a safe-guard that the delta never exceeds some value to avoid strange behavior when the flash application freezes up for some unexpected reason.
This article explains it all perfectly:
http://gafferongames.com/game-physics/fix-your-timestep/
The framerate is a desired value. If a user runs it on a slow machine, you might experience their output to be too slow. How about reverting to the good old
setInterval?

How to get IMediaControl.Run() to start a file playing with no delay

I am attempting to use DirectShow to play two AVI files consecutively (one after the other) so that there is no interruption in the audio or video when the player transitions from one file to the next.
I have two custom controls on my form. Each one is pre-loaded with an AVI file, and before playback begins I set up all the DirectShow interfaces, set the video windows and resize them, call IMediaControl.Run(), then IMediaControl.Pause(), then IMediaSeeking.SetPositions to reset to frame 0, on both controls. On the form, you can see that both files are paused at their initial frames.
I then call IMediaControl.Run() on the first control, and wait for it to complete before calling Run() on the second control. Initially, I hooked into the first video's EC_COMPLETE notification message, and used this to start the second. Thinking that this event might be slow to arrive (turns out it is, but for a weird reason), I tried two other approaches:
Check the first video's current position inside a timer that goes off every second or so (using IMediaPosition.get_CurrentPosition). When the current position is within a second of the video's stop time (known in advance from IMediaPosition.get_StopTime), I go into a tight while loop and wait for the current position to equal the stop time, and then call Run() on the second video.
Same as the first, except I replace the while loop with a call to timeSetEvent from winmm.dll, with a delay set so that it fires right when the first file is supposed to end. I use the callback to Run() the second file.
Either of these two methods substantially cuts down the delay between the end of the first file and the beginning of the second, indicating that the EC_COMPLETE message doesn't arrive immediately after the file is complete (I also tried hooking the EC_SEGMENT_COMPLETE message, which is supposed to be used for looping within a file, but apparently nobody supports this - it never occurs on my machine, at least).
Doing all of the above has cut the transition delay from as much as a second, down to a barely perceptible glitch; about a third of the time the files transition with no interruption at all, which suggests there's no fundamental reason I can't get this to work all the time.
The slight delay is still unacceptable, unfortunately. I assume (and I could easily be wrong) that the remaining delay is due to a slight variable delay between the call to IMediaControl.Run() and when the video actually starts playing.
Does anybody know anything I can do to eliminate this little lag? It would also help to be told this is fundamentally impossible for whatever reason, which wouldn't surprise me. I've never encountered a video player in Windows that doesn't have this problem, so it may not be doable.
More info: the AVI files I'm playing are completely uncompressed (video and audio are uncompressed), so I don't think the lag is due to DirectShow's having to uncompress the video ahead of play start, although it may still buffer ahead as matter of course (and this may be the source of the problem). I would have though that starting play, pausing and then rewinding to the beginning would fix this.
Also, the way I'm handling the transition is to actually have the second control underneath the first; when the first completes playing, I start the second and then call BringToFront on it, creating the appearance of a single video transitioning between the two originals. I don't think the glitch is due to this, because it works perfectly some of the time, and even if this were problematic, it wouldn't explain the matching audio glitch.
Even more: I just tried starting the second video 30-50 milliseconds "early" and that seemed to eliminate even more of the gap, so I'm guessing that the lag in Run() is about that long. It appears to be variable, though, so this is still not where I need it to be.
Still more: perhaps I could eliminate this delay by loading the AVIs from memory rather than from a file. Unfortunately, I have no idea how to do this. IMediaControl only has a RenderFile() method, not something like a RenderStream or RenderMemory method.
If you call IMediaControl::Run on a stopped graph, the graph manager will post the call to a worker thread (so there's some variability). On the worker thread, the graph will be paused. Render filters only complete a pause transition once they have received data, so once GetState() returns S_OK, the graph manager knows that the graph is fully cued. At this point, it picks a time roughly 10ms into the future, and calls Run on each filter with that time as the start point. Since it takes time to tell each filter to Run, the dshow Run method has a parameter which is the refclock time at which a sample timestamped zero should be played -- i.e. the time at which the actual transition to run mode should take place.
To synchronise this with another graph, you first have to ensure that both graphs have the same clock. Query the graph (not the filter) for IMediaFilter, and call GetSyncSource on one graph and SetSyncSource on the other. Then you need to pause the second graph, so that it is cued and ready. When you want to start it, call IMediaFilter::Run instead of IMediaControl::Run, and you can pass your own start time. This still has to be a few milliseconds into the future, so the best thing might be to set the start time of the second graph to be the first graph's start time plus its duration (for an indexed container of uncompressed streams, the duration should be accurate).
Another approach is to use multiple graphs. Separating source from rendering would allow you to switch seamlessly between sources since they feed into a common render graph. There is sample source code for this approach at www.gdcl.co.uk/gmfbridge.
G

AS3: How accurate are the getTimer() method and the Timer class?

I'm in the process of making a game (a shmup) and I've started to question the accuracy of the timers in ActionScript. Sure, they're accurate enough when you want to time things on the order of a few seconds or deciseconds, but it seems to perform pretty poorly when you get to finer ranges. This makes it pretty tough to do things like have a spaceship firing a hundred lasers per second.
In the following sample, I tested how long (on average) the intervals were between 1000 timer ticks intended for 30ms. Time and time again, the results are ~35-36ms. Decreasing the time, I found the floor on the timer delay to be ~16-17ms. This gives me a max fps of ~60, which is great visually but also means I can't possibly fire more than 60 lasers per second :-(. I ran this test a few times at 100 and 1000 loops, but for both the 30ms test and the 1ms test the results didn't change. I print to a textField at the end because using trace() and launching the swf in debug mode seems to negatively affect the test. So what I'm wondering is:
Is this test a decent measure of the Timer class's performance, or are my results questionable?
Will these results change dramatically on other machines?
I understand this is dependent on the getTimer() method's accuracy, but the discussions I find on this topic usually center around getTimer()'s accuracy on larger intervals.
package
{
import flash.display.Sprite;
import flash.events.TimerEvent;
import flash.text.TextField;
import flash.utils.getTimer;
import flash.utils.Timer;
public class testTimerClass extends Sprite
{
private var testTimer:Timer = new Timer(30, 1000);
private var testTimes:Array = new Array();
private var testSum:int = 0;
private var testAvg:Number;
private var lastTime:int;
private var thisTime:int;
public function testTimerClass()
{
testTimer.addEventListener(TimerEvent.TIMER, step);
testTimer.addEventListener(TimerEvent.TIMER_COMPLETE, printResults);
lastTime = getTimer();
testTimer.start();
}
private function step(event:TimerEvent):void
{
thisTime = getTimer();
testTimes.push(thisTime - lastTime);
lastTime = thisTime;
}
private function printResults(event:TimerEvent):void
{
while (testTimes.length > 0)
{
testSum += testTimes.pop();
}
testAvg = testSum / Number(testTimer.repeatCount);
var txtTestResults:TextField = new TextField();
txtTestResults.text = testAvg.toString();
this.addChild(txtTestResults);
}
}
}
I guess the best route to take would be to just draw multiple lasers in the same frame with different positions and avoid having more than one Timer object.
edit: I used stage.frameRate to change the render frameRate and ran the test on several framerates but there was no change.
Tinic Uro (Flash Player engineer) has written an interesting blog post about this issue some time ago.
Intead of using the timer class at all, I would put my update code in and enterframe eventlistener.
Then use getTimer(), to find out how much time has passed since last update, and then a bit of bit of math to calculate movement, laser "spawning" etc. This way the game should perform the same no matter if you getting 60FPS or 10FPS.
This also prevents weird game behavior if the the FPS drop temporary, or if the game is running on a slow machine.
For the most part the math is pretty simple, and when it is not, you can usually "cut corners" and still get a result good enough for a game.
For simple movement you can simply multiply movement offset with time since last update. For acceleration, you need a second degree equation, but could simplify be multiplying again.
In response to jorelli comment below:
The collision detection problem can be solved by better code, that does not just check the current state, but also what happened between the previous state and the current.
I've never had problems with the keyboard. Maybe you should try this nifty little class:
http://www.bigroom.co.uk/blog/polling-the-keyboard-in-actionscript-3
I just tried running your sample code, exactly as-is except as a frame script, and where I'm sitting Timer works exactly as you'd expect. With a 30ms timer, the average comes out about 33-34, and with a 3ms timer it comes out around 3.4 or 3.5. With a 1 ms timer I get between 1.4 and 1.6 over a thousand trials. It works that way in Flash and in the browser.
So as for the accuracy, see Tinic's blog post in Luke's answer. But for the upper limit on frequency, if you're getting events no faster than 16ms apart with only the sample code you posted, either something's weird, or maybe that's the upper limit on how fast your browser is giving Flash timing messages. If you're getting those results in your actual game, I think you simply have synchronous code that blocking the timer events.
One more thing - I know it's not what you asked, but it would really be wiser to handle your game logic in an ENTER_FRAME handler. It doesn't matter whether the code to spawn lasers runs every 30ms or every 3ms, the screen only gets redrawn once per frame (unless you're forcing it to update more often, which you probably shouldn't be). So whatever happens between screen refreshes is just overhead that lowers your overall framerate, since with a little cleverness it ought to be possible to achieve the exact same results as you'd get from a timer that executed more frequently. For example, instead of spawning a laser every 3ms, you could spawn 10 lasers every 30ms, and move each one a certain distance along its flight path, as if it had been created 3 or 6 or 9ms earlier.
Another natural way to run your logic off frame events would be to make a game loop that "theoretically" runs every T milliseconds. Then, in your ENTER_FRAME handler, simply iterate that loop F/T times, where F is the number of ms that have elapsed since the last frame event. Thus if you want the game to theoretically update every 5ms, and you want the screen to update at 30FPS, you'd simply publish at 30FPS, and in your ENTER_FRAME handler you'd call your main game loop 5-7 times consecutively, depending on how long it had been since the last frame. Onscreen, this will give you the same results as if you had used a 5ms timer event, and it will dispense with much of the overhead.
BitmapData.scroll and BitmapData.copyPixels are the fastest way to render in flash right now, although on a few systems, using movieclips with gpu acceleration is slightly faster. Each quad is rendered as a separate texture in OpenGL, so its not what you'd expect from an ordinary GPU accelerated application. I know, because I profiled both ways in my game. One thing that you can do to improve response time is to call your game update from the input event handlers. That way, you hear correctly timed sounds even when your game's framerate is lower, and the application will feel more responsive.
This gives me a max fps of ~60, which is great visually but also means I can't possibly fire more than 60 lasers per second :-(
I would say you are very lucky to be getting that kind of FPS as it is, and the majority of your users (assuming your audience is the internet at large) will more than likely not be achieving that kind of framerate.
I would agree that the abilities of the flash player are probably not sufficient for what you are trying to achieve.

Is it a bad idea to implement a timer loop in Flex?

In our game project we did have a timer loop set to fire about 20 times a second (the same as the application framerate). We use this to move some sprites around.
I'm wondering if this could cause problems and we should instead do our updates using an EnterFrame event handler?
I get the impression that having a timer loop run faster than the application framerate is likely to cause problems... is this the case?
As an update, trying to do it on EnterFrame caused very weird problems. Instead of a frame every 75ms, suddenly it jumped to 25ms. Note, it wasn't just our calculation claimed the framerate was different, suddenly the animations sped up to a crazy rate.
I'd go for the Enter frame, in some special cases it can be useful to have two "loops" one for logic and one for the visuals, but for most games I make I stick to the Enter frame-event listener. Having a separate timer for moving your stuff around is a bit unnecessary since having it set to anything except the framerate would make the motion either jerky or just not visible (since the frame is not redrawn).
One thing to consider however is to decouple your logic from the framerate, this is most easily accomplished by using getTimer (available in both as2 and as3) to calculate the time that has expired since the last frame and adjusting the motions or whatever accordingly.
A timer is no more reliable than the enter frame event, flash will try to keep up with whatever rate you've set, but if you're doing heavy processing or complex graphics it will slow down, both timers and framerate.
Here's a rundown of how Flash handles framerates and why you saw your content play faster.
At the deepest level, whatever host application that Flash is running in (the browser usually) polls flash at some interval. That interval might be every 10ms in one browser, or 50ms in another. Every time time that poll occurs, Flash does something like this:
Have (1000/framerate) miliseconds passed since the last frame update?
If no: do nothing and return
If yes: Execute a frame update:
Advance all (playing) timelines one frame
Dispatch all events (including an ENTER_FRAME event
Execute all frame scripts and event handlers with pending events
Draw screen updates
return
However, certain kinds of external events (such as keypresses, mouse events, and timer events) are handled asynchronously to the above process. So if you have an event handler that fires when a key is pressed, the code in that handler might be executed several times between frame updates. The screen will still only be redrawn once per frame update, unless you use the updateAfterEvent() method (global in AS2, attached to events in AS3).
Note that the asynchronous behavior of these events does not affect the timing of frame updates. Even if you use timer events to, for example, redraw the screen 50 times per second, frame animations will still occur at the published framerate, and scripted animations will not execute any faster if they're driven by the enterFrame event (rather than the timer).
The nice thing about using enter frame events, is your processing will degrade at the same pace as the rendering and you'll get a screen update right after the code block finishes.
Either method isn't guaranteed to occur at a specific time interval. So your event handler should be determining how long it's been since it last executed, and making decisions off of that instead of purely how many times it's run.
I think timerEvent and Enter Frame are both good options, I have used both of them in my games. ( Did you mean timerEvent by timer loop? )
PS: notice that in slow machines the timer may not refresh quick enough, so you may need to adjust your code to make game work "faster" in slow machines.
I would suggest using a class such as TweenLite ( http://blog.greensock.com/tweenliteas3/ ) which is lightweight at about 3kb or if you need more power you can use TweenMax, which i believe is 11kb. There are many advantages here. First off, this "engine" has been thoroughly tested and benchmarked and is well known as one of the most resource friendly ways to animate few or even many things. I have seen a benchmark, where in AS3, 1,500 sprites are being animated with TweenLite and it holds a strong 20 fps, as where competitors like Tweener would bog down to 9 fps http://blog.greensock.com/tweening-speed-test/. The next advantage is the ease of use as I will demonstrate below.
//Make sure you have a class path pointed at a folder that contains the following.
import gs.TweenLite;
import gs.easing.*;
var ball_mc:MovieClip = new MovieClip();
var g:Graphics = ball_mc.graphics;
g.beginFill(0xFF0000,1);
g.drawCircle(0,0,10);
g.endFill();
//Now we animate ball_mc
//Example: TweenLite.to(displayObjectName, totalTweeningTime, {someProperty:someValue,anotherProperty:anotherValue,onComplete:aFunctionCalledWhenComplete});
TweenLite.to(ball_mc, 1,{x:400,alpha:0.5});
So this takes ball_mc and moves it to 400 from its current position on the x axis and during that same Tween it reduces or increases the alpha from its current value to 0.5.
After importing the needed class, it is really only 1 line of code to animate each object, which is really nice. We can a also affect the ease, which I believe by default is Expo.easeOut(Strong easeOut). If you wanted it to bounce or be elastic such effects are available just by adding a property to the object as follows.
TweenLite.to(ball_mc, 1,{x:400,alpha:0.5,ease:Bounce.easeOut});
TweenLite.to(ball_mc, 1,{x:400,alpha:0.5,ease:Elastic.easeOut});
The easing all comes from the gs.easing.* import which I believe is Penner's Easing Equations utilized through TweenLite.
In the end we have no polling (Open loops) to manage such as Timer and we have very readable code that can be amended or removed with ease.
It is also important to note that TweenLite and TweenMax offer far more than I have displayed here and it is safe to say that I use one of the two classes in every single project. The animations are custom, they have functionality attached to them (onComplete: functionCall), and again, they are optimal and resource friendly.

Resources