Running AS3 Function Asynchronously - actionscript-3

I'm having a bit of trouble making sense of some of the tutorials for this online, thus why I'm asking here. (Using ActionScript 3, Adobe AIR, and Flash Professional CS5.5)
I have a very heavy function in my AS3 document class that I need to run asynchronously, so it doesn't stop the code on the MovieClip itself (don't ask me why, it just needs to be that way.)
So, simply put, how do I run this document class function (StartNow) asynchronously? The code can be placed in the document class or on the movieclip, I don't care where. It seems to be a relatively simple and common practice, but all my research is digging up nothing.
Thanks!

If your target is Flash player 11.4, there are Worker objects which can be assigned such a heavy function. I had no FP11, and eventually made a procedural generator that lasted more than 300 seconds per iteration in total. I had to use a state-based approach, paired with an enter frame listener. In my c ase, the entire complex generation process was split into logical chunks that were small enough to be completed within a reasonable timespan, and had a variable tracking the current generation phase. So, when another frame called the generation function, it read last completed step from that variable, performed one extra step with its set of data, stored the new value and exited for the frame. This, as is, is not a pure asynchronous process, but a pseudo-multitasking approach, this can suit you if your function that makes your SWF lag is splittable.

In Flash there is no such thing as run a function asynchronously, you have to do it yourself, unless you want to use Workers (like Vesper said). Workers gives you a separate process. Otherwise, you have to break your calculation into parts. This is how you do it:
Imaging 'trace' is a very heavy operation. It's not, but just to illustrate. This simple for-loop is runned on a frame, and causes a lower framerate, since it's all calculated before the frame actually renders.
for(var i:int = 0; i < 1000; i ++)
{
trace(i); // heavy calculation here
}
So you have to break the calculation into parts, and break it to be able to run the calculation over time.
To do that, you have to create a function which just takes a part of the loop every time:
calculatePart(0, 1000, 20);
function calculatePart(startIndex:int, endIndex:int, amountPerRun:int)
{
for(var i:int = startIndex; (i < startIndex + amountPerRun) || (i < endIndex); i ++)
{
trace(i); // heavy calculation here
}
if (i < endIndex)
{
calculatePart(i, endIndex, amountPerRun);
}
}
This is actually the same function as the simple for-loop in the first code, it also outputs 1000 traces. It is prepared to run in parts, but this isn't async yet. We can now change the function easily, so the function operates over time.
I use the setTimeout for this. You can also use a ENTER_FRAME event-listener or the Timer class for this, but for the sake of this example I try to keep it clear.
calculatePart(0, 1000, 20, 100);
function calculatePart(startIndex:int, endIndex:int, amountPerRun:int, timeBeforeNextRun:Number)
{
for(var i:int = startIndex; (i < startIndex + amountPerRun) && (i < endIndex); i ++)
{
trace(i); // heavy calculation here
}
if (i < endIndex)
{
setTimeout(calculatePart, timeBeforeNextRun, i, endIndex, amountPerRun, timeBeforeNextRun);
}
}
As you can see, I've added a timeBeforeNextRun parameter. If you run the example, you can see it takes 100 milliseconds before 20 traces are outputted.
If you set it very low, the calculation will be tried to be done very fast, however you cannot gain extra speed just by trying to do more in less time of course. You have to play with the time and amount variables, you can test which one actually gives better performance (or less lag).
// more time between a run, less calculations per run
calculatePart(0, 1000, 30, 10);
// more calculations per run, more time between a run
calculatePart(0, 1000, 100, 30);
Hope this helps.
If you want to use a smarter calculation of the time, I found this utility class very helpful, which measures how much time the calculation actually took, and alter the time itself.

Related

Increase Timer interval

I have a timer that calls the function 'bottleCreate' from 500 to 500 miliseconds. But I want that time to increase during the game (getting faster the creation of the bottles, and the game gets more difficult). But I don't know how to increase that variable inside new Timer. Thanks
interval=500;
var my_timer=new Timer(interval);
my_timer.addEventListener(TimerEvent.TIMER, bottleCreate);
my_timer.start();
You want the game to get faster, so the variable needs to decrease, because less time between function calls will make it faster.
According to the Documentation of the Timer Class you can use the delay variable to change the interval speed.
So, to make it faster, you could simply write
my_timer.delay -= 50;
Each time you do this, the function call will be called 50 ms faster.
Be aware though, going beneath 20ms will cause problems, according to the Documentation.
Furthermore, each time you manipulate the delay variable, the timer will restart completely, with the same repeat count you use at initialization.

