Custom Event Not being Dispatched AS3 - actionscript-3

I have a class "Shop" through which I'm trying to dispatch an event. Previously, I've done with another class "Buyer" and it works but the same thing doesn't work for my new class.
Function of Shop Class that is dispatching event:
public function Select(event:MouseEvent):void
{
trace(ShopName);
dispatchEvent( new SelectEvent(SelectEvent.SHOPSELECT,null,this));
}
The code when I run it , displays the "Shop Name" efficiently through trace but it doesn't seem to dispatch the event or else, it is dispatched but not reccieved well.
Reccieving code for Shop class dispatched event:
addEventListener(SelectEvent.SHOPSELECT,shopselected,true);
Buyer Class' function where the same method worked:
public function Select(event:MouseEvent):void
{
trace(buyerCode);
if(y>=377|| enteredmall)
{
dispatchEvent( new SelectEvent(SelectEvent.BUYERSELECT,this,null));
}
}
Recceiving Code for the Buyer Class dispatched event:
addEventListener(SelectEvent.BUYERSELECT,showselectbuyer,true);
This works but Shop class' one doesn't.
The only difference between both the classes is that the CLICK is on different objects. The Buyer class's object when clicked dispatches the event but the Shop Class's movieclip when clicked dispatches the event.
I've learnt about bubbling of events and I think I'm doing it right in the code. I've read similar question that was asked here but I couldn't understand how to proceed with the solution as the answer was not clear to me.
How to make it work for the shop class as well?
Additional Information:
Select Event Class:
package
{
import flash.events.Event;
import flash.utils.getQualifiedClassName;
public class SelectEvent extends Event
{
public static const BUYERSELECT:String = "buyerselect";
public static const SHOPSELECT:String = "shopselect";
public var selectedbuyer:Buyer;
public var selectedshop:Shop;
public function SelectEvent(type:String, selectedbuyer:Buyer=null, selectedshop:Shop=null, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type,bubbles,cancelable);
if(selectedshop==null)
{
this.selectedbuyer= selectedbuyer;
}
else
{
this.selectedshop= selectedshop;
}
}
override public function clone():Event
{
return new SelectEvent (type, selectedbuyer, selectedshop ,bubbles, cancelable);
}
}
}

Related

Dispatchevent not firing

I have a fla file and 2 class files. On my fla I have:
addEventListener(SubtitleLoadEvent.PASS_PARAMS, onProcessedEvent);
function onProcessedEvent(e:Event):void {
trace(e.currentTarget);
}
SubtitleLoadEvent.as :
package
{
import flash.events.Event;
public class SubtitleLoadEvent extends Event
{
public static const PASS_PARAMS:String = new String("passparams");
public var resultArr:Array = new Array();
public function SubtitleLoadEvent(type:String, arr:*, bubbles:Boolean = false,
cancelable:Boolean = false):void
{
this.resultArr = arr;
super(type, bubbles, cancelable);
}
override public function clone():Event
{
return(new SubtitleLoadEvent(type, resultArr, bubbles, cancelable));
}
}
}
And I have a class file which extends sprite :
dispatchEvent(new SubtitleLoadEvent(SubtitleLoadEvent.PASS_PARAMS, cleanArr));
But the movie doesn't output anything. How can I fix this?
Since your event doesn't bubble, the only way your timeline code will hear the event is if it was dispatched on the same scope (which is unlikely to be the case here).
If your dispatching sprite is on the same scope (timeline) or a descendant/child of it, then making the event bubble (third parameter when creating the event) should make it work. (or you could listen on the capture phase)
Otherwise, you will need to listen for the event on some common parent of both objects.
The easiest way to resolve this, is to dispatch and listen on the stage:
stage.addEventListener(SubtitleLoadEvent.PASS_PARAMS, onProcessedEvent);
stage.dispatchEvent(new SubtitleLoadEvent(SubtitleLoadEvent.PASS_PARAMS, cleanArr));
This assumes that your dispatching sprite has been added to the display list. If not, then the stage property will be null. If it's not on the display list, then it will not work.
TO learn more about how events work and their lifecycle, you could read this article.

AS3 - dispatch custom event with parameter (not working)

