ActionScript 3.0 How to call SoundManager to all classes - actionscript-3

i have 3 classes. the SoundManager.as, MainMenu.as, and OnGame.as.
How can I call SoundManager on MainMenu.as and OnGame.as properly?
I tried:
MainMenu.as:
var sound:SoundManager = new SoundManager();
OnGame.as:
var sound:SoundManager = new SoundManager();
but when i turn off the bgmusic on OnGame.as, the bgmusic on MainMenu doesn't turn off.
Sorry for my bad english and explanation. please help me.
//edited
When i call function 'MUTE' from the SoundManager in onGame.as and go back to mainmenu, the bgmusic in MainManu.as is not muted. help please me.
SoundManager.as
public static var mVolume:SoundTransform = new SoundTransform();
public static var mChannel:SoundChannel = new SoundChannel();
public static var mPosition:Number;
public static var music:Sound = new Sound();
public static var Music:Boolean = true;
public function LOADMUSIC():void {
if(Music){
UNMUTE();
}else {
MUTE();
}
music.addEventListener(Event.COMPLETE, LOADMUSIC);
mChannel = music.play();
mChannel.addEventListener(Event.SOUND_COMPLETE, ONCOMPLETE);
}
public function ONCOMPLETE(e:Event):void {
if(DataBase.music){
UNMUTE();
}else{
MUTE();
}
e.currentTarget.removeEventListener(Event.SOUND_COMPLETE, ONCOMPLETE);
LOADMUSIC();
}
public function REMOVE_MUSIC():void{
try{
mChannel.stop();
music = null;
}catch(e:Error) {}
}
public function MUTE():void {
mVolume.volume = 0;
mChannel.soundTransform = mVolume;
}
public function UNMUTE():void {
mVolume.volume = 1;
mChannel.soundTransform = mVolume;
}
MainMenu.as
var sound:SoundManager;
btn_music.addEventListener(TouchEvent:TOUCH_END, MUSIC);
public MainMenu(sound:SoundManager){
this.sound = sound;
sound.REMOVE_MUSIC();
SoundManager.music = new BackgroundMusic01();
sound.LOADMUSIC();
}
private function MUSIC(e:TouchEvent):void {
if(SoundManager.Music){
SoundManager.music = false;
sound.MUTE();
}else {
SoundManager.Music = true;
sound.UNMUTE();
}
}
OnGame.as
var sound:SoundManager;
btn_music.addEventListener(TouchEvent:TOUCH_END, MUSIC);
public OnGame(sound:SoundManager){
this.sound = sound;
sound.REMOVE_MUSIC();
SoundManager.music = new BackgroundMusic02();
sound.LOADMUSIC();
}
private function MUSIC(e:TouchEvent):void {
if(SoundManager.Music){
SoundManager.music = false;
sound.MUTE();
}else {
SoundManager.Music = true;
sound.UNMUTE();
}
}
There's no problem in changing the background music. When i mute the bgmusic in MainMenu using MainMenu btn_music it works, it works also in OnGame. But if it is from OnGame to MainMenu or MainMenu to Ongame, the bgmusic is not muted . I don't see what's wrong. please help me. sorry for my bad english.

Singleton or some other static (global) access is one easy way to do it. But just to add an alternative solution, according to some a "better way" is to use dependency injection. A simple example of this for your situation could look like this:
First, in your MainMenu and OnGame class you add a constructor argument (effectively declaring a dependency) of a SoundManager instance:
public class MainMenu {
private var sound:SoundManager;
public function MainMenu(sound:SoundManager){
this.sound = sound;
}
}
public class OnGame {
private var sound:SoundManager;
public function OnGame(sound:SoundManager){
this.sound = sound;
}
}
Then in a higher level class, you can create a single SoundManager and pass it into the classes that need it:
public class Main {
private var sound:SoundManager;
public function Main(){
sound = new SoundManager();
}
private function showMenu():void {
var menu:MainMenu = new MainMenu(sound);
addChild(menu);
}
private function showGame():void {
var game:OnGame = new OnGame(sound);
addChild(game);
}
}
The end result is that you have a single SoundManager instance being re-used between various classes.

