Access of undefined property issues in AS3 - actionscript-3

I am having a bit of trouble with some AS3. First time using this language and have more experience with web development then OOP so am getting a bit confused.
I am trying to make it so that when someone clicks a 'powerbutton' which is a "movieclip" symbol within flash then another symbol should then become visible. This is all being done within the Kitchen class.
The code for the main class is which i got from a youtube tutorial video i followed;
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.events.Event;
import Kitchen
public class DragFood extends MovieClip
{
protected var originalPosition:Point;
var myKitchen:Kitchen
public function DragFood() {
myKitchen = new Kitchen;
originalPosition = new Point (x, y);
buttonMode = true;
addEventListener (MouseEvent.MOUSE_DOWN, down);
}
protected function down (event:MouseEvent):void
{
parent.addChild(this);
startDrag();
stage.addEventListener (MouseEvent.MOUSE_UP, stageUp);
}
protected function stageUp (event:MouseEvent):void
{
stage.removeEventListener (MouseEvent.MOUSE_UP, stageUp);
stopDrag();
if (dropTarget)
{
if(dropTarget.parent.name == "bowl")
{
trace("The " + this.name + " is in the bowl");
this.visible = false;
} else {
returnToOriginalPosition();
}
} else {
returnToOriginalPosition();
}
}
protected function returnToOriginalPosition():void
{
x = originalPosition.x;
y = originalPosition.y;
}
}
}
Within it i call the other class;
import Kitchen
public class DragFood extends MovieClip
{
protected var originalPosition:Point;
var myKitchen:Kitchen
The code for the kitchen class is;
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.events.Event;
public class Kitchen extends MovieClip
{
// This is a function. This particular function has the same name as our class and therefore will be executed first
public function Kitchen()
{
// This is a "call" to another function that is defined later in the program.
init();
trace("Hello world");
}
public function init():void
{
// If we want an object (on the screen or otherwise) to be notified about an event we must add a listener for that event to that object.
// We also need to specify what happens everytime the event we are listening for happens.
PowerButton.addEventListener(MouseEvent.CLICK, handleButtonClicks);
}
//This function is called when the oven on button recieves a click.
public function handleButtonClicks(event:MouseEvent):void
{
OvenOn.visible = true;
trace("the oven is being switched on");
}
}
}
The issue i keep getting is that OvenOn and PowerButton are giving me a undefined access issue and im not sure how to fix it. I have found posts on similar subjects like - Access of Undefined property? Actionscript 3
but im not quite sure how to apply it to my issue if anyone could offer any help that would be great.

When you're programming on the timeline, code is referencing the local namespace, and objects you make there (movieclips, textfields, etc.) are automatically instantiated in that namespace so that you can simply call OvenOn.visible = true. However, for each class, their local namespace is whatever is inside the class, so unless you actually created a property on your class called OvenOn, it will most definitely give you Access of Undefined Property errors.
Think of each class as its own island. For them to touch eachother, they need some sort of connection. That connection can be made once the parent instantiates the class in its own namespace. For example...
var foo:String = "Hello!";
var bar:MyClass = new MyClass();
// At this point, whatever code runs inside of MyClass has no concept of foo, or how to access it.
addChild(bar);
// Now that we've added it to the stage, the bar has some properties that have automatically been populated such as "root", "parent", or "stage".
foo.someProperty = "World";
// Since this namespace has a variable pointing to the instance, we can change properties on that class.
Now that we've instantiated MyClass on the stage, we can reference parent properties the class didn't know about. Mind you, this is not necessarily best practice.
package
public class MyClass extends MovieClip {
var someProperty:String = "cheese";
public function MyClass() {
trace(parent.foo) // this will fail
addEventListener(Event.ADDED_TO_STAGE, test);
}
public function test(e:Event):void {
trace(this["parent"].foo); // this will succeed
}
}
}
If you absolutely must change something that is not part of your Kitchen class, pass either the parent of OvenOn or that object specifically as a property of Kitchen. You could do this a couple ways.
with the Constructor...
var something:*;
public function MyClass(someObject:*) {
something = someObject;
}
public function test():void {
something.visible = false;
}
...or by Assigning the Property...
var bar:MyClass = new MyClass();
bar.something = OvenOn;
bar.test(); // will turn off the OvenOn now that 'something' is pointing to it.

