Updating one of several views with event - actionscript-3

I don't undertand mechanism of events in actionscript completely, so please forgive if a question is dump. Supose that we have a Controller (extends EventDispatcher) and several views, note that views can be instances of various classes. Supose that each view listens CustomEvent.SOMETHING_CHANGED. The question is if I do dispatchEvent(new CustomEvent(CustomEvent.SOMETHING_CHANGED)) in Controller, will event come to each of listeners or it will be caught by first of views and will not go further.
Thank you in advance!

Yes, it will be passed to all listeners until one of them calls the stopImmediatePropagation method of the event object (this will only stop the event if it is cancelable)

For any object to observe an event dispatched by another object, there are several conditions:
The object has to be a display object.
The object dispatching that event has to be a child of the listening object.
If the parent object is listening for the bubbling phase(default), then bubbling has to be set to true during event creation.
dispatchEvent(new Event(TYPE_NAME, true));
Otherwise it could be captured in the Capture phase, add event listener with 'useCapture = true to accomplish this.
addEventListener(TYPE_NAME, onFuncName, true);
In all other cases, an object can only capture events dispatched by the object itself in the target phase.
Here is a code example:
package regression
{
import flash.display.Shape;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.events.EventPhase;
/**
* ...
* #author ...
*/
public class Check_event_listening_1 extends Sprite
{
public const EVENT_DANCE : String = "dance";
public const EVENT_PLAY : String = "play";
public const EVENT_YELL : String = "yell";
private var baby : Shape = new Shape();
private var mom : Sprite = new Sprite();
private var stranger : EventDispatcher = new EventDispatcher();
public function Check_event_listening_1()
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
trace("test begun");
addChild(mom);
mom.addChild(baby);
stage.addEventListener(EVENT_YELL, onEvent);
this.addEventListener(EVENT_YELL, onEvent);
mom.addEventListener(EVENT_YELL, onEvent);
baby.addEventListener(EVENT_YELL, onEvent);
stranger.addEventListener(EVENT_YELL, onEvent);
trace("\nTest1 - Stranger yells with no bubbling");
stranger.dispatchEvent(new Event(EVENT_YELL, false));
trace("\nTest2 - Stranger yells with bubbling");
stranger.dispatchEvent(new Event(EVENT_YELL, true));
stage.addEventListener(EVENT_PLAY, onEvent);
this.addEventListener(EVENT_PLAY, onEvent);
mom.addEventListener(EVENT_PLAY, onEvent);
baby.addEventListener(EVENT_PLAY, onEvent);
stranger.addEventListener(EVENT_PLAY, onEvent);
trace("\nTest3 - baby plays with no bubbling");
baby.dispatchEvent(new Event(EVENT_PLAY, false));
trace("\nTest4 - baby plays with bubbling");
baby.dispatchEvent(new Event(EVENT_PLAY, true));
trace("\nTest5 - baby plays with bubbling but is not a child of mom");
mom.removeChild(baby);
baby.dispatchEvent(new Event(EVENT_PLAY, true));
mom.addChild(baby);
stage.addEventListener(EVENT_DANCE, onEvent, true);
this.addEventListener(EVENT_DANCE, onEvent, true);
mom.addEventListener(EVENT_DANCE, onEvent, true);
baby.addEventListener(EVENT_DANCE, onEvent, true);
trace("\nTest6 - Mom dances without bubbling - everyone is listening during capture phase(not target and bubble phase)");
mom.dispatchEvent(new Event(EVENT_DANCE, false));
trace("\nTest7 - Mom dances with bubbling - everyone is listening during capture phase(not target and bubble phase)");
mom.dispatchEvent(new Event(EVENT_DANCE, true));
}
private function onEvent(e : Event):void
{
trace("Event was captured");
trace("\nTYPE : ", e.type, "\nTARGET : ", objToName(e.target), "\nCURRENT TARGET : ", objToName(e.currentTarget), "\nPHASE : ", phaseToString(e.eventPhase));
}
private function phaseToString(phase : int):String
{
switch(phase)
{
case EventPhase.AT_TARGET :
return "TARGET";
case EventPhase.BUBBLING_PHASE :
return "BUBBLING";
case EventPhase.CAPTURING_PHASE :
return "CAPTURE";
default:
return "UNKNOWN";
}
}
private function objToName(obj : Object):String
{
if (obj == stage) return "STAGE";
else if (obj == this) return "MAIN";
else if (obj == mom) return "Mom";
else if (obj == baby) return "Baby";
else if (obj == stranger) return "Stranger";
else return "Unknown"
}
}
}
I would be glad to shed more light on the subject.

