Is this "good practice" to do in AS3 (about using Grand Events)? - actionscript-3

first I'd like to thank you for taking the time to read my question.
So, I've made a little flash game(can't really call it a game), anyway at one point I'm checking for if 2 objects hit each other. So to sum it up here's the code
public function loop(e:Event):void
{
y += vx;
if(y > stageRef.stageHeight || y < 0)
removeSelf();
if(hitTestObject(target.hit))
{
removeSelf();
stageRef.dispatchEvent(new GameOverEvent(GameOverEvent.DEAD)); // <--
stageRef.addChild(new SmallImplosion(stageRef, x, y));
}
}
So, when they collide, one object dispatches an event, there is no problem with the code, it works, but I would like to know if it's good to make handle it this way. stageRef is the reference to stage, both classes have it.
And my other class catches that event and it triggers a function, like this:
stageRef.addEventListener(GameOverEvent.DEAD, takeHit, false, 0, true);
The question is, is this a good way to handle it? Thank you in advance!

When implementing the observer pattern, each of the participating objects has a clear role: One is the subject, who is the object where the action is happening, while the other is the observer, who listenes for events on the subjects. In Flash, any object can be the observer, as you pass the handling function to the subscribe-method. Subjects however implement IEventDispatcher and provide the necessary methods to subscribe to the subject. There is also the standard implementation EventDispatcher which already implements the necessary methods (and many types are subtypes of it).
Now back to your question; you are essentially bringing in a third party, the stage where the events are broadcasted on. Instead of having the events that are local to the subject dispatched on the subject itself, you are dispatching them over the global stage, and all observers have to listen to the stage instead of the subject itself.
This is generally not what you should do. Every subject (IEventDispatcher) should only dispatch its own events. Just like you receive a click event from the button that is clicked, you’d receive a GameOverEvent from the object that triggers it.

From the name GameOverEvent, I believe a bit of significance is implied. Since there's plenty to do at the end of a game, I feel it's appropriate for your stage to listen for an event such as this.
However, don't use this technique to handle any smaller systems. For example, if the collision only dealt some damage to the player (I don't know if this even makes sense in the context of your game but roll with me here) then it would be better to have the classes that check for collisions and the classes that handle health to interact directly with one another instead of firing these "Grand Events".

Related

AS3 Event architecture

I'm having difficulty with the last piece in the puzzle on AS3 events.
I understand target classes inherit from EventDispatch or implement IEventDispatch and can register (amongst other methods) event listeners.
However what do the target classes register with? If an Event happens, how does AS3 know to pass the Event to the target classes?
Regards,
shwell.
Read this article about event phases and it will make more sense:
http://livedocs.adobe.com/flex/3/html/help.html?content=events_02.html
Hope this helps. Have a great day.
You can look at how starling event works
starling even dispatcher
When a displayObject bubbles an event, it will check if the parent of the displayObject exist and add the parent to bubbleList if exist util the ancestor of displayObject is null.
The following code is in starling eventDispatcher
var element:DisplayObject = this as DisplayObject;
var chain:Vector.<EventDispatcher> = new <EventDispatcher>[element];
while ((element = element.parent) != null)
chain[int(length++)] = element;
In AS3, EventDispatcher is an implementation of the observer design pattern. This class implement the addEventLister, removeEventListener, dispatchEvent' andhasEventListener` methods. Internally, it also maintains a dictionary or similar data structure that contains the events which are currently being listened for, and a list of methods which have to be called when the event is dispatched. Something like this -
{"event1": [method7, method5, method3], "event2": [method3, method2], "event3": [method1]};
When addEventListener is called on an object, it creates a new key for the event in question and adds the method reference to its associated value list.
When dispatchEvent is called on the class, it fetches all the methods associated with the event and calls the methods attached with it. Each method is called with an instance of the Event class or its subclasses.
Removing an event listener obviously does the opposite of what adding does.
I guess you're missing of addEventListener() mechanics. This thing has a global side effect on event engine, registering a callback function along with caller this value to provide correct context of a fired event, with possible update of event.localX and event.localY properties by calling globalToLocal() either statically or dynamically, as the event bubbles up and down.
If you are, like me, confused about how does Flash player determine the target of an event - there is an internal "focus" pointer that determines which component of the SWF has keyboard focus, and that one is used to target keyboard events. For mouse events, most likely Flash engine calls getObjectsUnderPoint() to query for topmost IEventDispatcher compatible objects (not all of the DisplayObjects can process events), and that one is sent a mouse event, with the previous event's target to receive a say MouseEvent.ROLL_OUT or MouseEvent.MOUSE_OUT if the target has been changed. For other events, most likely the entire display list can react.
For objects in the display list, the following excerpt from Adobe is the answer "When Adobe® Flash® Player dispatches an Event object, that Event object makes a roundtrip journey from the root of the display list to the target node, checking each node for registered listeners.".
For non display objects, AS3 run time maintains a dictionary of all AS3 events containing bound variables. The bound variables are a reference to the event listeners.

