AS3 - stop onEnterFrame Function from constantly running - actionscript-3

Okay, I have a collisionTest function that is tied to my "onEnterFrameHandler" function.
So to simplify the way it looks:
onEnterFrameHandler(e:Event):void{
testCollision();
}
testCollision():void{
trace("always running");
if(1_MC.hitTestObject(2_MC)){
//do stuff
}
}
The thing is, it is always running. Constantly running in order to test for a collision. I have a feeling that it is what may be causing the lag on this project.
Do you know of a good way to control a function that needs to be able to check, at any time, an event, yet not run while the even is not occurring?

Usually you are always checking for collisions in a game loop. You provide a flag to indicate if something needs to be checked or not.
On a side note, consider using collision detection kit, I think you'll find it takes care of just about every scenario you can have regarding collisions.

It's hard to answer this question as it is pretty vague when you're not checking for collision. To improve the performance it's not about changing how to collision test, but when to do the check.
so you could do this by simply adding an if statement like so:
if (doCollisionTest){testCollision();}
but that doesn't solve when doCollisionTest is true or false, and that's the tricky part, that cannot be answered from the information you provided.

If you don't need to check every single frame, you can use a Timer to only check as often as you like, for instance, if you deemed it good enough to check 3 times per second, you'd set it up like this:
var timer:Timer = new Timer(333); //run 3 times a second
timer.addEventListneer(TimerEvent.TIMER, collisionTest, false, 0, true);
timer.start();
function collisionTest(e:Event = null):void {
//do you collision stuffs
}
Then, if for whatever reason you want to temporarily disable it, use timer.stop() , then timer.start() again

Related

Nesting Asynchronous Promises in ActionScript

I have a situation where I need to perform dependent asynchronous operations. For example, check the database for data, if there is data, perform a database write (insert/update), if not continue without doing anything. I have written myself a promise based database API using promise-as3. Any database operation returns a promise that is resolved with the data of a read query, or with the Result object(s) of a write query. I do the following to nest promises and create one point of resolution or rejection for the entire 'initialize' operation.
public function initializeTable():Promise
{
var dfd:Deferred = new Deferred();
select("SELECT * FROM table").then(tableDefaults).then(resolveDeferred(dfd)).otherwise(errorHandler(dfd));
return dfd.promise;
}
public function tableDefaults(data:Array):Promise
{
if(!data || !data.length)
{
//defaultParams is an Object of table default fields/values.
return insert("table", defaultParams);
} else
{
var resolved:Deferred = new Deferred();
resolved.resolve(null);
return resolved.promise;
}
}
public function resolveDeferred(deferred:Deferred):Function
{
return function resolver(value:*=null):void
{
deferred.resolve(value);
}
}
public function rejectDeferred(deferred:Deferred):Function
{
return function rejector(reason:*=null):void
{
deferred.reject(reason);
}
}
My main questions:
Are there any performance issues that will arise from this? Memory leaks etc.? I've read that function variables perform poorly, but I don't see another way to nest operations so logically.
Would it be better to have say a global resolved instance that is created and resolved only once, but returned whenever we need an 'empty' promise?
EDIT:
I'm removing question 3 (Is there a better way to do this??), as it seems to be leading to opinions on the nature of promises in asynchronous programming. I meant better in the scope of promises, not asynchronicity in general. Assume you have to use this promise based API for the sake of the question.
I usually don't write those kind of opinion based answers, but here it's pretty important. Promises in AS3 = THE ROOTS OF ALL EVIL :) And I'll explain you why..
First, as BotMaster said - it's weakly typed. What this means is that you don't use AS3 properly. And the only reason this is possible is because of backwards compatibility. The true here is, that Adobe have spent thousands of times so that they can turn AS3 into strongly type OOP language. Don't stray away from that.
The second point is that Promises, at first place, are created so that poor developers can actually start doing some job in JavaScript. This is not a new design pattern or something. Actually, it has no real benefits if you know how to structure your code properly. The thing that Promises help the most, is avoiding the so called Wall of Hell. But there are other ways to fix this in a natural manner (the very very basic thing is not to write functions within functions, but on the same level, and simply check the passed result).
The most important here is the nature of Promises. Very few people know what they actually do behind the scenes. Because of the nature of JavaScript (and ECMA script at all), there is no real way to tell if a function completed properly or not. If you return false / null / undefined - they are all regular return values. The only way they could actually say "this operation failed" is by throwing an error. So every promisified method, can potentially throw an error. And each error must be handled, or otherwise your code can stop working properly. What this means, is that every single action inside Promise is within try-catch block! Every time you do absolutely basic stuff, you wrap it in try-catch. Even this block of yours:
else
{
var resolved:Deferred = new Deferred();
resolved.resolve(null);
return resolved.promise;
}
In a "regular" way, you would simply use else { return null }. But now, you create tons of objects, resolvers, rejectors, and finally - you try-catch this block.
I cannot stress more on this, but I think you are getting the point. Try-catch is extremely slow! I understand that this is not a big problem in such a simple case like the one I just mentioned, but imagine you are doing it more and on more heavy methods. You are just doing extremely slow operations, for what? Because you can write lame code and just enjoy it..
The last thing to say - there are plenty of ways to use asynchronous operations and make them work one after another. Just by googling as3 function queue I found a few. Not to say that the event-based system is so flexible, and there are even alternatives to it (using callbacks). You've got it all in your hands, and you turn to something that is created because lacking proper ways to do it otherwise.
So my sincere advise as a person worked with Flash for a decade, doing casino games in big teams, would be - don't ever try using promises in AS3. Good luck!
var dfd:Deferred = new Deferred();
select("SELECT * FROM table").then(tableDefaults).then(resolveDeferred(dfd)).otherwise(errorHandler(dfd));
return dfd.promise;
This is the The Forgotten Promise antipattern. It can instead be written as:
return select("SELECT * FROM table").then(tableDefaults);
This removes the need for the resolveDeferred and rejectDeferred functions.
var resolved:Deferred = new Deferred();
resolved.resolve(null);
return resolved.promise;
I would either extract this to another function, or use Promise.when(null). A global instance wouldn't work because it would mean than the result handlers from one call can be called for a different one.