Related

object's stage reference lost when re-instantiated after being removed from memory & displaylist

I'm building a game. When you die or win a level you're prompted to continue or return to the main menu. If you chose to go to the main menu you can start a new game. When you start a new game, the game is object is created again & it's children have lost their reference to the stage. I'm not sure why this is happening and I've spent over a week trying to figure out why. Here's some code (and descriptions of the code) from the game that should hopefully provide enough insight as to why the problem may be occurring:
if the "new game" button is clicked on the startMenu the NavigationEvent.START event is dispatched. a LevelEvent.COMPLETE event is dispatched by WeeBeeGame when the level is completed.
public class DocumentClass extends MovieClip {
public var startMenu:StartMenuGenerator = new StartMenuGenerator();
public var weeBeeGame:WeeBeeGame;
public var youWonBox:YouWonBox = new YouWonBox();
public function DocumentClass() {
// constructor code
addChild(startMenu);
startMenu.addEventListener(NavigationEvent.START, startGameHandler);
}
public function startGameHandler(e:NavigationEvent) : void {
this.removeChild(startMenuBG);
removeChild(startMenu);
weeBeeGame = new WeeBeeGame();
this.addChild(weeBeeGame);
weeBeeGame.addEventListener(LevelEvent.COMPLETE, levelCompleteHandler);
}
public function levelCompleteHandler(e:LevelEvent) : void {
youWonBox.x = this.stage.stageWidth/2;
youWonBox.y = this.stage.stageHeight/2;
addChild(youWonBox);
youWonBox.addEventListener(MouseEvent.CLICK, mouseClickHandler);
}
private function mouseClickHandler(e:MouseEvent) : void {
if(e.target.name === "mainmenubtn"){
mainmenuHandler();
}
}
private function continueHandler() : void {
youWonBox.removeEventListener(MouseEvent.CLICK, mouseClickHandler);
}
private function mainmenuHandler() : void {
youWonBox.removeEventListener(MouseEvent.CLICK, mouseClickHandler);
WeeBeeGame.collisionDOC.removeChildren();
removeChild(weeBeeGame);
weeBeeGame = null;
this.addChild(startMenuBG);
addChild(startMenu);
removeChild(youWonBox);
}
}
the code that dispatches a LevelEvent.COMPLETE event is not shown but it dispatches when the level is complete. collisionDOC needs to be static because it's needed in a lot of other classes and holds the display objects needed for a 3rd party pixel-level collision detection.
public class WeeBeeGame extends MovieClip {
public var bee: Bee;
public var beeHurt:BeeHurt;
public var spawningDaemon:SpawningDaemon;
public static var collisionDOC:DisplayObjectContainer;
public function WeeBeeGame() {
this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler, false, 0, true);
}
private function addedToStageHandler(e:Event) : void {
this.removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
collisionDOC = new MovieClip();
addChild(collisionDOC);
bee = new Bee();
collisionDOC.addChild(bee);
beeHurt = new BeeHurt(bee.x, bee.y);
addChild(beeHurt);
beeHurt.visible = false;
spawningDaemon = new SpawningDaemon(currentLevel);
this.addEventListener(LevelEvent.COMPLETE, levelCompleteHandler, false, 0, true);
}
private function levelCompleteHandler(e:LevelEvent) : void {
removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
}
the first line to throw a 1009 error (Cannot access a property or method of a null object reference) is the line containing stage.mouseX because the stage reference is null.
public class Bee extends MovieClip {
public function Bee() {
this.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
}
private function addedToStageHandler(e:Event) : void {
this.removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
this.x = this.stage.stageWidth / 2;
this.y = this.stage.stageHeight - this.stage.stageHeight / 9;
this.addEventListener(Event.ENTER_FRAME, enterFrameHandler, false, 0, true);
}
private function enterFrameHandler(e:Event) : void {
if(stage == null){
trace('stage is null' + stage.mouseX);
}
}
}
When the swf is first opened and a new WeeBeeGame is created its children have references to the stage. But when WeeBeeGame and it's children are removed from the display list and memory they lose reference and even if they're re-instantiated their references are still lost. How do I fix this? I'm very confused. Thank you all!!
ENTER_FRAME handlers continue to execute even when the display object is removed form the stage. So when you removeChild(weeBeeGame) those ENTER_FRAME handlers are still trying to access stage.mouseX each frame. You need to stop the ENTER_FRAME handlers.
Probably the easiest fix is to add an Event.REMOVED_FROM_STAGE handler to remove the Event.ENTER_FRAME handlers.
A better fix IMO is to not add any ENTER_FRAME handlers from your game objects, but rather expose a public function like update() which gets called from a single ENTER_FRAME handler in your WeeBeeGame when the game is running. Then to stop the game completely you can stop all updates by simply removing that single ENTER_FRAME handler. This is a common practice.