Why use custom events instead of direct method calling?

I'm new to programming and I've been checking a lot of game coding tutorials. I've noticed that on most of them they use custom events to trigger methods instead of calling a method directly.
What's the reasoning behind this practice? Why aren't they just calling the method?
For example:
We have two objects: A and B. A has method A.methodA() that B needs to use when X condition is triggered.
Why implement:
B dispatches an event to A that tells A to run A.methodA()
Instead of:
B uses A.methodA()
The main reason is separation of interests. When using events, class A doesn't need to know about the existence of class B (and vice versa).
Some benefits to this are:
Much easier unit testing (you can test Class A without class B)
Less chance of breaking your code when you change class A or B
Less references to other classes in your code, which reduces the potential for memory leaks
Cleaner code
More flexible/reusable code (a bunch of other classes could all listen/respond to the event without any additional code in the your dispatcher)
Typically in bigger applications using events will help abstract everything. When you have 15+ classes and they're all ditpatching events to a controller, it's a lot easier to figure out what's going on than reading through all different parts of the code to trace functions. Using callbacks begins to create spaghetti code.
However, direct function calls are going to be executed faster than events.
Personally, I use custom events simply for the ease of use. I can have one class dispatch an event when something happens (say an animation finishes or an error occurs in a download) and any number of other classes run any number of other functions based on that event. In addition, I code for reusability. The goal of each class is complete independence so that it can run in any project without needing other packages. So rather than have one class call a method of another class, I dispatch an event from the first class that the second class listens for and then run that method. Then when I need that first class for another project, I can just copy/paste it without having to modify it and without losing any functionality.
EDIT:
Also, it's worth noting that sometimes people do what you describe to get around having to pass in event arguments.
Say you have a button on the stage and you need to be able to click it, but you also need to be able to manually call that method. Some people don't realize you can pass in a null event and have only the single method. Or you can set it as a null default argument, see below:
private function onClickHandler( e:MouseEvent = null ):void{
//as long as you never reference "e" within this method, this method can be used both for MouseEvent listeners and manually calling it elsewhere in the code
}
That technique can help avoid having an event handler that only calls another method and nothing else. At this point in my programming, every single AS3 event handler I write sets the event argument to null by default. It just makes things easier later on.
You might want to read this.
And also note using the callback method allows you to pass parameters to it directly and not via a custom event model.
I built my own, very simplified, events dispatcher system. AS Event model is very powerful, but in 99% of situations you don't need that power. A simple callback with parameters fired as an event is more than enough. You can still retain the versatility from an event model, but don't need to write too many lines of code for, let's say, a simple button.
I can setup a simple event like this:
Buttonizer.autoButton(_buttQuit, this, "onPress");
public function onPressQuit(c:Sprite) {
// Execution goes here
}
You can build your own event model, it will make life simpler, and your code much more concise.

What exactly this method do ? addActionListener

What exactly will this addActionListener Do.....we we call button.addActionListener(this) what will happen
It basically adds this (the current object) to a list of objects that will be notified when the component has an action performed on it, such as a button being pressed.
It's a way of registering your interest in what is happening to the component and is useful in that you don't have to keep polling a component to check its status.
Your object (or class, really) simply implements the interface methods for listening (such as actionPerformed) and that method will be called for each event that happens.
The Java tutorials have a large variety of different articles on the various listeners that you're likely to use.

Problem with event listener added by a weak reference in ActionScript

My problem is basically as follows. There is an instance of a class extending EventDispatcher. Everything goes well when I add event listener to the object like this:
myObject.addEventListener('eventName', someFunction, false, 0, false);
But something changes when event listener is added by a weak reference:
myObject.addEventListener('eventName', someFunction, false, 0, true);
Now someFunction is not called even though the line containing dispatchEvent('eventName') is being executed just like before (and there is an external reference to myObject as well).
The application I’m developing is quite complex so, unfortunately, I can’t post the exact code.
You are misunderstaning how GC works, I think. Using a weak reference will not pin down myObject. It could (possibly, not necessarily) prevent the scope in which the handler is declared to be collected (as long as myObject itself is alive). Hence, the callback itself could be collected, causing it not to be executed. It seems this is the case here, according to your description.
So your goal is to avoid that the scope declaring someFunction is collected. One way could be actually using a hard ref (if you ask me, weak refs are a bad idea, anyway). There may be others, but I don't know how your app is structured, so I can't say much.
Edit to address a comment.
GC wise, event handling is not different from the general case. When you add a listener, you're passing a reference to the dispatcher (the reference is the scope that in which the listener is declared). The dispatches stores this reference so it can execute the callback when neccesary. It's really not that different from this:
myObject.keepThisReference = someFunction;
Now, myObejct has a reference to someFunction. So, as long as myObject is alive, someFunction will be alive too (unless you set someFunction as a weak ref).
So, to answer the question in your comment (an object is not referenced anywhere else but has an event listener attached), given this scenario:
myObject.addEventListener('someEvent',someFunction);
If myObject doesn't have any other reference and goes out of scope, it is collectable.
If there's no other link to myObject, then it'll get collected when the function that you're in goes out of scope. Either change the code so it's not a weak listener, or make sure there's a reference to myObject somewhere else in the code