There are several ways to do it, one of them is to use a Singleton class.
Follow an example:
package
{
public class CustomSoundManager
{
private static var _instance:CustomSoundManager;
public function CustomSoundManager()
{
if (_instance)
{
throw new Error('CustomSoundManager... use getInstance()');
}
_instance = this;
}
public static function getInstance():CustomSoundManager
{
if (!_instance)
{
new CustomSoundManager();
}
return _instance;
}
public function soundOn():void
{
// your logic to turn the sound on
}
public function soundOff():void
{
// your logic to turn the sound off
}
}
}
So, doesn't matter where (e.g. MainMenu.as, OnGame.as), you can use just these methods:
CustomSoundManager.getInstance().soundOn();
CustomSoundManager.getInstance().soundOff();

Because i can't see what's wrong in my code. Since I only got 1 channel in my game, i used SoundMixer to mute and unmute the music background.
import flash.media.SoundMixer;
...
...
public function MUTE():void {
mVolume.volume = 0;
SoundMixer.soundTransform = mVolume;
}
public function UNMUTE():void {
mVolume.volume = 1;
SoundMixer.soundTransform = mVolume;
}
thanks.

Related

Starling not displaying graphic

Hi guys i am new to AS3 and to Starling i am having problem displaying an image in a different class. it does show on my game menu class but i wanted it to show on my play game class.
so i got 3 classes Main that starts the starling that runs GameMenu class.
"GameMenu class"
package {
import starling.display.BlendMode;
import starling.display.Button;
import starling.display.Image;
import starling.display.Sprite;
import starling.events.Event;
public class GameMenu extends Sprite {
private var bg:Image;
private var gameLogo:Image;
private var playBtn:Button;
private var rankBtn:Button;
private var settingBtn:Button;
private var inGame:PlayGame;
public function GameMenu ()
{
super ();
this.addEventListener (Event.ADDED_TO_STAGE, onAddedToStage);
}
private function onAddedToStage (event:Event):void
{
this.removeEventListener (Event.ADDED_TO_STAGE, onAddedToStage);
drawScreen ();
}
private function drawScreen ():void
{
bg = new Image(Assets.getAtlas().getTexture(("Background.png")));
bg.blendMode = BlendMode.NONE;
this.addChild(bg);
gameLogo = new Image(Assets.getAtlas().getTexture(("GameLogo.png")));
gameLogo.x = stage.stageWidth/2 - gameLogo.width/2;
gameLogo.y = 30;
this.addChild(gameLogo);
playBtn = new Button(Assets.getAtlas().getTexture("PlayBtn.png"));
playBtn.x = stage.stageWidth/2 - playBtn.width/2;
playBtn.y = 450;
playBtn.addEventListener(Event.TRIGGERED, onPlayClick);
this.addChild(playBtn);
rankBtn = new Button(Assets.getAtlas().getTexture("RankBtn.png"));
rankBtn.x = rankBtn.bounds.left + 60;
rankBtn.y = 600;
rankBtn.addEventListener(Event.TRIGGERED, onRankClick);
this.addChild(rankBtn);
settingBtn = new Button(Assets.getAtlas().getTexture("SettingBtn.png"));
settingBtn.x = settingBtn.bounds.right + 60;
settingBtn.y = 600;
settingBtn.addEventListener(Event.TRIGGERED, onSettingClick);
this.addChild(settingBtn);
}
private function onRankClick (event:Event):void
{
trace("LEADERBOARD BUTTON HIT")
}
private function onSettingClick (event:Event):void
{
trace("SETTING SCREEN BUTTON HIT")
}
private function onPlayClick (event:Event):void
{
playBtn.removeEventListener(Event.TRIGGERED, onPlayClick);
trace("PLAY BUTTON HIT")
gameLogo.visible = false;
playBtn.visible = false;
rankBtn.visible = false;
settingBtn.visible = false;
//bg.visible = false;
inGame = new PlayGame();
}
}
}
this class works perfectly now.
"PlayGame class"
package {
import starling.display.Image;
import starling.display.Sprite;
import starling.events.Event;
public class PlayGame extends Sprite
{
private var bubble:Image;
public function PlayGame ()
{
trace("PlayGame");
super ();
this.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage2);
}
private function onAddedToStage2 (event:Event):void
{
trace("OnAddedToStage");
this.removeEventListener (Event.ADDED_TO_STAGE, onAddedToStage2);
drawScreen ();
}
public function drawScreen ():void
{
trace("Bubble");
bubble = new Image(Assets.getAtlas().getTexture(("Bubble.png")));
bubble.x = 100;
bubble.y = 100;
this.addChild(bubble);
}
}
}
the bubble image is now showing and i don't know why?
They are too much parenthesis, but this is not your issue
bubble = new Image(Assets.getAtlas().getTexture(("Bubble.png")));
//is less clean/readable than
bubble = new Image(Assets.getAtlas().getTexture("Bubble.png"));
When facing this kind of issues, if starling/air doesn't report any errors, you should try to be sure the display object are currently rendered.
Try to apply a color instead of the texture.
bubble = new Image( Texture.fromColor(64,64,0xff99ff) );
If this code shows a fancy rectangle of 64 pixel/side, you trouble come from your texture atlas or texture. Be sure to have a valided atlas, validates frames, and names.
If this code doesn't show the facy rectangle, your issue doesn't come from the texture atlas or texture, but more possibly from the display list of starling.
And in your case,
I think you should just need to addChild the Ingame in your GameMenu class :
GameMenu :
private function onPlayClick (event:Event):void
{
//... your stuff
inGame = new PlayGame();
this.parent.addChild(inGame);
}
And it should works.