Array shuffle function not touching last element

I am using this function to shuffle a 4 element array. It shuffles the first 3 elements well, shuffling them randomly, but the last element is only sometimes shuffled around with the other three.
public function shuffleArray(objA:Object, objB:Object):int{
return Math.round(Math.random() * 2) - 1;
}
There's nothing really wrong with it. That's random. As mentioned, the algorithm used for Math.random() makes the difference and I don't believe the AS3 algorithm is especially good.
For testing purposes, I ran it a few times in JS and saw very similar things, where a specific index was the same quite a few times in a row. My results were showing 5-10 times in a row, the one of the indexes would be exactly the same. In a few tests, I saw the exact same result appear 11 times in a row. Running it with a higher maxValue (I tried 15) resulted in a much more random outcome, though it still had the same problems. Interestingly, bumping the iterations up seemed to break the pattern. I noticed it became slightly more random as we got higher in tries (I tried 10k).
var maxValue = 4,
iterations = 100,
a = [];
for (var i = 1; i <= maxValue; i++) {
a.push(i);
}
function shuffle(a, b) {
return Math.round(Math.random() * 2) - 1;
}
for (var i = 0; i < iterations; i++) {
console.log(a.sort(shuffle));
}
http://jsfiddle.net/KA2tf/1/
I did test the same code in Flash (with some minor alterations for AS3, obviously) and saw mostly similar results (to be expected; I believe Flash and JS use very similar algorithms, if not the same one). There's only 24 different combinations a 4 item array can be sorted. You're bound to get repetition.

Flashplayer Gray exclamation error