Related

AS3 Access a method inside the Main class from another class . Gives error?

I have trouble with actionScript , im trying to use a simple one line code to access a method inside the Document Class (Main) , but every time i got error . i tried the same code with a movieClip on stage, it work nicely .
Main Class linked to the fla :
package {
import flash.display.*;
import flash.events.*;
public class Main extends MovieClip {
public function Main() {
if (stage) {
init();
}
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
button.addEventListener(MouseEvent.CLICK,_click);
}
private function _click(e:MouseEvent):void {
var l:Leecher = new Leecher();
l.leech();
}
public function callMe():void {
trace("hey nice work");
}
}
}
Leecher Class :
package {
import flash.display.*;
public class Leecher extends MovieClip {
public function leech():void
{
trace(" leech function ");
Main(parent).callMe(); // output null object
Main(root).callMe(); // output null object
Main(Main).callMe(); // output null object
}
}
}
The Same code , but the class linked to a button on stage
package
{
import flash.display.*;
import flash.events.*;
public class Button extends MovieClip {
public function Button() {
this.addEventListener(MouseEvent.CLICK,r_click);
}
private function r_click(e:MouseEvent):void {
var l:Leecher = new Leecher();
l.leech();
Main(parent).callMe(); // hey nice work
Main(root).callMe(); // hey nice work
Main(Main).callMe(); // output null object
}
}
}
The errors are because when that code runs, the Leecher instance has not yet been added to the display list, and as such does not have a parent or root or stage (so parent is null).
Here is a breakdown of what's happening (explained with code comments):
private function _click(e:MouseEvent):void {
//you instantiate a new Leecher object
var l:Leecher = new Leecher();
//you call leech, but this new object does not have a parent because you haven't added it to the display list (via `addChild(l)`)
l.leech();
}
//your saying parent should be of type Main, then call the callMe method. However, parent is null because this object is not on the display list
Main(parent).callMe();
//same as above, except using root
Main(root).callMe();
//Here you are saying the Main class is of type Main (which since Main is a class and not an instance of Main will error or be null)
Main(Main).callMe();
The root, parent & stage vars of a display object are only populated when said display object is added to to the display list. In the case of root & stage the parent (and any grand parents) must also be added so that the top most parent/grandparent is the stage.
As a result, you need to wait until it's safe to access parent by listening for the Event.ADDED_TO_STAGE event.
private function _click(e:MouseEvent):void {
var l:Leecher = new Leecher();
//call the leech method once the child has been added to the stage and has a parent value
l.addEventListener(Event.ADDED_TO_STAGE, l.leech, false, 0, true);
addChild(l);
}
If you do the above, you'll need to add an optional event parameter to the leech method or you'll get an error:
public function leech(e:Event = null):void
{
To make your Main class easily accessible, you could use a static reference.
Static vars are not tied to an instance of an object, but to the class itself.
public class Main extends MovieClip {
//create a static var that holds a reference to the root/main instance
public static var main:Main;
public function Main() {
//assign the static var to this (the instance of Main)
main = this;
//...rest of code
If you do that, you can asses your root anywhere in your code by doing Main.main so in your example you could then do:
Main.main.callMe();
I'd recommend reading about static vars more before going crazy using them. Doing what I've just shown for an easy reference to your document class / root is safe, but in other contexts there are some memory & performance nuances it's best to be aware of.

Getting the error 1119: Access of possibly undefined property visible through a reference with static type Class

I am attempting to hide a symbol (Grill image) as soon as my animation loads.
Currently I am getting the error, E:\Burger Game\DragandDrop\Dragable.as, Line 4, Column 8 1119: Access of possibly undefined property visible through a reference with static type Class. As you can probably tell, I am new to flash.
package DragandDrop
{
Grill.visible=false;
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.geom.Point;
public class Dragable extends MovieClip
{
protected var homePos:Point;
var totalToBowl:int =3;
var i:int = 0;
public function Dragable ()
{
homePos=new Point( x, y);
buttonMode =true;
addEventListener ( MouseEvent.MOUSE_DOWN, move);
}
//egg functions
protected function move(event:MouseEvent) :void
{
parent.addChild(this);
startDrag();
stage.addEventListener(MouseEvent.MOUSE_UP, stageUp)
}
//item drop function
protected function stageUp(event:MouseEvent):void
{
stopDrag();
if (event.target.dropTarget != null &&dropTarget.parent.name == "Bowl")
{
scaleX=scaleY=0;
alpha=0.5;
y= stage.stageHeight-height -700;
x=stage.stageWidth-width- 1400;
buttonMode=false;
removeEventListener(MouseEvent.MOUSE_DOWN, stageUp)
i++
}if (i == totalToBowl){
i=10
trace(i);
event.target.dropTarget.visible = false;
}
if (i==10 )
{
dropTarget.parent.visible = false;
}else{
returnToHome();
}
}
protected function returnToHome():void
{
x = homePos.x;
y= homePos.y;
}
}
Any idea why I am getting this error?
Any help would be massively appreciated.
Many thanks,
Rob
There are two issues:
Grill is a class, but it would seem you are trying to use it like an instance. This is what it's expecting to see when used like you're doing:
public class Grill extends MovieClip {
public static var visible:Boolean;
}
But more than likely, what you need to do is work with an instance, not the class itself:
var g:Grill = new Grill();
g.visible = false;
If this class is linked to a timeline instance, you'd have to use the instance name you gave it (and make sure that instance name doesn't clash with any Class names - or use getChildByName).
Assuming this is not meant to be static code, you have code outside of a function/method that will cause another error.
In class files, all non-static functional code needs to be in a function. You need to move that line in question (Grill.visible=false) into a function. Most likely, you want this to be the equivalent of timeline code. So the best place to put would be this:
public function Dragable ()
{
homePos=new Point( x, y);
buttonMode =true;
addEventListener ( MouseEvent.MOUSE_DOWN, move);
//addedToStage is the best equivalent of when timeline code would run
addEventListener(Event.ADDED_TO_STAGE, addedToStage);
}
private function addedToStage(e:Event):void {
//where grillinstance is the instance name of your grill
grillInstance.visible = false;
}
Now, this assumes you have this class linked at timeline that has an instance of Grill on it. If this is an incorrect assumption, please clarify with a comment or by updating your question.

Adding eventlisteners in main document class for external classes

I have a small project I'm trying to help learn as3. It is a variation from the book Foundation Game Design with Actionscript 3.0. I am using an fla only to have a document class. All art is loaded within the as files. In the book, he just put all the code in the document class, I followed along and it worked as expected. I am trying to break out the code into separate classes to get a handle on OOP. One class makes a background - Background.as, one makes a character - Character.as, and one makes a button, which I instantiate 6 times for 6 different buttons - GameButton.as. And of course there is GameWorld.as which is the document class. Everything loads and shows up as expected. However when I try and add an eventListener for the buttons, I don't get any response. I have tried putting the eventListener in the GameButton.as and also tried it in the GameWorld.as neither of which has worked. Also I pass a reference to the stage when instantiating the various classes, because when I tried to addChild in the GameWorld.as, nothing would show up. I searched the site and found something similar, but it didn't seem to help. Thank you in advance for any advice you my have. Here is the code:
GameWorld.as
package
{
import flash.net.URLRequest;
import flash.display.Loader;
import flash.display.Sprite;
import flash.display.DisplayObject
import flash.events.MouseEvent;
import GameButton;
import Character;
import Background;
[SWR(width = "550", height = "400", backgroundColor = "#FFFFFF", frameRate = "60")]
public class GameWorld extends Sprite
{
//public variables
//Background
public var gameBackground:Background;
//Character
public var catCharacter:Character;
//Buttons
public var upButton:GameButton;
public var downButton:GameButton;
public var growButton:GameButton;
public var shrinkButton:GameButton;
public var vanishButton:GameButton;
public var spinButton:GameButton;
public function GameWorld ()
{
//Add the background to the stage
gameBackground = new Background("../images/background.png", stage);
//Add the character(s) to the stage
catCharacter = new Character("../images/character.png", stage);
//Set initial character position
catCharacter.CharacterPos(225, 150);
//Add the buttons to the stage
upButton = new GameButton("../images/up.png", stage, 25, 25);
downButton = new GameButton("../images/down.png", stage, 25, 85);
growButton = new GameButton("../images/grow.png", stage, 25, 145);
shrinkButton = new GameButton("../images/shrink.png", stage, 425, 25);
vanishButton = new GameButton("../images/vanish.png", stage, 425, 85);
spinButton = new GameButton("../images/spin.png", stage, 425, 145);
//Button event handlers
upButton.addEventListener(MouseEvent.CLICK, upButtonHandler);
}
public function upButtonHandler(event:MouseEvent)
{
trace("You clicked the up button!");
catCharacter.CharacterMove(15);
}
}
}
GameButton.as
package
{
import flash.net.URLRequest;
import flash.display.Loader;
import flash.display.Sprite;
import flash.display.Stage;
import flash.events.MouseEvent;
public class GameButton extends Sprite
{
//public variables
public var stageRef:Stage;
public var urlRequest:URLRequest;
public var gameButtonLoader:Loader;
public var gameButtonSprite:Sprite;
//Constructor
public function GameButton (urlRequest:String, stageRef:Stage, xPos:Number, yPos:Number)
{
this.stageRef = stageRef
this.urlRequest = new URLRequest();
gameButtonLoader = new Loader();
gameButtonSprite = new Sprite();
this.urlRequest.url = urlRequest;
gameButtonLoader.load(this.urlRequest);
gameButtonSprite.addChild(gameButtonLoader);
this.stageRef.addChild(gameButtonSprite);
gameButtonSprite.buttonMode = true;
gameButtonSprite.x = xPos;
gameButtonSprite.y = yPos;
}
}
}
Character.as
package
{
import flash.net.URLRequest;
import flash.display.Loader;
import flash.display.Sprite;
import flash.display.Stage;
public class Character
{
//private variables
private var stageRef:Stage;
private var urlRequest:URLRequest;
private var characterLoader:Loader;
private var characterSprite:Sprite;
//public variables
public var character_x_pos:Number;
public var character_y_pos:Number;
//Constructor
public function Character (urlRequest:String, stageRef:Stage)
{
this.stageRef = stageRef;
this.urlRequest = new URLRequest();
characterLoader = new Loader();
characterSprite = new Sprite();
this.urlRequest.url = urlRequest;
characterLoader.load (this.urlRequest);
characterSprite.addChild (characterLoader);
this.stageRef.addChild (characterSprite);
characterSprite.mouseEnabled = false;
}
//Set the position of the character
public function CharacterPos(xPos:Number, yPos:Number):void
{
characterSprite.x = xPos;
characterSprite.y = yPos;
}
//Move the position of the character
public function CharacterMove( yPos:Number):void
{
characterSprite.y -= yPos;
}
}
}
Background.as
package
{
import flash.net.URLRequest;
import flash.display.Loader;
import flash.display.Sprite;
import flash.display.Stage;
public class Background
{
//Private variables
private var stageRef:Stage;
private var urlRequest:URLRequest;
private var backgroundLoader:Loader;
private var backgroundSprite:Sprite;
//Constructor
public function Background (urlRequest:String, stageRef:Stage)
{
this.stageRef = stageRef;
this.urlRequest = new URLRequest();
backgroundLoader = new Loader();
backgroundSprite = new Sprite();
this.urlRequest.url = urlRequest;
backgroundLoader.load (this.urlRequest);
backgroundSprite.addChild (backgroundLoader);
this.stageRef.addChild (backgroundSprite);
backgroundSprite.mouseEnabled = false;
}
}
}
All art is loaded within the as files.
This is not an approach I recommend. There's a reason God gave us the Flash IDE--and it's not to write code! Any time you're spending on layout and viduals in code is just wasted, unless you have an actual requirement to change the visuals at runtime. The fact that your paths are all hard-coded suggests that you don't have that requirement.
So let's step back and imagine that you have a Symbol that contains 6 Symbols that you've created as just Flash buttons (when you select Button as the Symbol type). These will be SimpleButtons, but in the Class below we're just going to type them as DisplayObject. The Class doesn't care what they are, but using Simplebutton gives them up, over, down and hit states that require no code.
Note that the below assumes you have "automatically declare stage instances" off, which is IMO the best way to do things.
package view {
public class NavBar extends Sprite {
//because you put these on stage in the Symbol, they will be available in the constructor
public var upButton:DisplayObject;
public var downButton:DisplayObject;
public var growButton:DisplayObject;
public var shrinkButton:DisplayObject;
public var rotateButton:DisplayObject;
public var vanishButton:DisplayObject;
//makes it easier to do the same setup on all buttons
protected var allButtons:Vector.<DisplayObject> = <DisplayObject>([upButton, downButton, growButton, shrinkButton, rotateButton, vanishButton]);
public function NavBar() {
super();
for each (var btn:DisplayObject in allButtons) {
btn.buttonMode = true;
btn.mouseChildren = false;
btn.addEventListener(MouseEvent.CLICK, onButtonClick);
}
}
protected function onButtonClick(e:MouseEvent):void {
switch (e.target) {
case upButton:
dispatchEvent(new CharacterEvent(CharacterEvent.UP));
break;
case downButton:
dispatchEvent(new CharacterEvent(CharacterEvent.DOWN));
break;
case growButton:
dispatchEvent(new CharacterEvent(CharacterEvent.GROW));
break;
case shrinkButton:
dispatchEvent(new CharacterEvent(CharacterEvent.SHRINK));
break;
case rotateButton:
dispatchEvent(new CharacterEvent(CharacterEvent.ROTATE));
break;
case vanishButton:
dispatchEvent(new CharacterEvent(CharacterEvent.VANISH));
break;
default:
break;
}
}
}
}
Note that there's zero layout code. This code is dependent on a custom Event Class. I'm going to write that Event Class so that it always bubbles. That way, it can be dispatched anywhere on the display list and received at the top level:
package control {
class CharacterEvent extends Event {
public static var UP:String = 'characterUp';
public static var DOWN:String = 'characterDown';
public static var GROW:String = 'characterGrow';
public static var SHRINK:String = 'characterShrink';
public static var ROTATE:String = 'characterRotate';
public static var VANISH:String = 'characterVanish';
public function CharacterEvent(type:String) {
super(type, true, true);//always bubbles
}
public function clone():Event {
return new CharacterEvent(type);
}
}
}
Now, if you want to manually handle instantiation of the Symbol that has view.NavBar as its base class, it will look like this:
package {
public var navBar:NavBar;
class GameWorld {
public function GameWorld() {
try {
var navClass:Class = getDefinitionByName('NavBarSymbol') as Class;
} catch (e:Error) {
trace('You need to have a Library symbol called NavBarSymbol');
}
if (navClass) {
navBar = new navClass() as NavBar;
//unnecessary layout code here
//Note that this is NOT the responsibility of the child Class!
addChild(navBar);
}
//instantiate character
...
//by listening to the whole Document, you can add other things that
//dispatch Character events on the display list, like a keyboard listener
addEventListener(CharacterEvent.UP, moveCharacterUp);
//listeners for the rest of the character events...
}
public function moveCharacterUp(e:CharacterEvent):void {
//character move logic
}
//other handlers
}
}
Personally, I'd just add the navBar to the stage, and then there's no need to manage it at all (not even reference it with a variable), simply add the event listeners for the various character events.
The root of your problem doesn't seem to be the character code. However, I'm going to give you a few "best practice" pointers about it.
The convention in AS3 is for Class members (properties and methods) to be camel case starting with a lower case letter. So, characterPos() and characterMove().
Your Class already contains character in the name, so really these should just be pos() and move() (though there's no need now to shorten position()).
The only thing your child Classes are doing with their references to the parent are adding themselves. They don't need and shouldn't have a reference to the parent for this purpose. It is the parent's responsibility to add the Children (or the responsibility of the Flash Player if you use the stage).
That said, you could give your Character a reference to the parent Class typed as IEventDispatcher and allow the Character to listen to this channel. This concept is called an event bus.
Note that the reason that so many people do what you're doing is that Adobe failed to document how to properly use OOP with the timeline. Unfortunately, by the time a few of us started documenting that around late 2009/early 2010, the damage was done and everyone assumed that if you wanted to write good code you had to pretend the timeline and stage didn't exist.
I know I've covered a lot of ground, and probably most of what I said directly contradicts what you thought you knew, so please don't hesitate to ask any questions you might have.

How to improve this AS3 code structure to be more effective?

I have made an AS3 code to be a function. But I think my code is too lengthy. Could you help to improve it? Thank you!
I created test.fla first and added 5 grey block(external pictures from PSD) to stage. My function is to display different pictures when hovering mouse on corresponding grey block.
I converted those 5 grey blocks to Movie Clip and set instance name as sp1, sp2, sp3, sp4 and sp5. Then I created a document class, test.as and set 5 EventListener.
sp1.addEventListener(MouseEvent.MOUSE_OVER,clickmouse1);
sp2.addEventListener(MouseEvent.MOUSE_OVER,clickmouse2);
sp3.addEventListener(MouseEvent.MOUSE_OVER,clickmouse3);
sp4.addEventListener(MouseEvent.MOUSE_OVER,clickmouse4);
sp5.addEventListener(MouseEvent.MOUSE_OVER,clickmouse5);
So my first question is can I have any method to combine those 5 EventListener to be one? Because in my mind, so many EventListener will cost much more resource of PC.
My second question is I set 5 target pictures as 5 class.
In test.as I created code below:
public class EuroCup extends Sprite{
var arr:Array=new Array();
var Res1:Result609=new Result609();
var Res2:Result610=new Result610();
var Res3:Result611=new Result611();
var Res4:Result612=new Result612();
var Res5:Result613=new Result613();
var i:int=0;
public function EuroCup() {
arr[1]=Res1;
arr[2]=Res2;
arr[3]=Res3;
arr[4]=Res4;
arr[5]=Res5;
}
}
I think that is too lengthy. Is there any way to simplify it?
Here is the test.fla and test.as:Download
Whatever, thank u guys!
Restructuring:
public class EuroCup extends Sprite {
private var arr:Array;
public function EuroCup() {
arr = [ new Result609(), new Result610(),
new Result611(), new Result612(), new Result613()
];
}
}
Then use results as arr[0], arr[1] and so on. Also, if you have several sprites to listen clicks on, with similar listeners, you can connect all such sprites to single listeners and use event.target to distinguish them, where event is MouseEvent. Or place them into container and create one listener to that container - again, event.target will tell what sprite is clicked.
And yet two things - every time you see new Array(), replace it with [] - its faster and shorter. And place all code into constructor, not class body - it will be compiled to be executed faster.
You can/should use a Dictionary for associations between the grey rects and the images to display.
package {
public class EuroCup {
private var _children:Array, _current:Sprite, _map:Dictionary;
public function EuroCup() {
super();
initialize();
}
protected function initialize():void {
_children = [];
_map = new Dictonary();
// i don't know the image's symbol name.
// _map[_children[_children.length] = new Result609()] = new SYMBOL_NAME();
for each(var child:Sprite in _children) {
child.addEventListener(MouseEvent.CLICK, click_handler);
}
}
private function click_handler(event:MouseEvent):void
{
if (_current) {
_current.visible = false; // or use fading, etc
}
_current = _map[event.currentTarget] as Sprite;
if (_current) {
_current.visible = true; // or use fading, etc
}
}
}
}
One option for simplifying the code would be to associate the sp and Res instances with each other by identity, using a Dictionary. That allows you to avoid the work of tracking array indices, which is half of the reason you have separate event handler methods. Once the instances are associated by identity, then you can use the currentTarget property of a dispatched event to determine which element in the Dictionary you want to show on the stage.
package {
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.events.Event;
import flash.utils.Dictionary;
public class test extends Sprite
{
var dict:Dictionary = new Dictionary();
var visibleResult:MovieClip;
public function test()
{
dict[sp1]=new Result609();
dict[sp2]=new Result610();
dict[sp3]=new Result611();
dict[sp4]=new Result612();
dict[sp5]=new Result613();
sp1.addEventListener(MouseEvent.MOUSE_OVER,clickmouse);
sp2.addEventListener(MouseEvent.MOUSE_OVER,clickmouse);
sp3.addEventListener(MouseEvent.MOUSE_OVER,clickmouse);
sp4.addEventListener(MouseEvent.MOUSE_OVER,clickmouse);
sp5.addEventListener(MouseEvent.MOUSE_OVER,clickmouse);
}
private function clickmouse(evt:MouseEvent):void
{
if(visibleResult)
{
removeChild(visibleResult);
}
var Res:MovieClip = dict[evt.currentTarget] as MovieClip;
addChild(Res);
Res.x=300;
Res.y=400;
visibleResult=Res;
}
}
}
If you expect to have more than 5 sp instances in the application, then you could use a loop to assign the event listeners. But for less than 10 instances, you probably don't gain much from a loop.
I would go for a more simple version; add only one event listener and use Event.target to determine on which item is clicked, using a switch-statement.
This is helpful if the buttons should do different things.
package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
public class Test extends Sprite
{
public var sp1:Sprite;
public var sp2:Sprite;
public var sp3:Sprite;
public function Test()
{
this.addEventListener(MouseEvent.MOUSE_OVER, handleClick);
}
private function handleClick(event:MouseEvent):void
{
trace("Clicked on: " + event.target)
switch (event.target)
{
case this.sp1:
{
// do something here
break;
}
case this.sp2:
{
// do something here
break;
}
case this.sp3:
{
// do something here
break;
}
default
{
trace("No handler defined for: " + event.target)
}
}
}
}
}
However, you can also make smart use of it's type. Let's say all you buttons extend a custom class called CustomButton, and they all need to do the same (like call a function), but with a parameter based on it's id.
This is helpful if the buttons should basically do the same thing.
package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
public class Test extends Sprite
{
public function Test()
{
this.addEventListener(MouseEvent.MOUSE_OVER, handleClick);
}
private function handleClick(event:MouseEvent):void
{
if (event.target is CustomButton)
{
var button:CustomButton = event.target as CustomButton; // you're now sure it's a CustomButton
this.showById(button.id); // let's say CustomButton has a public var 'id'
}
}
private function showById(id:int):void
{
// do something
}
}
}
Hope that helps.
Tip: Always start your class+filename with a capital. Variables start with capitals. This is very common in the actionscript world.

custom AS3 Loader class that uses a custom LoaderInfo class?

This is a question specifically about creating a custom Loader class as a followup to How do I modify existing AS3 events so that I can pass data?. If this wasn't the right way to go about this, let me know.
I have a custom Loader class and a custom LoaderInfo class. What I can't figure out is how to have the Loader class use the custom LoaderInfo class as it's contentLoaderInfo property.
package com.display {
import flash.display.Loader;
import com.display.CustomLoaderInfo;
public class CustomLoader extends Loader {
public var customData:*;
public function CustomLoader(passedData: *= null) {
customData = passedData;
}
}
}
^ Have to do something in there to make it have the new CustomLoaderInfo
package com.display {
import flash.display.LoaderInfo;
import flash.events.Event;
import com.events.CustomEvent;
public class CustomLoaderInfo extends LoaderInfo {
public var customData:*;
public function CustomLoaderInfo(passedData: *= null) {
customData = passedData;
}
override public function dispatchEvent(event:Event):Boolean {
var customEvent:CustomEvent = new CustomEvent(event.type, customData, event.bubbles, event.cancelable);
return super.dispatchEvent(customEvent);
}
}
}
^ That might work, but since I can't get CustomLoader to use it, I don't know yet.
I don't know how it fits into what you're doing, but you could not bother making an extended LoaderInfo at all. Loader.contentLoaderInfo has a property called loader that will return the Loader (or in this case CustomLoader) that was used. In theory you can just do this with the CustomLoader class that you have:
var loader: CustomLoader = new CustomLoader("Extra Data");
loader.load(new URLRequest("file.swf"));
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderComplete);
function loaderComplete(event: Event) : void
{
var customData:* = (event.target.loader as CustomLoader).customData;
trace(customData); // Extra Data
}
You would have to override the function where the loaderinfo instance is created, and that might be in a private function. In the new function you could then instanciate your custom loaderInfo class instead, but you would also have to do anything else that the overwritten method does. You might run into some security sandbox problems with loadinfo as well. Overwriting a function like this is usually only posible when the function written with this in mind.
Alternatively you could use the prototype chain (read here) to change the loaderInfo class at runtime. But I wouldn't recommend it. It's not good practice in my opinion.
If you get this to work you still have the problem that your custom event will not work with any event that has properties not inheritet from the Event class (like the ProgressEvent that has progress related properties).
I would say you properly should look for another solution.
In the question you link to you talk about sending movieclip with your event. Have you thought about reaching the other way? When you recieve the event, you get a reference to the object that dispatched it (Event.target). Can you not use that reference to get the movieclip?
Perhaps you could explain your problem in more detail (maybe in a new question so you still keep this open), I am sure there is a better / easier way to solve it.
I needed something like this because I wanted to carry an index with the info ... ie - have something like event.target.index available after an event is triggered .. anyway i designed a class that contained the loader and the loader info... heres the class
public class LoaderBox extends Sprite {
public static var PROGRESS:String = "progress"
public static var COMPLETE:String = "complete"
public var id:int
public var index:int
public var loader:Loader
public var info:LoaderInfo
public var isOpen:Boolean
//
public var percent:Number = -1
public function load(path:String,idx:int=-1,nm:String=null){
loader = new Loader()
if (nm != null){
name = nm
}
index = idx
var req:URLRequest = new URLRequest(path)
info = loader.contentLoaderInfo
info.addEventListener(Event.COMPLETE,complete)
info.addEventListener(ProgressEvent.PROGRESS,progress)
isOpen = true
loader.load(req)
}
private function complete(e:Event):void{
isOpen = false
dispatchEvent(new Event(LoaderBox.COMPLETE))
}
private function progress(e:ProgressEvent):void{
if (e.target.bytesTotal>0){
percent = Math.floor(e.target.bytesLoaded/e.target.bytesTotal * 100)
}
dispatchEvent(new Event(LoaderBox.PROGRESS))
}
}
A potential issue with the flagged answer: if contentLoaderInfo spits out a IOError, you can't access the .loader property to access your custom loader class.
What I did is the following:
* in my custom loader class, create the following method:
public function requestError(event:Event):void {
dispatchEvent(event);
}
when adding a listener to contentLoaderInfo for the IOerror, point to the custom loader class's method:
_loaderCls.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, _loaderCls.requestError);
Then, add the same listener to your loader class and make it call any method you need. At that point, the event.target would be that of your custom loader class and you can add any extra info you need to that class:
_loaderCls.addEventListener(IOErrorEvent.IO_ERROR, requestError);
or you can do a better thing to pass data into the Loader class:
package com.display
{
import flash.display.Loader;
public class Loader extends flash.display.Loader
{
private var _obj:Object;
public function Loader():void
{
super();
}
public function get obj():Object
{
return _obj;
}
public function set obj(o:Object):void
{
_obj = o;
}
}
}