use of addChild inside a function to add a child into a previously added instance

I wrote a simple function "adone" to add things to the stage and today I decided to make it add child to other objects as well but the test function "ad2" I made is not working right. what do you suggest?
package {
import flash.display.MovieClip;
public class main extends MovieClip {
public var ui:Array = new Array;
public var splz:Array = new Array;
public var pows:powsys = adone("powsz",powsys,ui,400,240);
public var s1:powsyspsl = ad2("s1",powsyspsl,splz,100,100,"powsz");
public function main() {
}
public function adone(nm,tp,lst,ex=0,ey=0) {
nm = new tp();
addChild(nm);
lst.push(nm);
nm.x = ex;
nm.y = ey;
}
public function ad2(nm,tp,lst,ex=0,ey=0,par=null) {
nm = new tp();
par.addChild(nm);
lst.push(nm);
nm.x = ex;
nm.y = ey;
}
}
}
public var pows:powsys = adone("powsz",powsys,ui,400,240);
you are setting first parameter "powsz" but you're not using this parameter, you're just changing it with nm = new tp(); when your adone() function worked, so it is looking like working properly...
and here...
public var s1:powsyspsl = ad2("s1",powsyspsl,splz,100,100,"powsz");
you're not making the same fault as in "adone()" so it is still a string variable and you're trying to add a child to a string variable "powsz" here? i think you should fix that
par.addChild(nm);
but if you don't wanna fix things but you wanna your code work unproperly you can try this
public function ad2(nm,tp,lst,ex=0,ey=0,par=null) {
nm = new tp();
par = new tp();
par.addChild(nm);
lst.push(nm);
nm.x = ex;
nm.y = ey;
}
And all this stuff looks like a joke! Your problems not going to be solved by this way, you have to fix your whole code and logic.. You're using lots of unnecessary stuff and wrong ways to make what you want...
changed the code to:
package {
import flash.display.MovieClip;
public class main extends MovieClip {
public var ui:Array = new Array ;
public var splz:Array = new Array ;
public var pows:powsys = adone("pows",powsys,ui,400,240);
public var s1:powsyspsl = adone("s1",powsyspsl,splz,100,100,pows);
public function main() {
}
public function adone(nm,tp,lst,ex=0,ey=0,par=null) {
nm = new tp ;
if (par) {
par.addChild(nm);
} else {
addChild(nm);
}
lst.push(nm);
nm.x = ex;
nm.y = ey;
}
}
}
the "par" var returns null both times in the trace. and that means 2nd object is added to the stage not to 1st one.
Untested....
package {
import flash.display.MovieClip;
public class main extends MovieClip {
public var ui:Array = new Array;
public var splz:Array = new Array;
public var pows:powsys = adone(powsys,ui,400,240);
public var s1:powsyspsl = adone(powsyspsl,ui,400,240,pows);
public function main() {
}
public function adone(tp,lst,ex=0,ey=0,par=null):Object {
var nm = new tp();
if (par) {
par.addChild(nm);
} else {
addChild(nm);
}
lst.push(nm);
nm.x = ex;
nm.y = ey;
return nm;
}
}
}