This was driving me mad for some time, today I manged to reproduce this problem, so one of the causes is division by 0.
e.g.
var end:Number = 1024/0,
size:Number = 1000,
a:Array = [];
for (var i:int=0;i<end;i++){
a.push(size);
}
After dividing by 0 (I don't know how its possible, but anyway) value end becomes Infinity and sneaks into the loop, so flash player stops execution of the script with exclamation mark.
I discovered that when one of the components in flex, after state changes in layout, passed on its width of 0 as one of the parameters to construct the loop. How to avoid this behavior of flex component?
This is expected behavior in most, if not all, languages. I just tested AS3, Javascript, and PHP. AS3 and JS give you Infinity and PHP gives you false (PHP's go-to handler for if there is a low-level error). You should avoid dividing by 0 at all costs because it simply is not possible. Most languages do not want to prevent a user from dividing by 0, since Infinity is an actual value and the correct value of dividing by 0, which is why they allow it.
Your error is because you are using Infinity as your loop check, which will never be reached in your loop.
Instead, use a conditional to handle the possibility of the value being 0. So something like:
function calculateRatio(x:Number, y:Number):Number {
if (y == 0) {
return 1; // or whatever to indicate an error
}
return x / y;
}
or
function calculateRatio(x:Number, y:Number):Number {
return x / (y == 0 ? 1 : y); // the value is still calculated, just makes sure y is not 0 at all times
}
Just make sure any time you perform division, you never divide by 0. In your case, your loop is running an infinite number of times. Flash is single-threaded and will actually freeze completely while any script execution is happening. Generally, this happens so quickly that the end-user doesn't notice it but in your case, it will freeze until the end of time. Fortunately, Flash will end script execution at 15s or 30s, depending on runtime version so it should error out at some point.
Division by 0 is not a problem as such here, 0 is passed as a parameter, as a result of other operations at run-time, and I can not be sure, that 0 will not be passed as parameter.
What's boggling my mind is that division by 0 should be flagged in the first place, but it isn't. Then gets result of infinity, ok from mathematical point of view, but then I get infinite loop. I would normally expect that executing the script longer than e.g. 15 sec. throw an error and the script stops, but instead what I have is exclamation sign without any information for the developer, and that sucks..

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).

for-loop mechanism efficiency tips

As I am using for-loops on large multi-dim arrays, any saving on the for-loop mechanism itself is meaningful.
Accordingly, I am looking for any tips on how to reduce this overhead.
e.g. : counting down using uint instead of int and != 0 as stop instead of >0 allows the CPU to do less work (heard it once, not sure it is always true)
One important suggestion: move as much calculation to the outer loop as possible. Not all compilers can do that automatically. For eample, instead of:
for row = 0 to 999
for col = 0 to 999
cell[row*1000+col] = row * 7 + col
use:
for row = 0 to 999
x = row * 1000
y = row * 7
for col = 0 to 999
cell[x+col] = y + col
Try to make your loops contiguous in memory, this will optimize cache usage. That is, don't do this:
for (int i = 0; i < m; i++)
for (j = 0; j < n; j++)
s += arr[j][i];
If processing images, convert two loops to one loop on the pixels with a single index.
Don't make loops that will run zero times, as the pipeline is optimized to assume a loop will continue rather than end.
Have you measured the overhead? Do you know how much time is spent processing the for loops vs. how much time is spent executing your application code? What is your goal?
Loop-unrolling can be one way. That is:
for (i=0; i<N; i++) {
a[i]=...;
}
transforms into:
for (i=0; i<N; i+=4) {
a[i]=...;
a[i+1]=...;
a[i+2]=...;
a[i+3]=...;
}
You will need special handling when N is not a multiple of 4 in the example above.
First, don't sweat the small stuff. Details like counting up versus counting down are usually completely irrelevant in running time. Humans are notoriously bad at spotting areas in code that need to be sped up. Use a profiler. Pay little or no attention to any part of the loop that is not repeated, unless the profiler says otherwise. Remember that what is written in an inner loop is not necessarily executed in an inner loop, as modern compilers are pretty smart about avoiding unnecessary repetition.
That being said, be very wary of unrolling loops on modern CPUs. The tighter they are, the better they will fit into cache. In a high-performance application I worked on last year, I improved performance significantly by using loops instead of straight-line code, and tightening them up as much as I could. (Yes, I profiled; the function in question took up 80% of the run time. I also benchmarked times over typical input, so I knew the changes helped.)
Moreover, there's no harm in developing habits that favor efficient code. In C++, you should get in the habit of using pre-increment (++i) rather than post-increment (i++) to increment loop variables. It usually doesn't matter, but can make a significant difference, it doesn't make code less readable or writable, and won't hurt.
This isn't a language agnostic question, it depends highly on not only language, but also compiler. Most compilers I believe will compile these two equivalently:
for (int i = 0; i < 10; i++) { /* ... */ }
int i = 0;
while (i < 10) {
// ...
i++;
}
In most languages/compilers, the for loop is just syntactic sugar for the later while loop. Foreach is another question again, and is highly dependant on language/compiler as to how it's implemented, but it's generally less efficient that a normal for/while loop. How much more so is again, language and compiler dependant.
Your best bet would probably be to run some benchmarks with several different variations on a theme and see what comes out on top.
Edit: To that end, the suggestions here will probably save you more time rather than worrying about the loop itself.
BTW, unless you need post-increment, you should always use the pre-increment operator. It is only a minor difference, but it is more efficient.
Internally this is the difference:
Post Increment
i++;
is the same as:
int postincrement( int &i )
{
int itmp = i;
i = i + 1;
return itmp;
}
Pre Increment
++i;
is the same as:
int preincrement( int &i )
{
i = i + 1;
return i;
}
I agree with #Greg. First thing you need to do is put some benchmarking in place. There will be little point optimising anything until you prove where all your processing time is being spent. "Premature optimisation is the root of all evil"!
As your loops will have O(n^d) complexity (d=dimension), what really counts is what you put INTO the loop, not the loop itself. Optimizing a few cycles away in the loop framework from millions of cycles of an inefficient algorithm inside the loop is just snake oil.
By the way, is it good to use short instead of int in for-loop if Int16 capacity is guaranteed to be enough?
There is not enough information to answer your question accurately. What are you doing inside your loops? Does the calculation in one iteration depend on a value calculated in a previous iteration. If not, you can almost cut your time in half by simply using 2 threads, assuming you have at least a dual core processor.
Another thing to look at is how you are accessing your data, if you are doing large array processing, to make sure that you access the data sequentially as it is stored in memory, avoiding flushing your L1/L2 cache on every iteration (seen this before on smaller L1 caches, the difference can be dramatic).
Again, I would look at what is inside the loop first, where most of the gains (>99%) will be, rather than the outer loop plumbing.
But then again, if your loop code is I/O bound, then any time spent on optimization is wasted.
I think most compilers would probably do this anyway, stepping down to zero should be more efficient, as a check for zero is very fast for the processor. Again though, any compiler worth it's weight would do this with most loops anyway. You need to loo at what the compiler is doing.
There is some relevant information among the answers to another stackoverflow question, how cache memory works. I found the paper by Ulrich Drepper referred to in this answer especially useful.