I read a lot of topics about dispatching event but I can't make my code work.
This topic and this topic are closed to what I would like to do, but it's not working in my case.
Here is the situation :
My scene is a battle field and has two ships
Each ship knows when it is touched by a fire, so it has to inform the scene that contains the graphic interface
So the ship dispatch a custom event with itself as parameter, so the scene knows when a ship is touched and which ship
I have 3 classes :
The custom event class is an event that has a property "Ship"
The EventDispatcher class
The symbole class that corresponds to my scene and listen to the event
1) CustomEvent class
public class FightEvent extends Event
{
public static const SHIP_TOUCHED:String = "SHIP_TOUCHED"; //type
public var object:Ship = null; //object to pass
public function FightEvent(type:String, pObject:Ship, bubbles:Boolean=true, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
object = pObject;
}
public override function clone():Event
{
return new FightEvent(type, object, bubbles, cancelable);
}
}
2) EventDispatcher
public class Ship extends EventDispatcher
{
private function updateDamages():void
{
//compute damages
dispatchEvent( new FightEvent( FightEvent.SHIP_TOUCHED, this ) );
}
}
3) Scene
public class Fight extends customMovieClip
{
private var playerShip:Ship; //I have two ships, player and enemy
private var enemyShip:Ship;
public function init():void
{
stage.addEventListener(FightEvent.SHIP_TOUCHED, onShipTouched);
//I made a test : the event listener is correctly added
}
private function onShipTouched(e:FightEvent):void
{
//update the graphic interface to show damages
}
}
My event listener is added, the code passes on the dispatch line, but onShipTouched is not called.
Please help, what did I miss ?
What is the element I didn't understand ?
Is it a good way to use events like this ? or should I set a reference to the scene inside the Ship class ?
Your Ship class is not a MovieClip, Sprite or their subclass in order for your event to bubble up the display list, just because they don't participate in a display list. So, you change your Ship to Sprite subclass (this one already inherits EventDispatcher), add graphics and addChild() both ships to the stage, this way your stage will receive events properly.
My logic was wrong :
I was doing this : the eventdispatcher is dispatching the event, and the stage is listening to the event. That is incorrect.
The right solution is : the eventdispatcher is dispatching the event, and is also listening to its own dispatched event. The eventlistener is added to the eventdispatcher in the scene, that contains the function to call.
As Vesper said, the parameter in FightEvent is useless, as the eventdispatcher is actually the event target.
DodgerThud, BotMaster, you gave me this answer, thank you for your help (Looks like I can't set a comment as "answer accepted").
Here the right code for the Fight class :
public class Fight extends customMovieClip
{
private var playerShip:Ship; //I have two ships, player and enemy
private var enemyShip:Ship;
public function init():void
{
enemyShip.addEventListener(FightEvent.SHIP_TOUCHED, onShipTouched);
playerShip.addEventListener(FightEvent.SHIP_TOUCHED, onShipTouched);
}
private function onShipTouched(e:FightEvent):void
{
//e.target == the ship that dispatched the event
}
}

How to listen to events between classes with no inheritance in actionscript?

In the code below, the event "myEvent" dispatched in class A is never listened in class C. Do you see where the problem is?
Class A extends EventDispatcher{
A(){
dispatchEvent(new Event("myEvent"));
}
}
Class B extends A{
...
}
Class C extends EventDispatcher{
method(){
addEventListenet("myEvent", onresult);
var ob:A = new B();
ob.method();
}
onResult(){
...
}
}
The problem here is, your A object in creation does not know wherer to dispatch the event "myEvent", and dispatching to self does not do a thing, because there is nowhere for the event to go, even if you'll tell it to bubble. You need to provide a listening object to either the entire A class, or to a specific object of type A, so that that object will be the source of dispatchEvent() call, becoming the target for the dispatched event.
class A { // no inheritance needed
public static var listener:EventDispatcher;
public function A() {
if (listener) listener.dispatchEvent("myEvent");
}
}
Another possibility is to create a static class just for the purpose of sending broascast events, implement its functionality as you would do with an EventDispatcher (use internal instance of EventDispatcher to add and remove listeners, dispatch events and check if there's someone listening), and use that class's interface to register with any event type that you're intending to send to all who will listen.
public class Broadcaster {
private static var _instance:EventDispatcher=new EventDispatcher();
public static function addBroadcastListener
(s:String,f:Function,c:Boolean=false,p:int=0,w:Boolean=false) {
if (_instance) _instance.addEventListener(s,f,c,p,w);
}
// etc, just make wrappers for EventDispatcher functions
}
Then in C.method you do:
Broadcaster.addBroadcastListener("myEvent",onresult);
And in A() you do:
Broadcaster.dispatchEvent(new Event("myEvent"));
You need to attach listener to the the ob:
Class C extends EventDispatcher{
method(){
var ob:A = new B();
ob.addEventListener("myEvent", onresult);
ob.method();
}
onResult(){
...
}
}

Whats the appropriate form when dispatching events in AS3?

I was wondering what the appropriate form was when creating custom events? Should one create a CustomEvent class, and then create a temporary dispatcher in the function, and dispatch the CustomEvent. or is it better to attempt to create a CustomEventDispatcher class, and create the CustomEvent class as an internal class of that class, eg:
package
{
public class CustomEventDispatcher extends EventDispatcher
{
public function CustomEventDispatcher()
{
super(new CustomEvent());
}
}
}
class CustomEvent
{
public function CustomEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable)
}
}
Unilaterally, it is better to make events publicly accessible. This way you can type your listeners (good for code hinting and debugging) and have the Event have public static const types (which you also may want to look in to).
There are two basic questions to answer, when conceiving event mechanics.
1) How do I create dispatcher instance for my events?
General options are: extend EventDispatcher, or aggregate dispatcher instance.
Most basic and common practice (and official docs also state that), is extending EventDispatcher class, thus giving your classes event-dispatching capabilities.
Pros: simple to implement -- just type extends EventDispatcher, and you are done.
Cons: you can't extend something else. Apparently, this is the reason why many native classes are EventDispatcher's grandchildren. Just to spare us the trouble, I guess.
Second general approach is aggregating a dispatcher instance.
package
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
public class ClassA implements IEventDispatcher
{
private var dispatcher:EventDispatcher;
public function ClassA()
{
initialize();
}
private function initialize():void
{
dispatcher = new EventDispatcher(this);
}
public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
{
dispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference);
}
public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void
{
dispatcher.removeEventListener(type, listener, useCapture);
}
public function dispatchEvent(event:Event):Boolean
{
return dispatcher.dispatchEvent(event);
}
public function hasEventListener(type:String):Boolean
{
return dispatcher.hasEventListener(type);
}
public function willTrigger(type:String):Boolean
{
return dispatcher.willTrigger(type);
}
}
}
Note: we pass a reference to aggregating class to dispatcher constructor.
This is done to make event.target reference your class instance and not the dispatcher instance itself.
Pros: you are free to extend whatever you like. You may do some tricks with dispatcher hooks like maintaining listeners list or something alike.
Cons: not as simple as the first approach.
2) How do I pass custom data with my events?
General options are: pass data in an event instance, or only use event.target reference in event handler to access some data from source.
If you choose to access all necessary data through event.target -- no additional work nedded, just cast this reference in event handler to appropriate class.
If you want to pass some data along with event, you subclass Event, and this class should be publicly visible to the code that handles events, as the answer above states. AS3 is all about strict and strong typing, so why would you resist that?
Overriding clone() method in an Event subclass is only necessary if you are going to redispatch handled events. The official docs say you must do that every time you create a custom event class, just to be safe.
don't forget to override clone. it's also a good idea to override toString for debugging.
here's an example of one of my custom events:
package com.mattie.events
{
//Imports
import flash.events.Event;
//Class
public class SearchFieldEvent extends Event
{
//Constants
public static const SEARCH_COMPLETE:String = "search complete";
//Variables
public var totalResults:uint;
public var duration:uint;
public var searchText:String;
//Constructor
public function SearchFieldEvent(type:String, totalResults:uint = 0, duration:uint = 0, searchText:String = "")
{
super(type);
this.totalResults = totalResults;
this.duration = duration;
this.searchText = searchText;
}
//Override clone
public override function clone():Event
{
return new SearchFieldEvent(type, totalResults, duration, searchText);
}
//Override toString
public override function toString():String
{
return formatToString("SearchFieldEvent", "type", "totalResults", "duration", "searchText");
}
}
}

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