Haxe: Return value of field

For some reason, I can't modify the value of a field in Haxe. Of course, this doesn't seem to be affecting all of my fields, just this one. Here's (what I'm pretty sure is) the applicable code. First, in the parent class:
class TopMenu extends Sprite
{
public function new()
{
super();
init();
}
private function init()
{
var tempField:BitmappedTextField = new BitmappedTextField( "File", 100, false );
trace( tempField.textWidth );
}
}
Then, in the child class:
class BitmappedTextField extends Sprite
{
private var _fieldText:String;
private var _fieldWidth:Int;
private var _addToStage:Bool;
public var textWidth:Int;
public function new( thisText:String, thisWidth:Int = 100, adTStg:Bool = true )
{
super();
_fieldText = thisText;
_fieldWidth = thisWidth;
_addToStage = adTStg;
textWidth = 55;
init();
}
public function init()
{
textWidth = 777;
}
}
I would expect the trace statement to return 777, but instead it will always return 55. In fact, no matter what I do, I can't seem to modify a field outside of the constructor class and then retrieve that value via the parent class. There's something horribly simple I must be missing, but I just can't figure it out. Maybe it has to do with the way Haxe uses getters and setters? Any help is appreciated, thank you.
I cant reproduce your problem however and you are missing a ; and a super call.
Try this code.
package;
import nme.display.Sprite;
import nme.display.MovieClip;
class HelloWorld extends MovieClip
{
public function new( )
{
super();
var tempField:BitmappedTextField = new BitmappedTextField();
trace( tempField.textWidth );
}
}
class BitmappedTextField extends Sprite
{
public var textWidth:Int;
public function new( )
{
super();
textWidth = 55;
init( );
}
public function init( )
{
textWidth = 777;
}
}

Definition fl.video.FLVPlayback could not be found