synchronous image loading action script 3 flash

I am having a problem with my flash/as3 application. I've created most of it and at the moment I'm struggling to get my external resources work.
My application consists of a Controller class, that takes control of an application flow. At the beginning it initializes AppInitializer class, that loads / generates the whole app content (it is a simple point'n'click game).
In AppInitializer I create an array of items available in a game. Item's constructor takes path as a parameter (String) to the resource (image). Then, inside the constructor I call a static method of my AssetsLoader class which looks like that:
public static function loadImage(path:String):BitmapData
{
completed = false;
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function(e:Event){completed = true;
trace("Loading completed");
e.target.removeEventListener(Event.COMPLETE, check);});
if (path == "")
loader.load(new URLRequest("images/default.png"));
else
loader.load(new URLRequest("images/" + path));
//while (!completed);
var image:Bitmap = new Bitmap((loader.content as BitmapData));
return image.bitmapData;
}
Where completed is a static variable of AssetsLoader.
First problem is: I create many Item objects in a row, so the method loadImage should not be static I guess (same with completed variable), since that may cause problems when loading.
Second problem is: At the moment I'm unable to return the bitmapData (or bitmap, it does not really matter), because the return statement will always return null - because the resource is loaded asynchronously and is not loaded at the time application reaches return statement. If I uncomment the wile loop, the complete event is never called.
I would like to ask more experienced ActionScript developers to point out any solutions that would require minimal changes to the rest of my app and would solve those problems. (I think first problem can be eliminated by using some sort of queueing method for the loader, but I'm stuck with the second problem for few days so far and came up with no possible solution).
I could also consider changes in my logic, so I could preload all image resources into "somewhere" and after that just make copies of these images for my purposes. If that's easier to do.
So as I suggested in the comments, a minimal change resolution could simply be to pass a function to call as part of the parameters for loadImage(). This is known as a callback function, and it would look something like this:
First create the callback function:
public function addImage( bitmapData:BitmapData ):void {
//do something with the bitmapData returned
}
Next adjust your loadImage() local function to use the callback with the bitmap data when the event has completed:
public static function loadImage(path:String, callback:Function):BitmapData {
completed = false;
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function(e:Event){completed = true;
trace("Loading completed");
var image:Bitmap = new Bitmap((loader.content as BitmapData));
callback( image ); //call the callback with the bitmap
e.target.removeEventListener(Event.COMPLETE, check);});
if (path == "")
loader.load(new URLRequest("images/default.png"));
else
loader.load(new URLRequest("images/" + path));
}
Then just you make the call to loadImage() like so:
loadImage( myPathToImage, addImage );
That is a simply resolution and does exactly what you need it to.
Super, you commented that insane line of code with while ;)
Here for you, simple QueueLoader (It loads items one by one, when you add item to the queue, you can store id of item in queue), that will help you with your task:
package {
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
public class StackOverflow extends Sprite {
public function StackOverflow() {
addEventListener(Event.ADDED_TO_STAGE, onAdded);
}
private function onAdded(e:Event):void {
removeEventListener(Event.ADDED_TO_STAGE, onAdded);
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
setup();
}
private function setup():void {
//Store somewhere reference on QueueLoader to reuse it, and use queue
var loader:QueueLoader = new QueueLoader();
loader.addEventListener(QueueLoaderEvent.COMPLETE, onCompleteItem);
//Add as many images to load as you want, and store Id's of items that
//will be loaded in future, if you want...
loader.addItem("someUrl1");
loader.addItem("someUrl2");
var importantId:int = loader.addItem("someUrl3");
loader.addItem("someUrl4");
loader.addItem("someUrl6");
}
private function onCompleteItem(e:QueueLoaderEvent):void {
trace("Item loaded");
}
}
}
import flash.display.Loader;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import flash.net.URLRequest;
internal class QueueLoader extends EventDispatcher {
private var _list:Array;
private var _cursor:int;
private var _loading:Boolean;
public function QueueLoader(target:IEventDispatcher = null) {
super(target);
_list = [];
}
public function addItem(url:String):int {
var item:Object = {url: url, id: ++_cursor};
_list.push(item);
loadNext();
return item.id;
}
override public function dispatchEvent(evt:Event):Boolean {
if (hasEventListener(evt.type) || evt.bubbles) {
return super.dispatchEvent(evt);
}
return true;
}
protected function loadNext():void {
if (_list.length > 0 && !_loading) {
var loader:Loader = new Loader();
var data:Object = _list[0];
var request:URLRequest = new URLRequest(data.url);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete, false, 0, true);
loader.load(request);
_loading = true;
}
}
private function onComplete(e:Event):void {
var data:Object = _list.shift();
data.content = e.currentTarget.content;
dispatchEvent(new QueueLoaderEvent(QueueLoaderEvent.COMPLETE, data.id, data));
_loading = false;
loadNext();
}
}
internal class QueueLoaderEvent extends Event {
public static const COMPLETE:String = "queueLoaderEventComplete";
private var _id:int;
private var _data:Object;
public function QueueLoaderEvent(type:String, $id:int, $data:Object, bubbles:Boolean = false, cancelable:Boolean = false) {
_id = $id;
_data = $data;
super(type, bubbles, cancelable);
}
override public function clone():Event {
return new QueueLoaderEvent(type, id, data, bubbles, cancelable);
}
public function get id():int {
return _id;
}
public function get data():Object {
return _data;
}
}
Your loadImage mehtod will look at the end:
public static function loadImage(path:String):int
{
return queueLoader.addItem(path);
}

