ActionScript.org Flash, Flex and ActionScript Resources - http://www.actionscript.org/resources
Say "Good Bye" to EventDispatcher and "Hello" to NResponder
http://www.actionscript.org/resources/articles/1046/1/Say-Good-Bye-to-EventDispatcher-and-Hello-to-NResponder/Page1.html
Diney Bomfim
I think that I'm not an Interactive Developer, but Interactively a Developer, because everything is changing me, constantly.

I grew up as a Designer, long time ago, for years I worked as Art Director and it led me to search for some poesy in the code. Today Code is my Art.
Some languages that work are JavaScript, PHP, .NET (C#), SQL Languages (MySQL, SQL Server, PostgreSQL)

My specialities are:
  • ActionScript
  • Objective-C
And I'm completely passionate by 3D world! Specialist in:
  • OpenGL, OpenGL ES and Shader Language.
  • Alternativa 3D, Away 3D, PaperVision 3D and others.
My website: http://db-in.com
Blog: http://db-in.com/blog
Twitter: http://twitter.com/dineybomfim
Facebook: http://facebook.com/dineybomfim
LinkedIn: http://linkedin.com/in/dineybomfim 
By Diney Bomfim
Published on November 14, 2010
 
NResponder is the most advanced and fast way to work with events in ActionScript 3.0 (AS3). Responder grown based on idea of Objective-C Event Flow. For this reason the name is Responder, like Responders in Objective-C.

New way to work with events in AS3, based on Objective-C approach
Introduction

Hello everyone!
Welcome to this article!
Today I want to show you something called Nineveh Responder engine, or as I say here just NResponder.
And to do this, I will cover just four points, nothing more:
  • Nineveh What?: What is this? For what I want?
  • NResponder's features: What has of special?
  • NResponder usage: How to use it?
  • REAL WORLD example: NResponder in action!
OK, so let's start!

Nineveh What?

Do you remember of city Nineveh? OK, nothing like that.
Nineveh is in really a new Framework to AS3 under construction. Is not the point here talk about this Framework, but just is important to say that NResponder is one of the engines and APIs of the Nineveh Framework. Something new about this framework is that it has engines and APIs independents, like NResponder, and these engines and APIs can work fine outside the framework.
OK, but what the kind of engine is NResponder?
An Event Engine!

For years I used the Event Engine of default Flash framework called EventDispatcher. Oh God!
How boring was that! You know:
  •  Create some kind of instance or inherit from EventDispatcher class.
  •  Add listeners into it.
  • Create a VERY LIMITED AND STRICT event-class inherited from Event class (in majority of cases). And you need to use just event-class AS PARAMETER when dispatch.
  • Create a new instance of that custom Event.
  • Dispatch that Event using the above instance of EventDispatcher (well, I mean, if you have some instance in the time of dispatch).
  • Wait for Capture phase, Target Phase, Bubbling Phase.
Ooooh...  just STOP!!!

If you are boring with all this, like me, NResponder is for you!
If you are completely new to Events in Flash, NResponder is for you too!
And if you are new just delete the points that I just spoke above, you don't need this with NResponder.

NResponder is much much faster than native Event Engine of Flash.
You don't need to create any instance, if you don't want.
Can manage and control events of your entire application.

Imagine this scene:
You start you application, place 3 buttons on the stage, and load an external SWF to play a video.
When you press one button, the video playing in the other SWF need to stop, because another SWF will be loaded above it.
Well...  with EventDispatcher you should have a big path to follow until finally catch it.
But with NResponder, all that you need, is just 2 lines of code!
One in the Button class and another in the video player! Just simple as this!

Well, this is just the natural behavior of NResponder, I didn't even talk about features yet.

You can use NResponder for everything related to events or fire actions, mouse and keyboard and touch interactions, etc.
As the title of this article, you can completely say "Good Bye" to EventDispatcher.

OK, now you know what NResponder is.
If you want, you can see the project page on Google: http://code.google.com/p/nineveh-responder/
Check the blog page here: http://db-in.com/blog/nineveh-framework/nresponder/

You can download the NResponder here: http://nineveh-responder.googlecode.com/files/Nineveh-Responder.zip

Obviously you can check the project page on Google to see the Documentation, check the SVN, learn with the Wiki, but here I will teach you step by step in a tutorial to use the great power of NResponder.

Now let's move further.

NResponder's features
NResponder's features

To talk about the features of NResponder I want to give a little comparison.
In the following table you can see the native Envent Engine (or API) compared to the features of NResponder.
Feature Event API
(Adobe® Flash®)
NResponder
(Diney Bomfim)
Use without instance No Yes
Use with instance Yes Yes
Specify number of dispatch arguments No Yes
Dynamic dispatch arguments No Yes
Change dispatch arguments in Run-Time No Yes
Remove all No Yes
Specify a delay time No Yes
Set the number of replies No Yes
Ordinate Yes Yes
Can associate with a target Yes Yes
Can pause without remove No Yes
Can stop propagation Yes Yes
Change attributes in Run-Time No Yes
Garbage Collect only weak references Yes

I will focus on the most important and more usable features:

Static and instantiated mode
With NResponder you can choose the best to way to work. Use it as a static class, without create any constant or variable, or use it as instance, a more object oriented approach.
A important thing to say is that the instantiated mode offers to you more control over the event, like pause it without remove.

Custom number of arguments and changes
This is really one of my favorite features. As you know, in the native Event Engine of Flash the dispatcher MUST and NEED to inform ONE, and just one, Event instance. And the call back functions need to expect that kind of event.
So, for example, what you have is:

[as]
eventDispatcherInstance.addEventListener("aCustomEvent", callBackFunction);
eventDispatcherInstance.dispatchEvent(new MyCustomEvent("aCustomEvent"));
...
private function callBackFunction(event:MyCustomEvent):void
{
...
}
[/as]

This is boring!!!
If you want to pass some kind of data to your callBackFunction() you need to put new variables to your MyCustomEvent class!
Just forget it!!!
With NResponder you can pass how many parameters you want and can have a call back function like this:

[as]
private function callBackFunction(aNumber:Number, aString:String, customObject:ACustomObject):void
{
...
}
[/as]

This give to you so much more flexibility to work!
Because you can make your call back functions more readable and more reusable.

Number of replies
This is one of my favorite too.
With this feature you can simple set the number of times that a specific event (or Action, in NResponder language) will happen!
How many you want, just 5, or until 21, anything!
One very common and useful usage of this is for view classes.
As you know, when you start a view class and it is not on the stage yet, its property of "stage" is null. So a technique widely accepted among developers is the use of:

[as]
public function Main()
{
    if (this.stage)
    {
        init(null);
    }
    else
    {
        this.addEventListener(Event.ADDED_TO_STAGE, init);
    }
}

public function init()
{
    if (this.hasEventListener(Event.ADDED_TO_STAGE))
    {
        this.removeEventListener(Event.ADDED_TO_STAGE, init);
    }
}
[/as]

You need to add and remove, make checks to hasEventListeners, to use this routine just ONCE!
Is boring!!!
With NResponder all that you need is set the number of replies, in this case, to 1 and stay focus on your code!
Because NResponder will be responsible to later clean up the mess, delete what it need to delete, frees the memory and go on.

Delay time
This can be very helpful for some situations.
The delay time specify the time, in seconds, that will be the minimum to wait between two consecutive dispatches.
For example, you have a button in your game that the user need to press continuously. But you want a little interval of time between two clicks, like 0.5 secs. With NResponder all that you need is set one property and everything will be controlled by the NResponder engine.

Combined removes
With the native Event Engine if you set a lot of listeners and after need to remove that listeners, you need to remove one by one.
With NResponder you can make combined removes, like remove all listeners of a target, remove all listeners of a specific call back function, remove all listeners of a specif type (Action), like Mouse.CLICK, or even make combination like remove all listeners of a specific target with a specific call back function.
Don't worry if this don't make sense to you now, when I show the examples, everything will becomes clearer.

OK, these are the most important features of NResponder.
I will not talk about features that have a correlated in native Event Engine, like order or stop propagations. Because I suppose that you already know from EventDispatcher.

One more thing...
Something that you may think now is: "OK, you talk about mouse events, keyboard, touches... and said that I can say Goog Bye to native Event Engine... but are not mouse, keyboard and touches native events?".
Yeh!
You are right!
With NResponder you don't need any instance of EventDispatcher in your application, you don't need to use the processing core of native Event Engine.
But if you want, NResponder give you a way to use the native system under the NResponder engine system.
Obviously to work with mouse envets, keyboard, touches, etc, NResponder need to use a little portion of the native Event Engine, because is the only way to catch this kind of event in Flash.
But again, NResponder can do this so much better than using the native EventDispatcher process.

NResponder usage
NResponder usage

Hands to work!

To do this, you'll need download the source of NResponder:



For now we just will create a project that print (trace) some responses on the screen.
So you'll need an IDE to compile and debug the code, like Flash Professional, Flash Builder, Flash Develop, FDT, etc.
OK, now let's code!


Static or instantiated mode
The first important thing is import the NResponder to your classes. Some IDEs do this automatically for you (Flash Builder, FDT, Flash Develop,...) when you are typing.
NResponder package is inside the "appkit" (a SubFramework of Nineveh Framework) and inside the package "responders".
This path is just a convention of Nineveh Framework. Of course, you will need to import this package in all classes that you want to use NResponder.

[as]
package
{
    import flash.display.MovieClip;
   
    import appkit.responders.NResponder;

    public class Main
    {
        public function Main():void
        {
        }
    }
}
[/as]

Now, about the static and instantiated mode. Every time you add a new NResponder (register an event, add a call back function, register a listener, whatever, is the same thing for NResponder), the NResponder will create a little instance of Responder, this instance go to the core of NResponder and will be the responsible to execute the commands in the engine's core. This is a behavior, NResponder always will do this.

The cool thing here is that you can get a copy of this instance when you add a new. And you have some flexible ways to do this:
IMPORTANT: The following code is not real, is just to illustrate the both modes. In the next section (Creating a NResponder) you'll see a real code.

[as]
package
{
    import flash.display.MovieClip;
   
    import appkit.responders.NResponder;

    public class Main
    {
        public function Main():void
        {
            // This is the static mode
            NResponder.add();
           
            // This is the instantiated mode.
            var responder:NResponder;
           
            responder = new NResponder();
            // Or even
            responder = NResponder.add();
        }
    }
}
[/as]

You could asking: "wait, why the 'new' create an instance and the static call return an instance too?"
Well, you'll understand soon, the "new" constructor is generic, and the static "adds" (in plural) have some shortcuts to you. As I mentioned early, the the NResponder can work with native events in Flash, so the different "adds" help you to create it. Although the "new" constructor can do this, you need to pass more parameters to it.

Reasons why:
The static and instantiated mode don't have any impact in performance of memory of your application. The unique reason to use instantiated is if you need to change some behaviors of NResponder after create it. Like pause it without delete it, for example. But if you don't need later changes, don't worry with any instance.


Creating a NResponder
Now let's see how to set a call back function to an event in Flash, or more directly, to create a NResponder. Here more than just define your listener, you'll specify the Action (same as Type in EventDispatcher's language) and all kind of things that NResponder will do for you.
IMPORTANT: Is here, in this section that you can say "Good bye" to EventDispatcher!

OK, the first thing that I want to show is like you normally do with EventDispatcher. When you want to use a custom event you do something like this:

[as]
var myDispatcher:EventDispatcher;
myDispatcher.addEventListener('myCustomEventType', callBackFunction, false, 0, true);
...
myDispatcher.dispatchEvent(new CustomEvent('myCustomEventType'));
[/as]

This is terrible!
Because the only way to you dispatch your CustomEvent is using the "myDispatcher" instance! And look at this line of addEventListener, it is so big, unnecessary.
Now to do the same thing with NResponder all that you need is:

[as]
NResponder.add('myCustomEventType', callBackFunction);
...
NResponder.dispatch('myCustomEventType');
[/as]

We'll talk about "dispatch" later, but for now, as you can see, you don't need to worry with additional parameters like use capture, use weak references, because NResponder don't need these kind of things to work with NResponder. Here is a little difference between the EventDispatcher and NResponder. The 'myCustomEventType' is the type of event to EventDispatcher, but NResponder called it of "Action". So henceforth let's call "Action" everything that means "Event Type" for EventDispatcher.

And as I told above, you can get a reference to the instance returned by the "add" method:

[as]
var myReponder:NResponder = NResponder.add('myCustomEventType', callBackFunction);
[/as]

Remember that this instance doesn't change anything, is just to you gain more control over the NResponder instance.
OK, now let's take a look at the NResponder working with native Event API of Flash. The method to create is very similar. If you want to set a click in a button, for example, using the native Event API you probably do something like this:

[as]
var myButton:CustomButton;// probably inherited from MovieClip or Sprite.

myButton.addEventListener(MouseEvent.CLICK, clickFunction, false, 0, true);
[/as]

OK, now let's translate this to NResponder's language:

[as]
var myButton:CustomButton;// probably inherited from MovieClip or Sprite.

NResponder.addNative(myButton, MouseEvent.CLICK, clickFunction);
[/as]

Just simple as it. Using the method "addNative" is very similar to "add", with only one difference: the first parameter is the target of the native Event.
Some people get confused at this point. But all that you need to remember is to ask "Who is responsible for dispatch this native event? Who is inherited from EventDispatcher class?", so you take this object and pass it on the first parameter to "addNative" method.
Like this:



You can use NResponder to all kind of native events. The benefits is that it will work faster, more clean and you can use all the features of the NResponder. The following topics will explain about these features.

Well, as you noticed, as a Good Practice in programming to avoid misspelling, is advisable to you store your custom Actions in a class with "public static constants", like this:

[as]
public static const CUSTOM_ACTION:String = 'myCustomAction';
...
NResponder.add(CUSTOM_ACTION, callBackFunction);
[/as]

This is just a tip, although in this article to simplify the purposes I'll use literal strings to illustrate the examples.


Dispatch and arguments
After create a NResponder with the "adds" methods (add() and addNative()) you can dispatch these responders from anywhere in your application, even in different SWF files (loaded files in the same application).
All that you need is inform the "Action" you want to dispatch and the parameters that you want, if needed.
Like this:

[as]
// This will dispatch "myAction" with no arguments. So the callBack function don't need to expect any parameter.
NResponder.dispatch('myAction');

// This will dispatch "anotherAction" with the arguments 35 (Number) and "aString" (String)
// So the callBack function should expect these parameter (Number and String in this order).
NResponder.dispatch('anotherAction', [35.5, 'aString']);
[/as]

The dispatch() method is simple, it will dispatch the specified Action to the whole application.
OK, so you could ask "If NResponder will dispatch an Action for anyone that was registered in NResponder, what it'll do with buttons, for example? Will dispatch a click to all? How it'll know for what button to dispatch?".
Good Point!
The answer is: using the Target parameter!
Do you remember in addNative() that you need to specify the Target as the first parameter? Is now that it makes the difference.
If you specify a target when create a NResponder, that target will work like a lock and this NResponder will only respond when it's target is specified.

Well, this can seems a little confused now, but just think that NResponderCore will care about this for you. If you are using a native event, like MouseEvents, KeyboardEvents or any other, this will happens automatically during the dispatch. Just don't care about it.

If you want, you can specify a target without use the native events. You may use this to take the benefits of this "lock" that target provides. But this is a more advanced topic and I don't want to confuse you with this here. If you want to know more about this just check this Wiki of the project:
http://code.google.com/p/nineveh-responder/wiki/DispatchAdvanced

Let's move.


Number of replies
As I told you, this is one of the most interesting features to me. This let you specify how many times you want that a NResponder performs and after the last one, it will automatically be removed and cleaned. All that you need is specify a number after the listener parameter in the "adds" methods.
Like this:

[as]
NResponder.add('myCustomEventType', callBackFunction, 5);
NResponder.addNative(myButton, MouseEvent.CLICK, clickButton, 2);
NResponder.addNative(this, Event.ADDED_TO_STAGE, init, 1);
[/as]

The code above means that:
  • "myCustomEventType" will only response 5 times
  • The CLICK on "myButton" will happens just 2 times
  • The "init" listener will happens just once when the target "this" be placed on the stage.
You can specify how many times you want. Obviously just can't specify negative number of times.
And just for convention, the 0 (default) number means that NResponder will be performed infinitely.


Delay time
The delay time is the minimum time necessary between two consecutive dispatches.
Imagine that you have a button in your game and don't want that the user click on it without stop. You want the at least the user waits 2.5 sec until make a new click. Well, all that you need is specify the next parameter after the number of replies in the "adds" methods.

[as]
NResponder.addNative(myButton, MouseEvent.CLICK, clickButton, 0, 2.5);
[/as]

This means that the "clickButton" listener just will happens again if the next click occur after 2.5 sec. If the user make a click during the delay of 2.5 sec that click will be ignored.
The 0 (default) means "no delay".


Has and remove
Just like the EventDispatcher class, NResponder provide a way to you check what is registered inside the NResponderCore and a way to remove it.
The advantage here is that you can combine and do multiple tasks at once.
Let's start with a simple case, you want to know if has in your application any registered Action of "myAction", so:

[as]
NResponder.has('myAction');
[/as]

So simple!
This will return "true" if you have at least one registered NResponder with "myAction". Now, imagine that you want to know if have "myAction" linked with a specific callBack function.

[as]
NResponder.has('myAction', myFunction);
[/as]

This will return "true" if you have at least one registered NResponder with "myAction" as Action and "myFunction" as Listener.
And at last, you can check if this is true for a specific target.

[as]
NResponder.has('myAction', myFunction, myTarget);
[/as]

This will return "true" if you have at least one registered NResponder with "myAction" as Action and "myFunction" as Listener and "myTarget" as Target.
The fun thing here, is that you can combine these 3 parameters. At this way:

[as]
NResponder.has('myAction', null, myTarget);
NResponder.has(null, myFunction, myTarget);
NResponder.has(null, myFunction, null);
NResponder.has(null, null, myTarget);
[/as]

The four line above means:
  1. Has at least one registered NResponder with "myAction" as Action and "myTarget" as Target?
  2. Has at least one registered NResponder with "myTarget" responding to "myFunction"?
  3. Has at least one registered NResponder responding to "myFunction", independently of Actions and Target?
  4. Has at least one registered NResponder with "myTarget" as target, independently of callBack functions and Actions?
The null means that you want to ignore that parameter and focus on the others. These combination can be very helpful in the case that you don't have more access to one or two of those parameters.

But the most helpful of the combination feature is on remove. You can remove a lot of NResponders with just one line of code.
The remove() method works exactly same as has() method:

[as]
NResponder.remove(null, null, myTarget);
[/as]

The line above means that you'll remove all the NResponder of a specific Target ("myTarget").

Now think of a button. You can register a NResponder to the "Mouse Over" action, another one to the "Mouse Out", another to "Mouse Down", one to "Mouse Up" and one "Mouse Move". Well, 5 NResponders. And after, when you don't want this button anymore, you can remove all these NResponder in just one line, like this:

[as]
NResponder.addNative(myButton, MouseEvent.MOUSE_OVER, overFunction);
NResponder.addNative(myButton, MouseEvent.MOUSE_OUT, outFunction);
NResponder.addNative(myButton, MouseEvent.MOUSE_DOWN, startDragFunction);
NResponder.addNative(myButton, MouseEvent.MOUSE_UP, stopDragFunction);
NResponder.addNative(myButton, MouseEvent.MOUSE_MOVE, draggingFunction);
...
NResponder.remove(null, null, myButton);
[/as]

Remember that NResponderCore is responsible for all clean, and it will know exactly how to clean everything with just one line of remove() method.


Benefits of instantiated mode
With instantiated mode you can change the order of dispatches of the same Actions, you can perform the call back function directly, you can check some attributes of that instance of NResponder, change the values of delay, number of replies, etc.
I'll not talk about all this kind of benefits, you can find information about they at the Wiki of Project page and at docs:

http://code.google.com/p/nineveh-responder/w/list
http://db-in.com/frameworks/nineveh/doc/

But I want to talk here about a benefit called "paused". This property is a boolean where "true" indicate paused.
As the name suggest, you can pause the NResponder without remove it. This can be very helpful if you want to interrupt a NResponder just for a while.
For example, imagine that in your application you have a 3D interface that react to mouse position. But if the user hit the space bar will appear a pop-up and for the time the user stay on this pop-up you want your 3D interface stop to react to mouse position.
Well, all that you need is use NResponder in instantiated mode and pause it when you need.
Like this:

[as]
var myResponder:NResponder = NResponder.addNative(my3DInterface, MouseEvent.MOUSE_MOVE, interactFunction);
...
// When start the pop-up, use this to pause this NResponder.
myResponder.paused = true;

...

// When close the pop-up, use this to reactivate this NResponder again.
myResponder.paused = false;
[/as]

Obviously you can remove and add the NResponder again using the static mode, but at this way you save CPU and memory, because pause is much much faster than add and remove.

Here I presented to you some features, the most important and most used, of the NResponder Engine. Remember to check the project page to see everything about NResponder. For now, this is all that we need to "say Good Bye to EventDispatcher". With just these features you can do almost everything with NResponder.
Now let's move to some real world example!

NResponder in action!
REAL WORLD example

Finally let's see a real example of NResponder working. Now you'll need the project files, you can download it in the link below:



At a glance
In this example we will create a very simple shoot game's routine. To show you how the features and benefits of NResponder can change how you think about your work, let's refine a little this shoot game. Imagine that the gun in this game is an old single-action revolver, so at every shoot the hammer of this revolver needs to be pulled again and this action may take about 1.5 sec. And more, the gun just has 6 bullets, after 6 shots the user must reload the gun.

First let's imagine what we need to construct this with the native Event API, how many Booleans, timers, a lot of "if then else", and variables we need to use to achieve this behavior. I'll show a possible way to do this, but in the middle, before the code start to be more complex, with a lot of annoying things, we'll change and use the NResponder.

Now, about the project files, is important to say that I place some two-handed comments. You know, that kind of
comment block that you can toggle on/off between two codes. Like this:

[as]
/*
...
/*/
The code here is activated.
//*/

---------

//*
The code here is activated.
/*/
...
//*/
[/as]

So in the project files I let this kind of comment to you see the difference between the native Event API and NResponder. You can easily toggle between both adding a "/" at the first line of the comment block.

Oh right, let's start!

Constructing with native Event API
At this point I'm sure you already look at the project files. So I'll just describe what you've found in FLA file:



Nothing new here, just a stage with 3 MovieClips: the shot area, the reload button and the bullets.
Inside the bullets MovieClip we have a MovieClip for each bullet. All these has instance names that we'll use in the main class later.
As you can see, in the library we export a view called VShootAnimation. Just is just a view class to control the animation of the shoot using a texture atlas (poof.png).

Now I'll start with the NResponderExample just using the native Event API.

[as]
/**
 * NResponderExample class
 *
 * @version NResponderExample v1.0
 * @author Diney Bomfim
 */
package
{
    import flash.display.MovieClip;
    import flash.events.Event;
    import flash.events.MouseEvent;
   
    /**
     * Simple shoot game to illustrate the usage of NResponder.
     */
    public dynamic class NResponderExample extends MovieClip
    {
       
    //**************************************************
    //  Protected / Private Properties
    //**************************************************
       
        private var shoots:int;
       
    //**************************************************
    //  Initialization
    //**************************************************
       
        /**
         * The initialization of NResponderExample class.
         */
        public function NResponderExample():void
        {
            if (stage)
            {
                init(null);
            }
            else
            {
                addEventListener(Event.ADDED_TO_STAGE, init, false, 0, true);
            }
        }
       
    //**********************************************************************************************************
    //
    //  Protected / Private Methods
    //
    //**********************************************************************************************************
       
        /**
         * Initiate the View of the application.
         *
         * @param    e
         */
        private function init(e:Event):void
        {
            // Remove the listener
            removeEventListener(Event.ADDED_TO_STAGE, init);
           
            // Definitions
            doReload(null);
           
            // Listeners
            this.btReload.addEventListener(MouseEvent.MOUSE_DOWN, doReload, false, 0, true);
        }
       
        /**
         * Make a Shoot on the valid stage area.
         *
         * @param    e
         */
        private function doShoot(e:MouseEvent):void
        {
            trace('a Shoot');
           
            var shootAnim:VShootAnimation = new VShootAnimation();
            shootAnim.x = stage.mouseX;
            shootAnim.y = stage.mouseY;
           
            addChild(shootAnim);
           
            this.mcBullets['mcBullet' + shoots].visible = false;
           
            ++shoots;
        }
       
        /**
         * Reload the gun.
         *
         * @param    e
         */
        private function doReload(e:MouseEvent):void
        {
            shoots = 1;
           
            for (var i:int = 1; i <= 6; i++)
            {
                this.mcBullets['mcBullet' + i].visible = true;
            }
           
            // Listeners
            this.mcShootArea.addEventListener(MouseEvent.MOUSE_DOWN, doShoot, false, 0, true);
        }
    }
}
[/as]

Well, the above class will be our main class of the FLA file.
  • First in the constructor of the class (NResponderExample()), just to follow a best practice we put Event.ADDED_TO_STAGE to guarantee that no errors will happens if this file is loaded by another SWF file.
  • In the init() method we remove the previously Event.ADDED_TO_STAGE, make the first reload to the gun and add the listener of the reload button.
  • In the doReload() method we make all the bullets inside the mcBullets visible again and add the listener that will make the shoots.
  • In the doShoot() method we place our VShootAnimation view class in the mouse screen position and remove one bullet from the screen.
At this point the code remains simple.
But our minimally refined behavior is not implemented yet. The bullets don't has a delay to simulate the old revolver, the shoots don't stop after the sixth and we have a bug in the line this.mcBullets['mcBullet' + shoots].visible = false; when the shoots don't stop after the sixth.

Well, try to think what should be necessary to implement our behavior.
Take some minutes if necessary looking at this code and try to implement this behavior.
Remember all the problems above.

To do this we would probably place a lot of "if then else" in our code, create timer checks, Booleans, oh god... really boring!

But let's STOP here and migrate all our events to NResponder Engine.


Solving the problems with NResponder
Now is the BIG POINT of this article. Is now! Is here!
Is here that the magic happens with NResponder!
Believe or not, but to solve ALL these problems, to implement our behavior to the above code, ALL that we need is to REPLACE 3 LINES of code and even can EXCLUDE ONE!!!

Just it, nothing more!

[as]
/**
 * NResponderExample class
 *
 * @version NResponderExample v1.0
 * @author Diney Bomfim
 */
package
{
    import flash.display.MovieClip;
    import flash.events.Event;
    import flash.events.MouseEvent;
   
    import appkit.responders.NResponder;
   
    /**
     * Simple shoot game to illustrate the usage of NResponder.
     */
    public dynamic class NResponderExample extends MovieClip
    {
       
    //**************************************************
    //  Protected / Private Properties
    //**************************************************
       
        private var shoots:int;
       
    //**************************************************
    //  Initialization
    //**************************************************
       
        /**
         * The initialization of NResponderExample class.
         */
        public function NResponderExample():void
        {
            if (stage)
            {
                init(null);
            }
            else
            {
                /*
                addEventListener(Event.ADDED_TO_STAGE, init, false, 0, true);
                /*/
                NResponder.addNative(this, Event.ADDED_TO_STAGE, init, 1);
                //*/
            }
        }
       
    //**********************************************************************************************************
    //
    //  Protected / Private Methods
    //
    //**********************************************************************************************************
       
        /**
         * Initiate the View of the application.
         *
         * @param    e
         */
        private function init(e:Event):void
        {
            // Remove the listener
            //removeEventListener(Event.ADDED_TO_STAGE, init); // Don't need this any more.
           
            // Definitions
            doReload(null);
           
            // Listeners
            /*
            this.btReload.addEventListener(MouseEvent.MOUSE_DOWN, doReload, false, 0, true);
            /*/
            NResponder.addNative(this.btReload, MouseEvent.MOUSE_DOWN, doReload);
            //*/
        }
       
        /**
         * Make a Shoot on the valid stage area.
         *
         * @param    e
         */
        private function doShoot(e:MouseEvent):void
        {
            trace('a Shoot');
           
            var shootAnim:VShootAnimation = new VShootAnimation();
            shootAnim.x = stage.mouseX;
            shootAnim.y = stage.mouseY;
           
            addChild(shootAnim);
           
            this.mcBullets['mcBullet' + shoots].visible = false;
           
            ++shoots;
        }
       
        /**
         * Reload the gun.
         *
         * @param    e
         */
        private function doReload(e:MouseEvent):void
        {
            shoots = 1;
           
            for (var i:int = 1; i <= 6; i++)
            {
                this.mcBullets['mcBullet' + i].visible = true;
            }
           
            // Listeners
            /*
            this.mcShootArea.addEventListener(MouseEvent.MOUSE_DOWN, doShoot, false, 0, true);
            /*/
            NResponder.addNative(this.mcShootArea, MouseEvent.MOUSE_DOWN, doShoot, 6, 1.5);
            //*/
        }
    }
}
[/as]

As you can see, first using the feature of "number of replies" we make our Event.ADDED_TO_STAGE listener run once and automatically be excluded.
With the same feature we make our gun dispatch just 6 times and stop.
And using the delay behavior we make our gun wait 1.5 sec between two consecutive shoots.

Well, literally, you can say "Good Bye" to EventDispatcher in your application!


Conclusion
Well, obviously that I show an specific example where the NResponder fits perfect and you can think that this is just a isolated example.
Well, just remember all the features and facilities that I told you here, remember to check the project page and the docs to know all the power of NResponder.
But if you still have doubts about how helpful and powerful NResponder can be, I just want that you remember two things, just two little things:
  • NResponder is completely independent, can dispatch from everywhere to everywhere and can carry everything with it.
  • With NResponder we can realize new things, new horizons that we don't realize before. Perhaps, before it, we just followed another ways.
Finally, hope I've helped you, hope you try NResponder, test it, try to replace in your own code, make some performance tests, in another words, ENJOY!

Again I'll place here the links about NResponder and if you have any doubt about NResponder, just email me!

Project page: http://code.google.com/p/nineveh-responder/
Blog page: http://db-in.com/blog/nineveh-framework/nresponder/
Download the NResponder: http://nineveh-responder.googlecode.com/files/Nineveh-Responder.zip

Thanks for everyone that read this article.

See you later!