I'm stumped. I have two flash files I'm authoring.
File A has a MovieClip on stage that has a linkage to a class in which I import fl.video.FLVPlayback
File B also attempts to import fl.video.FLVPlayback.
File B throws a COMPILE TIME error that it cannot locate the definition for fl.video.FLVPlayback. I'm noticing that my FlashDevelop also offers no syntax highlighting for that line.
Both are exporting for the same version of FlashPlayer (10). Both are being authored on the same platform, the same software (CS4).I have not messed with any Publish settings, other than that File B is associated with a Document Class.
Of interest may be that File A will eventually be loaded into File B, into the context of File B.
What is up? I have no idea where to even start looking.
Thanks in advance.
If you're not using the FLVPlayback component (dragged from the component library onto the stage), then Flash does not have access to the fl package out of the box for publishing.
You would have to include either the component source folder or .swc on your class path (source folder would go in the "Source Path" tab of your as3 publish settings, .swc in the "Library Path" tab) in order for your class to work.
The source folder is:
C:\Program Files (x86)\Adobe\Adobe Flash CS4\Common\Configuration\Component Source\ActionScript 3.0\FLVPlayback
The .swc is in the directory:
C:\Program Files (x86)\Adobe\Adobe Flash CS4\Common\Configuration\Components\Video
The swc is probably easier to include as you can copy and paste the .swc directly into your project folder if you like.
Building on Sapptime's answer, I would like to add that you can create different profiles under Publish Settings.
So you can make a profile which includes the FLVPlayback component by importing the .swc file and use that profile when you need to work with the FLVPlayer. Adds about 100 KB to the project.
This way you don't need a FLVPlayback component in your library or on your stage. Instead, you can import the FLVPlayback class like any other class in your project and make instances of FLVPlayback in your actionscript code.
//import:
import fl.video.FLVPlayback;
//Instantiate:
private var player:FLVPlayback = new FLVPlayback();
I have added a Videoplayer.as class (because I can't find a way to attach it) I made for a project and stripped it quick and dirty for some additional content, but it should work :) Feel free to use it as is, modify it or get some inspiration.
Put Videoplayer.as in the src folder of your project and make a new instance of it. Use the setters to control it.
//Instantiate
var MyPLayer:Videoplayer = new Videoplayer();
//Use setters
MyPLayer.SetVideopath = path to flv file;
MyPLayer.SetVideoAutoplay = true; // or false
//... and so on
// add to displaylist
this.addChild(MyPlayer);
// Load video
MyPlayer.Load();
// start playing
MyPlayer.Play();
and here is the Videoplayer class...
package {
import fl.video.*;
import flash.events.*;
import flash.display.Sprite;
import flash.display.Shape;
public class Videoplayer extends Sprite {
// VIDEO
private var player:FLVPlayback = new FLVPlayback();
private static var videoPath:String="";
private var w:Number = 1280;
private var h:Number = 720;
private var vol:Number = 0;
private var autoplay:Boolean = false;
private var autorewind:Boolean = false;
private var Loop:Boolean = false;
private var bgcolor:uint = 0x000000;
private var HasError:Boolean=false;
private var playerid:Number;
private var SeekSecToStop:Number=0;
private var BufferTime:Number=0;
private var videoBG:Shape;
// ===============================================================================================
// CONSTRUCTOR
// ===============================================================================================
public function Videoplayer() {
super();
trace("Videoplayer");
this.addChild(player);
player.addEventListener(VideoEvent.STATE_CHANGE, VidState, false, 0, true);
player.addEventListener(VideoEvent.READY, VidReady, false, 0, true);
player.addEventListener(VideoEvent.AUTO_REWOUND, VidRewinded, false, 0, true);
player.addEventListener(VideoEvent.STOPPED_STATE_ENTERED, VidStopped, false,0,true);
}
// ===============================================================================================
// SET VIDEO PROPS
// ===============================================================================================
private function setVidProps():void {
player.name = "player";
player.skinBackgroundColor = getVideoBGcolor;
player.skinBackgroundAlpha = 0;
player.registrationX = 0;
player.registrationY = 0;
player.setSize(getVideoWidth,getVideoHeight);
player.scaleMode = "maintainAspectRatio"; // exactFit, noScale, maintainAspectRatio
//player.fullScreenTakeOver = false;
player.isLive = false;
player.bufferTime = BufferTime;
player.autoRewind = getVideoAutorewind;
player.volume = vol;
}
// ===============================================================================================
// LOAD
// ===============================================================================================
public function Load():void {
trace("Load");
setVidProps();
player.source = getVideopath;
}
// ===============================================================================================
// PLAY
// ===============================================================================================
public function Play():void {
player.playWhenEnoughDownloaded();
UnMute();
}
public function Pause():void {
player.pause();
}
public function Stop():void {
//player.seek(SeekSecToStop);
player.stop();
//player.pause();
}
public function SeekAndStop():void {
player.seek(SeekSecToStop);
player.pause();
}
public function SeekAndPlay(n:Number=0):void {
player.seek(n);
Play();
}
public function Fullscreen():void {
//player.fullScreenTakeOver = true;
//player
}
public function Mute():void {
player.volume = 0;
}
public function UnMute():void {
player.volume = 1;
}
public function Volume(n:Number):void {
player.volume=n;
}
// ===============================================================================================
// VidReady
// ===============================================================================================
private function VidReady(e:Event):void {
trace("VidReady");
//player.removeEventListener(VideoEvent.READY, VidReady);
player.fullScreenTakeOver = false;
if (autoplay) {
player.autoPlay = autoplay;
Play();
} else {
player.play();
SeekAndStop();
}
dispatchEvent(new VideoEvent(VideoEvent.READY));
}
// ===============================================================================================
// VidStopped
// ===============================================================================================
private function VidStopped(e:Event):void {
trace("VidStopped");
//dispatchEvent(new VideoEvent(VideoEvent.STOPPED));
if(Loop) {
//SeekAndPlay();
Play();
} else {
dispatchEvent(new VideoEvent(VideoEvent.STOPPED_STATE_ENTERED));
}
}
// ===============================================================================================
// VidRewinded
// ===============================================================================================
private function VidRewinded(e:Event):void {
trace("VidRewinded");
}
// ===============================================================================================
// VidState
// ===============================================================================================
private function VidState(e:Event):void {
var flvPlayer:FLVPlayback = e.currentTarget as FLVPlayback;
//Log("VideoState 1 : "+flvPlayer.state);
if (flvPlayer.state==VideoState.CONNECTION_ERROR) {
trace("FLVPlayer Connection Error! -> path : "+flvPlayer.source);
//dispatchEvent(new VideoEvent(VideoEvent.CONNECTION_ERROR));
HasError=true;
//CleanUp();
} else if (flvPlayer.state==VideoState.BUFFERING) {
trace("BUFFERING");
} else if (flvPlayer.state==VideoState.DISCONNECTED) {
trace("DISCONNECTED");
} else if (flvPlayer.state==VideoState.LOADING) {
trace("LOADING");
} else if (flvPlayer.state==VideoState.PAUSED) {
trace("PAUSED");
} else if (flvPlayer.state==VideoState.RESIZING) {
trace("RESIZING");
} else if (flvPlayer.state==VideoState.REWINDING) {
trace("REWINDING");
} else if (flvPlayer.state==VideoState.SEEKING) {
trace("SEEKING");
} else if (flvPlayer.state==VideoState.PLAYING) {
trace("PLAYING");
} else if (flvPlayer.state==VideoState.STOPPED) {
trace("STOPPED");
//flvPlayer.pause();
} else if (flvPlayer.state==VideoState.RESIZING) {
trace("RESIZING");
}
}
// ===============================================================================================
// SETTERS & GETTERS
// ===============================================================================================
public function set SetPlayerId(n:Number):void {
playerid=n;
}
public function get getPlayerId():Number {
return playerid;
}
public function set SetSeekSecToStop(n:Number):void {
SeekSecToStop=n;
}
public function get getSeekSecToStop():Number {
return SeekSecToStop;
}
public function set SetVideoLoop(b:Boolean):void {
Loop = b;
}
public function get getVideoLoop():Boolean {
return Loop;
}
public function set SetVideoAutorewind(b:Boolean):void {
autorewind = b;
}
public function get getVideoAutorewind():Boolean {
return autorewind;
}
public function set SetVideoAutoplay(b:Boolean):void {
autoplay = b;
}
public function get getVideoAutoplay():Boolean {
return autoplay;
}
public function set SetVideopath(s:String):void {
videoPath = s;
}
public function get getVideopath():String {
return videoPath;
}
public function set SetVideoWidth(n:Number):void {
w = n;
}
public function get getVideoWidth():Number {
return w;
}
public function set SetVideoHeight(n:Number):void {
h = n;
}
public function get getVideoHeight():Number {
return h;
}
public function set SetVideoBGcolor(n:uint):void {
bgcolor = n;
}
public function get getVideoBGcolor():uint {
return bgcolor;
}
public function get getPlayerState():String {
return player.state;
}
public function get GetHasError():Boolean {
return HasError;
}
}
}
You need to make sure that the FLVPlayback component is present in you library and exported for ActionScript (which should be the default setting).
To add it to the library, simply open the Components panel (Window -> Components) and expand the group named Video and drag FLVPlayback in your library. No need to put it on the stage.
It should be exported by default as "fl.video.FLVPlayback".
Cheers

ActionScript - Global Custom Events?

up until now, the way i've been needing to handle my own custom events is by adding an event listener to the object that was dispatching the custom event. while this method of event handling works just fine, i've come to the point where i would like my custom events to be globally accessible, where the listening object does not need to be the same object that is dispatching the event.
in this example, my main Controller class is instantiating and adding to the display list 2 sprite classes: Square and Triangle. the 4th and final class is a custom event called ColorChangeEvent.
i'm attempting to dispatch a new ColorChangeEvent from the Square class, which uses a timer to dispatch a new random color once every second, while Triangle will listen for the dispatched event and change its fill color to the color that was dispatched by Square.
Controller.as:
package
{
import flash.display.Sprite;
public class Controller extends Sprite
{
public function Controller()
{
var sq:Square = new Square();
sq.x = sq.y = 100;
var tr:Triangle = new Triangle();
tr.x = tr.y = 250;
addChild(sq);
addChild(tr);
}
}
}
Square.as:
package
{
import flash.display.Sprite;
import flash.events.TimerEvent;
import flash.utils.Timer;
public class Square extends Sprite
{
public function Square()
{
graphics.beginFill(0x999999);
graphics.drawRect(0, 0, 100, 100);
graphics.endFill();
var myTimer:Timer = new Timer(1000);
myTimer.addEventListener(TimerEvent.TIMER, dispatchNewColor);
myTimer.start();
}
private function dispatchNewColor(evt:TimerEvent):void
{
var randomColor:Number = Math.random() * 0xFFFFFF;
trace("Square Class Dispatched: " + randomColor);
dispatchEvent(new ColorChangeEvent(ColorChangeEvent.CHANGE, randomColor));
}
}
}
Triangle.as:
package
{
import flash.display.Sprite;
import flash.geom.ColorTransform;
public class Triangle extends Sprite
{
public function Triangle()
{
graphics.beginFill(0x999999);
graphics.moveTo(0, 0);
graphics.lineTo(100, 50);
graphics.lineTo(-50, 150);
graphics.endFill();
addEventListener(ColorChangeEvent.CHANGE, changeColor);
}
private function changeColor(evt:ColorChangeEvent):void
{
var ct:ColorTransform = new ColorTransform;
ct.color = evt.color;
transform.colorTransform = ct;
trace("Triangle Class Received: " + evt.color);
}
}
}
ColorChangeEvent.as:
package
{
import flash.events.Event;
public class ColorChangeEvent extends Event
{
public static const CHANGE:String = "change";
public var color:Number;
public function ColorChangeEvent(type:String, color:Number)
{
super(type);
this.color = color;
}
override public function clone():Event
{
return new ColorChangeEvent(type, color);
}
}
}
needless to say, this isn't working.
of course, i could add the event listener to the Square instance in the Controller class, who's event handler could pass that value to Triangle via a public function to change the color, but this is exactly the kind of limitation i'm trying to avoid.
it's not always easy to access and pass a value to a class from where the custom event is dispatched, which is why i'm looking for an actual global solution to handling custom events.
I have been using this class for some time now. To use it you would do this in square:
data.EventManager.instance.publish("someName", randomColor);
and then in your Triangle:
data.EventManager.instance.subscribe("someName", handleColorChange);
private function handleColorChange(color:Number):void {
// implementation here
}
You can even pass the ColorChangeEvent instead of just the color.
data.EventManager.instance.publish(ColorChangeEvent.CHANGE, new ColorChangeEvent(ColorChangeEvent.CHANGE, randomColor);
And then
data.EventManager.instance.subscribe(ColorChangeEvent.CHANGE, handleColorChange);
private function handleColorChange(colorChangeEvent:ColorChangeEvent):void {
// implement here
}
I removed a lot of code that is specific to my projects, so I am not 100% it is usable exactly as-is. But, you should be able to modify it to get it working correctly. If not, let me know and I can try to work it out with you.
This class handles additional things that I will not go into, though you are free to explore. Be aware, however, that anything that subscribes for event notification has a strong reference by the EventManager. That means that if you want to destroy something for garbage collection, you need to call EventManager.instance.cancel(ColorChangeEvent.CHANGE, handleColorChange) before the Triangle instances can be collected.
package data {
import flash.utils.*;
public class EventManager extends Object {
private var _subscribers:Dictionary;
private var _calls:Dictionary;
private var _feeds:Dictionary;
private var _requests:Dictionary;
private var _notify:Dictionary;
private var _services:Dictionary;
private static var __instance:EventManager;
public function EventManager() {
if (__instance) {
trace("EventManager is a Singleton class which should only be accessed via getInstance()");
}
_feeds = new Dictionary(true);
_subscribers = new Dictionary(true);
_requests = new Dictionary(true);
_services = new Dictionary(true);
_notify = new Dictionary(true);
}
public function getFeedData($name:String) {
if (_feeds[$name]) {
return _feeds[$name];
}
return undefined;
}
public function unpublish($name:String) {
var _post:* = _feeds[$name];
delete _feeds[$name];
return _post;
}
public function cancel($name:String, $subscriberFunc:Function, ...args): void {
var _cnt:Number;
var _subscriberArray:Array;
if (_subscribers[$name]) {
for (_cnt = 0; _cnt < _subscribers[$name].length; _cnt++) {
if (_subscribers[$name][_cnt] == $subscriberFunc) {
_subscribers[$name].splice(_cnt, 1);
}
}
}
if (_requests[$name]) {
_subscriberArray = _requests[$name];
_cnt = _subscriberArray.length;
while (_cnt > 0) {
if (_subscriberArray[_cnt] == $subscriberFunc) {
_subscriberArray.splice(_cnt, 1);
}
_cnt--;
}
}
}
public function subscribe($name:String, $subscriber:Function, ...args): void {
var _funcArray:Array;
var _func:Function;
if (_feeds[$name]) {
$subscriber(_feeds[$name]);
}
if (! _subscribers[$name]) {
_subscribers[$name] = new Array();
}
_subscribers[$name].push($subscriber);
if (_notify[$name]) {
_funcArray = _notify[$name];
for each (_func in _funcArray) {
_func();
}
delete _notify[$name];
}
}
public function request($name:String, $feedFunction:Function): void {
var _requestArray:Array;
var _request:Function;
if (! _feeds[$name]) {
if (! _requests[$name]) {
_requests[$name] = new Array();
}
_requests[$name].push($feedFunction);
} else {
$feedFunction(_feeds[$name]);
}
if (_notify[$name]) {
_requestArray = _notify[$name];
for each (_request in _requestArray) {
_request();
}
delete _notify[$name];
}
}
public function publish($name:String, $data:*, $args:Object = null): void {
var _subscriberArray:Array;
var _func:Function;
var cnt:Number = 0;
_feeds[$name] = $data;
if (_subscribers[$name] != undefined) {
_subscriberArray = _subscribers[$name].slice();
_cnt = 0;
while (_cnt < _subscriberArray.length) {
_func = _subscriberArray[_cnt] as Function;
if ($args) {
_func($data, $args);
}else {
_func($data);
}
_cnt++;
}
}
if (_requests[$name]) {
_subscriberArray = _requests[$name].slice();
delete _requests[$name];
_cnt = 0;
while (_cnt < _subscriberArray.length) {
if (_subscriberArray[_cnt] != null) {
_subscriberArray[_cnt]($data);
}
_cnt++;
}
}
}
public function notify($name:String, $subscriber:Function): void {
if (_requests[$name] || _subscribers[$name]) {
$subscriber();
}else {
if (! _notify[$name]) {
_notify[$name] = new Array();
}
_notify[$name].push($subscriber);
}
}
public static function getInstance(): EventManager {
if (! __instance) {
__instance = new EventManager();
}
return __instance;
}
public static function get instance(): EventManager {
return getInstance();
}
}
}
I got this to work by creating a singleton: EventDispatchSingleton that extends EventDispatcher. It's basically an empty singleton that provides the dispatchEvent and add/removeEventListener methods (these are automatically provided by extending EventDispatcher).
Anywhere I want to dispatch an event I import EventDispatchSingleton and then call EventDispatchSingleton.instance.dispatchEvent(<someEvent>);.
Then, wherever I want to listen to that event, I just import EventDispatchSingleton and call EventDispatchSingleton.instance.addEventListener(eventName, callback);
You should look into event bubbling, specificly I think you will find the Capturing phase of the event propagation useful. Take a read of Event propagation from Adobe LiveDocs. It's in the Flex docs, but it is about AS3 Events.
Also Senocular has a good post on Flash Event Bubbling.