Array and EnterFrame eventlistener

I have a problem that I hope you can help me resolve. I made that code:
var dates_array:Array =[y1,y2,y3];
var i= 1;
for each(var dates_sym:MovieClip in dates_array){
dates_sym.visible=false;
};
france_map.addEventListener(Event.ENTER_FRAME, fnCheckDate);
function fnCheckDate (evt:Event):void{
var i = france_map.currentFrame;
}
function fnDateSym (evt:Event):void{
dates_array[i].visible=true;
}
It is supposed to make a symbol (y1, y2 or y3 (there are more symbols, but didn't put them in the code for clarity) appear depending on what frame the main symbol is. When I compil, it shows no errors, but when I try it in my app, nothing happens.
I'm still a beginner, and I really don't see what's wrong.
If you need more context I can give it. Thanks in advance.
Jeryl
Your fnCheckDate function is called on enter frame, but that function never does anything except setting i. The other function - fnDateSym - sets the visible property based on the value of i. Which is what you want - but fnDateSym is never called anywhere in your posted code.
That may just be because you've left out some code. I'm guessing you might be calling fnDateSym from elsewhere and expect it to use the global i, as set by fnCheckDate. And yes, it will use the global i. But fnCheckDate doesn't set the global i:
var i = france_map.currentFrame;
The var keyword declares a variable within the current scope. A function creates a new scope. In other words, you're declaring a variable i local to your function and assigning the currentFrame value to that - rather than to the already existing variable i in the global scope (var i = 1). When your function exits, the local i is "lost" - and the global i hasn't changed - it will still be 1.
So the quick fix is to simply change it to:
i = france_map.currentFrame;
Now you're not declaring a new variable, but rather setting the value of your global i variable.
ETA: A bit of "teaching you how to fish rather than giving you a fish"... An easy way to debug these kinds of issues is to check the value of your variables using the trace function. For example:
function fnDateSym (evt:Event):void
{
trace("i is:", i);
dates_array[i].visible=true;
}
Now, if you don't see any traces in the output window that means your function isn't called at all. If you constantly see "i is: 1" then you know that i doesn't change and that this is the root of the problem. You could just use trace(i) - I just tend to add some kind of text to the trace - makes it easier to tell what each line in the output is, when you have more traces.
Unrelated, just a bit of code review...
Note that ENTER_FRAME is triggered on every frame refresh. I.e., it doesn't mean "when I enter a new frame on the timeline". It simply means, "when a frame is drawn in the player". In other words, it's called 24 times per second - or whatever frame rate you've chosen in Flash - no matter if currentFrame doesn't change (e.g. because you've called france_map.stop()).
This may be fine in your case - after all, setting visible to true 24 times per second doesn't actually cause any side effects. If you're doing more than that, however, it may be wasteful - or it may cause unexpected issues, since it's called more often than you really want.
One way to make something similar to a "enter timeline frame" event would be:
var previousFrame:int; // used for storing the last currentFrame we encountered
mc.addEventListener(Event.ENTER_FRAME, enterFrameListener);
function enterFrameListener(event:Event):void
{
// Are we on a different frame than last time?
if (previousFrame != mc.currentFrame)
{
currentFrameChanged();
previousFrame = mc.currentFrame;
}
}
function currentFrameChanged()
{
// Do stuff that should be done when the current frame changes
// - rather than on every frame refresh.
}
It's hard to tell exactly how you're doing things (again, because it seems a call to fnDateSym is left out) - but depending on how fnDateSym is called, mostly you wouldn't need fnCheckDate at all. Just do:
dates_array[france_map.currentFrame] = true;
Other than that, just for "niceness", you may want to declare the type for i:
var i:int = 0;

Actionscript 3.0, using FlashDevelop: local variables. Can they be mistakenly created ad infinitum?

Riddle me this: I have my MouseEvent.MOUSE_DOWN which calls mouseHandler. The latter looks something like this:
public function mouseHandler(evt:MouseEvent):void
{
var p:Point = new Point(mouseX, mouseY);
var objs:Array = new Array(getObjectsUnderPoint(p));
}
Now what I want to know is thusly: will the objs array and p point be overwritten every time, simply causing the previous objs array and p point to be wiped and a new one generated, or...does it just create a new array and point over and over and over? Of course if I trace(objs) it gives me the expected results, but am I chocking up the system in the background without realising? Your expertise would be appreciated.
EDIT: well after learning a fair bit from the answerers -thanks btw- that made me think of something else and, a quick search later, found a way to theoretically reliably remove the references:
var a = null;
Now I appreciate that this is probably not needed as they'll be GCed at the end of the function, but considering it takes two ticks to write, better safe than sorry, no?
It works like this from what I understand - references for these variables will be lost after function will end. The values will be GC'ed then eventually.
If you will call the function second time, the new references will be created, and filled with new data, the values of previous references hovewer, may still exist in memory, and wait for Garbage Collector, but that may not necessarily happen! If they have attached listeners, the Flash Player will think that they are still useful, so they will exist in the memory to the end of the application run and listen, and even react to events - even if you theoretically cannot access them anymore.
Edit:
In your case whats happening is that you are creating two references that will disappear at the end of the function. They are not related to event listener, the listener creates them, but is not attached to them so it won't stop GC from collecting them after function will end. You creates an array of references, but that are just references to other objects that values are referred in other places (like the display list), if the array alone is not referred anywhere outside of this function, it should be GCted.
Since p is an object, not a primitive, the memory allocation for it will come from the Heap (and therefore need to be garbage collected) instead of the stack like local primitives (and are wiped once the function ends.
So new memory will be allocated every time this function is called, which will temporarily increase memory usage until they get GC'd, but the amount is probably insignificant (assuming that array isn't massive!).

Does addEventListener (and removeEventListener) stack?

Given the below:
object.addEventListen(eventType01,handler01);
object.addEventListen(eventType01,handler01);
object.removeEventListener(eventType01,handler01);
How many event listeners for eventType01 are on object? One or zero?
Zero. If you call addEventListener, using the exact same arguments more than once all subsequent calls after the first "silently fail." Call add as many times as you want, but that single remove will wipe the listener away.
EDIT: Another thing to keep in mind is that there's no penalty to calling multiple identical removeEventListener() functions on the same object, aside from needless performance overhead. No deadly error will occur, it will simply "silently fail" much the same way as repeated identical addEventListener calls will.
EDIT 2: To answer #ThomasM :: if your listener "fires twice" then you do not have exactly the same listener. Try putting this quick and dirty code on frame 1 in a fla that has one square movieclip as a child:
import flash.events.*
function foo(e):void{
trace("hi");
}
this.addEventListener(MouseEvent.CLICK,foo);
this.addEventListener(MouseEvent.CLICK,foo);
this.addEventListener(MouseEvent.CLICK,foo);
Notice that your output when you click the movieclip is precisely one trace action.
Now add this line to the end of the code
this.removeEventListener(MouseEvent.CLICK,foo);
Even though you added foo as a listener for click 3 times, this one call kills the listener completely.
So if you're experiencing an issue where "the same listener" fire twice then probably what you're doing is something like this:
this.addEventListener(MouseEvent.CLICK, function(e){
trace("hi");
});
this.addEventListener(MouseEvent.CLICK, function(e){
trace("hi");
});
That will definitely "fire twice" because the listener functions ARE NOT THE SAME. They perform the same actions but they do not reference identical positions in memory. They do not point to the same function object. Furthermore this is highly bad practice because you have no way to actually remove those listeners. How would you do it? You have no reference to them.

AS3: Run methods in an ordered sequence

I have a class with several methods I must run in an specific order. So, I created a kind of chain where each one calls the next in its last sentence (sometimes with calls, sometimes dispatching events):
internal function a(evt:SwapEvent):void { //started from custom event
...
b();
}
private function b():void {
...
bTimer = new Timer(bTime*1000,1);
bTimer.addEventListener(TimerEvent.TIMER, bEnd);
bTimer.start();
}
private function bEnd(evt:TimerEvent):void {
bTimer.removeEventListener(TimerEvent.TIMER, bEnd);
bTimer = null;
c();
}
private function c():void {
...
dispatchEvent(new CustomEvents(CustomEvents.NEXT_FRAME,1));
}
....
private function g():void {
// tell the second class the sequence finished
}
The problem is at some point and before arriving at last method, I need to run again a sub-sequence, let's say from function c() to e(). And it's causing problems in the form of an increasing delay between functions (I have 2 timers)
I guess the solution is something like this:
a();
b();
...
if (some condition) {
c();
...
e();
}
...
f();
g();
But, as far as I know, Flash Player doesn't make a synchronous execution. i.e., it doesn't wait until method a() completes to execute b()
Any idea/suggestion on a clean and bullet-proof implementation? This application will run in an endless loop 24x7
Thanks in advance,
After reading your code properly, yes, you are right. b() gets executed as that line of code is reached.
I might be tempted to create a queue of methods to execute. Execute one, check to see if you have time to execute another before the frame needs updating, and repeat. You can always insert new commands in to the queue at any time, so b() could insert endB() next in the queue.
Both the sequencers at http://www.dpdk.nl/opensource/running-tasks-in-order-with-a-task-based-sequence-manager and http://as3.casalib.org/docs/org_casalib_time_Sequence.html should do what you need. The former might be a bit of overkill as it looks like you need to create individual classes for each of your tasks which may be a little too much overhead. On the other hand the Conditional Tasks look like they are exactly what you need. The latter being simpler in that you can specify methods to execute. However, there doesn't seem to be a built in way to condition the tasks, but that may just be as easy as creating a task that conditionally adds tasks.
It might help to know a bit more how the conditions work.
Other points:
Tail calls are not very efficient in AS. Think of it as adding more to the stack every time you call a method. Once the method returns (even if you don't explicitly use return) the method gets knocked off the stack and the previously called method will continue to execute. So the more tail calls, the bigger the stack and the more to clean up.
As soon you start executing code the player hangs until the code has completely run and execution has returned to the player. You have around a 15 second execution limit before the player will kill your script, so you have to account for that when endlessly executing code. The solution is to execute some code then wait till the next frame to execute more.
You don't have to recreate your Timers, you can create them once as instance variables and just call start. The timers will return execution to the player (if no more method calls are made).
A somewhat simplified version, but I'm sure you get the picture.
ADDENDUM: I think you should look in to the Command Pattern (http://en.wikipedia.org/wiki/Command_pattern). You can store an array of commands to be executed (either synchronously, or asynchronously) and when one returns or dispatches a complete event you execute the next. I think you can create a simple implementation of the Command Pattern to do what you need without all the overhead of sequencers I mentioned earlier, but it's always good to get an idea of how others have done it.
There are a number of libraries that provide sequenced execution in AS3. Usually they are for performing Animation so they will generally have a bias toward that.
For example, Twease and Tweener will let you do sequenced actions as well as generic animation actions.
Another particularly good sequencing library is included as part of the asapframework ... which has a class called ActionQueue to which you can add TimedAction items. The great thing about TimedAction & ActionQueue is the feature to add an undo method and arguments, if you need to run the sequence backwards.
Using sequencers is a lot simpler than setting up a mass of timers manually.
i don't really understand your question. actionscript is synchronous in general (except for some AIR functions that can be executed asynchronously), but a timer is asynchronous in the sense that your code will not pause and wait for the timer to complete before continuing the main thread.
if you want your methods to only execute following the completion of a timer, use the timer event TIMER_COMPLETE event listener.