Responding to an Event that May Have Already Occurred

I'm debating two approaches to a pretty typical problem: Knowing when an event occurs or responding to it immediately if it already HAS occurred.
In approach one, a user of MyLoader1 adds an event listener which will be fired immediately if the loader is already complete.
class MyLoader1 extends EventDispatcher
{
private var _isComplete:Boolean = false;
public override function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void
{
super.addEventListener(type, listener, useCapture, priority, useWeakReference);
// if the operation is already complete, immediately notify listeners
if(_isComplete)
{
dispatchEvent(new Event(Event.COMPLETE));
}
}
}
class Application1()
{
function main():void
{
new MyLoader1().addEventListener(Event.COMPLETE, onComplete);
}
}
In approach 2, a user of MyLoader2 must first check the completion status of MyLoader2 before deciding whether to proceed or add a listener, which is fired later.
class MyLoader2 extends EventDispatcher
{
private var _isComplete:Boolean = false;
public function get isComplete():void
{
return _isComplete;
}
}
class Application2()
{
function main():void
{
var loader:MyLoader2 = new MyLoader2();
if(loader.isComplete)
{
// passing null just to simplify the example
onComplete(null);
}
else
{
loader.addEventListener(Event.COMPLETE, onComplete);
}
}
}
What advantages/disadvantages are there to each approach? Is there a design pattern out there that I could/should be using for this situation?
I'm leaning towards the first because it requires less knowledge of the Loader class and less code to leverage it. It could potentially create unwanted side effects when there are multiple listeners though, because the event will fire once for each time a listener is added.
The second method is understandable and easier to debug, but requires more up front work and seems to break encapsulation of the Loader.
I like your first approach better. I don't think that dispatching one event for each listener added is a problem, though; in fact, that's the very idea behind the event mechanism. If you have N objects that want to be notified whenever FooEvent occurs, you have to dispatch the event for each one whenever this event takes place.
Having said that, I wouldn't dispatch the event in the addEventListener method; I think that's the unwanted side effect, really. It goes against anyone's reasonable expectations. Adding a listener should not cause the event to fire. It should just register a listener. You should check whether the data is already loaded in your load function and dispatch the event there if the data is available (because at that point your load operation completed; not when you added the listener).
Another thing: I understand that you want to dispatch immediately if possible. But this has a problem, that can be serious and lead to annoying and not so obvious bugs. If you dispatch immediately you basically have 2 interfaces: one asynchronous and one synchronous. It's possible to handle this correctly in the calling code, but it requires more work and it's quite error prone, especially if you have chained events somewhere (I've made the error of having this kind of async/sync loader and I learned this the hard way).
It's much simpler and it makes almost no difference to delay the dispatching of the event in case the data is available right away. Just a tiny delay to make the code that handles the event run asynchronously (setTimeout(dispatchComplete,10) will do it), in a different stack frame that the code that called the loader. You'll save yourself some troubles and make your calling code simpler, which I think is what you're after.
Though slightly off topic, I would suggest you give signals a try. It depends on what kind of events you are using (ie. Mouse Events would still require the as3 Event so for some instances it might be a bit of extra work), but I've found signals a lot cleaner to implement, and for custom events, it is my preferred choice.
using a signals I usually set up one static var that acts as the main controller. I find this is better than the interconnected chain of Event Listeners and Dispatchers. You could have all the commands driving your app/game/website going through this one funnel.
The reason I'm bringing this up is that if you go this route, you essentially have a listener before you have the event. So if an object is created after the event has taken place, you could have it poll for whether an event occoured, and the addOnce() function is good for loaders and other events that are expected to happen once only. So while this does not answer your question, I hope it adds to the confusion :)
there's a link here to give you an idea of how it works
http://johnlindquist.com/2010/01/21/as3-signals-tutorial/