How to assign properties of a component inside an MC loaded from a Library?

I have a Library item: MovieClip with a single ComboBox component inside. The item has a Class assigned to it, myMC.
What I want to achieve is that a call from the main movie like var mmc:myMC = new myMC( stage); would:
initialize the ComboBox instance's values;
place the myMC instance on stage (or inside another MC).
So inside the myMC Constructor I wrote smth like:
public function myMc( theStage:flash.display.Stage) {
if( stage == null) this.addEventListener( Event.ADDED_TO_STAGE, init);
theStage.addChild( this);
}
public function init( e:Event = null) {
var Data:Array= new Array(
{'label1' : 'item1'},
{'label2' : 'item2'},
{'label3' : 'item3'}
);
cbox.dataProvider = new DataProvider( Data);
}
cbox is the name of ComboBox instance within myMC.
What happens is that the ComboBox doesn't have any values assigned. This is a simplified example of my problem, whereas the actual case involves more UI components — all of them miss their values.
Debugger show the component objects of correct type, with the values - but they miss from the stage objects shown!
Please explain, what am I doing wrong - and why does the instance on stage is somehow different from the AS instantiated Object?
Ok, seems that it was my mistake: wrong types and messy code.
Here's an example that works afterall. So, maybe its not the best practice to put an object onstage by its own constructor, however this works. The working example sources.
Main document has a class DocTest:
package {
import flash.display.Sprite;
import libItem;
public class DocTest extends Sprite {
public function DocTest() {
var instance:libItem = new libItem( this);
}
}
}
And the library item has a ComboBox and a text field inside, and the following Class code attached:
package {
import fl.data.DataProvider;
import flash.display.Sprite;
import flash.events.Event;
public class libItem extends Sprite{
public function libItem( theParent:flash.display.Sprite) {
if( stage == null) this.addEventListener( Event.ADDED_TO_STAGE, init);
else init();
theParent.addChild( this);
}
public function init( e:Event = null) {
var Data:Array= new Array(
{label:'label1', data: 'item1'},
{label:'label2', data: 'item2'},
{label:'label3', data: 'item3'}
);
cbox.dataProvider = new DataProvider( Data);
x = 200;
y = 100;
myText.text = 'Woo-hoo!';
}
}
}
Hope this helps someone. Sorry for the studid question.

AS3 checking if click was on stage or an a movieclip

How can i check if a click was on the stage (not on a other object in front of the stage - just on a place where no other object is) or on a movieclip (name "mcSlideHolder")?
function onMouse_Down(e:MouseEvent):void
{
trace("MouseDown occured");
trace("MouseDown target: " + e.target.name);
trace("MouseDown target.tostring: " + e.target.toString);
trace("MouseDown currentTarget: " + e.currentTarget);
if(e.target.name == null || e.target.name == "mcSlideHolder")
{
this._userInput();
}
}
My Problem is, that e.target.name is null, when clicking on the stage.
When clicking on the mcSlideHolder e.target.name is "instance235".
How would you do this?
Thanks for any advice!
Normally, when you want to detect a click on a specific MovieClip, that is the one you add the listener to:
mcSlideHolder.addEventListener(MouseEvent.MOUSE_DOWN, onSlideHolderMouseDown);
rather than
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouse_Down);
It sounds like you're doing the latter; adding a listener to the stage, and trying to figure out in the listener function what was clicked on. There is nothing wrong with this, and it can even be efficient if there are many possible things to click on. But in this case, the currentTarget is always going to be the stage, and the target is always going to be the thing you clicked on that generated the event. If that is indeed how you have things set up, you will get a different result--possibly the one you expected--if you do this:
mcSlideHolder.mouseChildren = false;
I'm assuming mcSlideHolder is the instance name. Setting mouseChildren to false will mean that mcSlideHolder will generate the MOUSE_DOWN event rather than instance235 that is its child.
Adam smith's answer already explains why you get "instance235" so I'll explain a work around for stage object's name property equaling null.
You could create a wrapper class for the stage object and give that class a property called name. The wrapper class would also have to be a subclass of EventDispatcher so that you can override it's addEventListener() method and alter its functionality so that you are implicitly adding an event listener to the stage object and also to the wrapper object. The best way to explain it is to show you an example I made:
package
{
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
public class Main extends Sprite
{
private var _stageWrapper:StageWrapper;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}// end function
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
var stageWrapper:StageWrapper = new StageWrapper(stage, "stage");
stageWrapper.addEventListener(MouseEvent.CLICK, onStageWrapperClick);
}// end function
private function onStageWrapperClick(e:MouseEvent):void
{
trace(e.target.name) // output: stage
}// end function
}// end class
}// end package
import flash.display.Stage;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.MouseEvent;
internal class StageWrapper extends EventDispatcher
{
private var _stage:Stage;
private var _name:String;
private var _listener:Function;
public function get stage():Stage { return _stage }
public function get name():String { return _name }
public function StageWrapper(stage:Stage, name:String)
{
_stage = stage;
_name = name;
}// end function
override public function addEventListener(type:String,
listener:Function,
useCapture:Boolean = false,
priority:int = 0,
useWeakReference:Boolean = false):void
{
super.addEventListener(type, listener, useCapture, priority, useWeakReference);
_stage.addEventListener(type, onStageEvent, useCapture, priority, useWeakReference);
}// end function
private function onStageEvent(e:Event):void
{
dispatchEvent(e);
}// end function
}// end class
Personally I wouldn't go with this approach but this is the best answer I can give you for the direction you seem to be going with.

Custom event dispatchment location

I've been looking into custom event (listeners) for quite some time, but never succeeded in making one. There are so many different methods, extending the Event class, but also Extending the EventDispatcher class, very confusing!
I want to settle with this once and for all and learn the appropriate technique.
package{
import flash.events.Event;
public class CustomEvent extends Event{
public static const TEST:String = 'test'; //what exac is the purpose of the value in the string?
public var data:Object;
public function CustomEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false, data:Object = null):void
{
this.data = data;
super();
}
}
}
As far as I know a custom class where you set the requirements for the event to be dispatched has to be made:
package
{
import flash.display.MovieClip;
public class TestClass extends MovieClip
{
public function TestClass():void {
if (ConditionForHoldToComplete == true) {
dispatchEvent(new Event(CustomEvent.TEST));
}
}
}
}
I'm not sure if this is correct, but it should be something along the lines of this.
Now What I want is something like a mouseevent, which can be applied to a target and does not require a specific class.
It would have to work something like this:
package com.op_pad._events{
import flash.events.MouseEvent;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.EventDispatcher;
import flash.events.Event;
public class HoldEvent extends Event
{
public static const HOLD_COMPLETE:String = "hold completed";
var timer:Timer;
public function SpriteEvent(type:String, bubbles:Boolean=true, cancelable:Boolean=false)
{
super( type, bubbles, cancelable );
timer = new Timer(1000, 1);
//somehow find the target where is event is placed upon -> target.addEventlistener
target.addEventListener(MouseEvent.MOUSE_DOWN, startTimer);
target.addEventListener(MouseEvent.MOUSE_UP, stopTimer);
}
public override function clone():Event
{
return new SpriteEvent(type, bubbles, cancelable);
}
public override function toString():String
{
return formatToString("MovieEvent", "type", "bubbles", "cancelable", "eventPhase");
}
//////////////////////////////////
///// c o n d i t i o n s /////
//////////////////////////////////
private function startTimer(e:MouseEvent):void
{
timer.start();
timer.addEventListener(TimerEvent.TIMER_COMPLETE, complete);
}
private function stopTimer(e:MouseEvent):void
{
timer.stop()
}
public function complete(e:TimerEvent):void {
dispatchEvent(new HoldEvent(HoldEvent.HOLD_COMPLETE));
}
}
}
This obviously won't work, but should give you an idea of what I want to achieve. This should be possible because mouseevent can be applied to about everything.The main problem is that I don't know where I should set the requirements for the event to be executed to be able to apply it to movieclips and sprites.
You are almost there actually, just for the last part, wouldn't this be more of an OOP related issue than stricly a confusion about the way of using custom events ?
Usually, Events in AS3 are value objects whose sole responsibility is to transport information from the event dispatcher to the listener(s). The dispatcher dispatches the event each time a defined momentum is reached, and the listener(s) may or may not react when this happens.
In the example above, I guess it is up to the listener to start a timer and so on when a mouse-down has been detected. In a more sophisticated context the Event could independently trigger more than one listeners actioning separate tasks which neither the Dispatcher nor the Event itself should have to bother about, that is probably why it's worth avoiding amending the dispatcher or the event itself with any soever logic.
For your very example, you could maybe create a handler checking if the mouse has been held down?
The following is just pseudocode, and there are obviously tons of other ways to get to the same result:
public class MouseDownHandler
{
// ...
public function( target:Sprite ) {
this.target = target;
start();
}
public function start():void{
// Listen for the target's mouseUp event
}
public function dispose():void{
// Stop listeners and eventually the timer
}
private function onMouseDown(e:MouseEvent):void{
// Start timer + listening for the stage's mouse up event (target.stage)
}
private function onMouseUp(e:Event):void{
// Cancel timer
}
private function onTimerComplete(e:TimerEvent):void {
dispatchEvent(new HoldEvent(HoldEvent.HOLD_COMPLETE));
}
}
Which could be reused for example this way:
var mc:MovieClip = new MovieClip(); ...
var mouseHandler:MouseDownHandler = new MouseDownHandler(mc);
mouseHandler.addEventListener(HoldEvent.HOLD_COMPLETE, onMcHoldComplete);
... or this way :
public class TestMovieClip extends MovieClip
{
private var mouseHandler:MouseDownHandler;
public function TestMovieClip() {
mouseHandler = new MouseDownHandler(this);
mouseHandler.addEventListener(HoldEvent.HOLD_COMPLETE, onMouseHoldComplete);
}
private function onMouseHoldComplete(e:HoldEvent):void {
// Do something
}
}
I just use robber penners signals. Very easy to use.
http://github.com/robertpenner/as3-signals