Flash events execution order - actionscript-3

Check out the next code, tell me what do you expect to be printed. Then run it and check what is really happen.
package
{
import flash.display.Sprite;
import flash.events.Event;
public class TestFlashEvents extends Sprite
{
private static const DUMMY_EVENT:String = "DummyEvent";
private var dummyObjects:Vector.<DummyObject> = new Vector.<DummyObject>(100);
public function TestFlashEvents()
{
for(var i:int = 0; i < dummyObjects.length; i++){
dummyObjects[i] = new DummyObject(this);
addEventListener(DUMMY_EVENT, dummyObjects[i].listener);
}
removeEventListener(DUMMY_EVENT, dummyObjects[41].listener);
dispatchEvent(new Event(DUMMY_EVENT));
}
private var counter:int = 0;
public function onGettingEvent(dummyObject:DummyObject):void{
if(counter == 25){
for(var i:int = 0; i < 50; i++){
removeEventListener(DUMMY_EVENT, dummyObjects[i].listener);
trace("Removing", dummyObjects[i].id);
}
}
trace("Handeling event", counter, dummyObject.id);
counter++;
}
}
}
import flash.events.Event;
class DummyObject
{
private static var dummyObjectsCounter:int = 0;
public var id:String;
private var tester:TestFlashEvents;
public function DummyObject(tester:TestFlashEvents)
{
this.tester = tester;
id = "DummyObject " + dummyObjectsCounter;
dummyObjectsCounter++;
}
public function listener(event:Event):void{
tester.onGettingEvent(this);
}
}
The removeEventListener function is actually not working. Tell me what do you think about it. I also open a bug in adobe.

This code means Adobe caches event listener list prior to actually calling event listeners. It is an unusual behavior to have two listeners for one particular event over one single object, but if it happens, Adobe assumed that all listeners should be invoked prior to actually modifying this list. I was actually expecting all 99 listeners to get called. So, this behavior can even be by design, because re-rendering the event listener list while processing a single event will put a too heavy load on Flash, so that the lags will galore. No one wants lags.

This can easily be fixed by prioritizing you event listeners.
This is not a Flash bug, it is, like Vesper said caching of event listeners to prevent lag.
Here is the updated version of your code, mark the prioritizing on the addEventListener call.
package
{
import flash.display.Sprite;
import flash.events.Event;
public class TestFlashEvents extends Sprite
{
private var _this = this;
private static const DUMMY_EVENT:String = "DummyEvent";
private var dummyObjects:Vector.<DummyObject> = new Vector.<DummyObject>(100);
public function TestFlashEvents()
{
for(var i:int = 0; i < dummyObjects.length; i++)
{
dummyObjects[i] = new DummyObject(this);
addEventListener(DUMMY_EVENT, dummyObjects[i].listener, false, dummyObjects.length - i);
}
removeEventListener(DUMMY_EVENT, dummyObjects[41].listener);
dispatchEvent(new Event(DUMMY_EVENT));
}
private var counter:int = 0;
public function onGettingEvent(dummyObject:DummyObject):void
{
if (counter == 25)
{
for (var i:int = 0; i < 50; i++)
{
removeEventListener(DUMMY_EVENT, dummyObjects[i].listener);
trace("Removing", dummyObjects[i].id);
}
}
trace("Handeling event", counter, dummyObject.id);
counter++;
}
}
}
import flash.events.Event;
class DummyObject
{
private static var dummyObjectsCounter:int = 0;
public var id:String;
private var tester:TestFlashEvents;
public function DummyObject(tester:TestFlashEvents)
{
this.tester = tester;
id = "DummyObject " + dummyObjectsCounter;
dummyObjectsCounter++;
}
public function listener(event:Event):void{
tester.onGettingEvent(this);
}
}

Related

Score not displaying in AS3

I've got this code that mostly works. I know the ammo is being tracked correctly because I have it to be game over when the ammo runs out. My problem is that neither the score nor the remaining ammo are displaying. I'm not sure what I'm missing. Here's the code that I have relating to the issue.
package {
import flash.display.*;
import flash.events.*;
import flash.utils.Timer;
import flash.text.TextField;
import flash.media.Sound;
import flash.media.SoundChannel;
public class AirRaid extends MovieClip {
private var aagun:AAGun;
private var airplanes:Array;
private var bullets:Array;
public var leftArrow, rightArrow:Boolean;
private var nextPlane:Timer;
private var shotsLeft:int;
private var shotsHit:int;
public function startAirRaid () {
// init score
shotsLeft = 20;
shotsHit = 0;
showGameScore();
}
public function checkForHits (event:Event) {
for(var bulletNum:int = bullets.length - 1; bulletNum >= 0; bulletNum--) {
for (var airplaneNum:int = airplanes.length - 1; airplaneNum >= 0; airplaneNum-- ) {
if ( bullets[bulletNum].hitTestObject(airplanes[airplaneNum])) {
airplanes[airplaneNum].planeHit();
bullets[bulletNum].deleteBullet();
shotsHit++;
showGameScore();
break;
}
}
if ((shotsLeft == 0) && (bullets.length == 0)) {
endGame();
}
}
}
public function fireBullet() {
if (shotsLeft <= 0) return;
var b:Bullet = new Bullet(aagun.x, aagun.y, -300);
addChild(b);
bullets.push(b);
shotsLeft--;
showGameScore();
}
public function showGameScore() {
showScore.text = String("Score: " + shotsHit);
showShots.text = String("Shots Left: " + shotsLeft);
}
}
}
Please check if Font Embedding property on both showScore and showShots text fields are true (checked) in GUI editor in your project. If either text field is not added in GUI, use the approach in this question AS3 - TextField: Embedded font to start embedding fonts, or set a proper defaultTextFormat to either text field somewhere at initialization.

AS3 Scrolling Movieclip

I have a problem with my code whereby I have a spawned vertical movieclip where there are button instances in it which makes it look like a list.
The problem is that I am trying to recreate a iOS-style drag scrolling. When I hold and drag my movieclip, it works fine, scrolling up and down. But when I release my left mouse button, It registers a click on one of my buttons.
I tried to remove the event listeners on the buttons but the scrolling only works once, after I released my left mouse button, the whole scrolling does not work the second time.
Is it possible to have maybe like a mouse drag (up or down) ignoring the button click listeners however when the user want to click the button instead, the scrolling won't kick in?
My buttons' class
public function PlaceOneButtons()
{
for (var a=0; a<buttons.length; a++)
{
stationsone1[a].addEventListener(clicked,StationSelectOne);
stationsone2[a].addEventListener(clicked,StationSelectOne);
stationsone3[a].addEventListener(clicked,StationSelectOne);
stationsone4[a].addEventListener(clicked,StationSelectOne);
stationsone5[a].addEventListener(clicked,StationSelectOne);
}
}
My Main (spawner) class
package
{
import flash.display.MovieClip;
import flash.display.*;
import flash.text.*;
import flash.events.*;
import flash.ui.*;
import flash.utils.*;
import flash.media.*;
import IconSpawn;
import Scrolling;
public class MainClass extends MovieClip
{
private var iconspawn:IconSpawn = new IconSpawn();
private var touchay:int = new int;
private var touchPoint:int = new int;
private var touchPoint2:int = new int;
private var touchString:int = new int;
private var AYint:int = new int;
private var touchTimer:Timer = new Timer(150,1);
private var endTime:Timer = new Timer(1,1);
private var speed:int = new int;
public static var scrollDiff:int = new int;
public static var doubleDiff:int = new int;
public static var dragging:Boolean = new Boolean
//private var scrolling:Scrolling = new Scrolling();
//public static var Ystore:Point;
public function MainClass()
{
// constructor code
AYint = IconSpawn.A_Y.y;
}
public function startApp()
{
addChild(iconspawn);
iconspawn.MenuSpawn();
dragging = false;
}
public function directionsApp()
{
addChild(iconspawn);
iconspawn.KeyboardOne();
}
public function placeOneApp()
{
addChild(iconspawn);
iconspawn.PlaceOneSpawn();
Evtlistener();
}
private function Evtlistener()
{
addEventListener(Event.ENTER_FRAME,update);
addEventListener(MouseEvent.MOUSE_DOWN,spawnTouch);
addEventListener(MouseEvent.MOUSE_UP,endScroll);
}
public function directionsApp2()
{
addChild(iconspawn);
iconspawn.KeyboardTwo();
}
public function update(evt:Event)
{
//trace(touchTimer);
//trace(touchString);
touchPoint2 = mouseY;
scrollDiff = touchPoint2 - touchPoint;
doubleDiff = scrollDiff - scrollDiff;
trace(dragging);
if(dragging == true)
{
//iconspawn.PlaceOneButtons();
}
}
public function spawnTouch(evt:MouseEvent)
{
touchPoint = mouseY;
touchTimer.addEventListener(TimerEvent.TIMER,timerTouch);
endTime.addEventListener(TimerEvent.TIMER,endTimer);
touchTimer.start();
dragging = true;
touchay = IconSpawn.A_Y.y;
}
public function timerTouch(evt:TimerEvent):void
{
if(dragging == true)
{
addEventListener(Event.ENTER_FRAME,startScroll);
}
}
public function startScroll(evt:Event)
{
if(mouseY > 540 && mouseY < 1510)
{
IconSpawn.A_Y.y = touchay + (touchPoint2 - touchPoint);
}
}
public function endScroll(evt:MouseEvent)
{
removeEventListener(MouseEvent.MOUSE_DOWN,spawnTouch);
removeEventListener(Event.ENTER_FRAME,startScroll);
touchTimer.reset();
endTime.start();
}
private function endTimer(evt:TimerEvent):void
{
dragging = false;
Evtlistener();
}
}
}
Help will be appreciated! Have been stuck at this problem for days now.
UPDATE: Added new updated code
Hi guys, now my problem is that after I scroll my movieclip, the code will listen out for scrollDiff if its = 0.
When scrollDiff is 0, the buttons of the movieclip is clickable but if its more or less than that, the buttons are not clickable. Now my new problem is that after I release my left click, the code does not update the scrollDiff to 0, so user have to double click to select the button. Help!
package
{
import flash.display.MovieClip;
import flash.display.*;
import flash.text.*;
import flash.events.*;
import flash.ui.*;
import flash.utils.*;
import flash.media.*;
import IconSpawn;
import Scrolling;
public class MainClass extends MovieClip
{
private var iconspawn:IconSpawn = new IconSpawn();
private var touchPoint:int = new int;
private var touchPoint2:int = new int;
private var AYint:int = new int;
private var touchTimer:Timer = new Timer(150,1);
private var endTimer:Timer = new Timer(150,1);
private var IconSpwnY:int = new int;
private var touchbool:Boolean = new Boolean
public static var scrollDiff:int = new int;
//private var scrolling:Scrolling = new Scrolling();
//public static var Ystore:Point;
public function MainClass()
{
// constructor code
}
public function startApp()
{
addChild(iconspawn);
iconspawn.MenuSpawn();
}
public function directionsApp()
{
addChild(iconspawn);
iconspawn.KeyboardOne();
}
public function placeOneApp()
{
AYint = IconSpawn.A_Y.y;
addChild(iconspawn);
iconspawn.PlaceOneSpawn();
addEventListener(Event.ENTER_FRAME,update);
addEventListener(MouseEvent.MOUSE_DOWN,spawnTouch);
addEventListener(MouseEvent.MOUSE_UP,endScroll);
touchbool = false;
//IconSpawn.container.mouseChildren = true;
}
public function directionsApp2()
{
addChild(iconspawn);
iconspawn.KeyboardTwo();
}
public function update(evt:Event)
{
touchPoint2 = mouseY;
scrollDiff = touchPoint2 - touchPoint;
trace(scrollDiff);
}
public function spawnTouch(evt:MouseEvent)
{
touchPoint = mouseY;
touchTimer.addEventListener(TimerEvent.TIMER,timerTouch);
touchTimer.start();
IconSpwnY = IconSpawn.A_Y.y;
if(scrollDiff == 0)
{
IconSpawn.container.mouseChildren = true; //Important <-
}
else
{
IconSpawn.container.mouseChildren = false; //Important <-
}
}
public function timerTouch(evt:TimerEvent):void
{
addEventListener(Event.ENTER_FRAME,startScroll);
touchbool = true
}
public function startScroll(evt:Event)
{
if(mouseY > 0 && mouseY < 1510)
{
IconSpawn.A_Y.y = IconSpwnY + (touchPoint2 - touchPoint);
}
}
public function endScroll(evt:MouseEvent)
{
removeEventListener(MouseEvent.MOUSE_DOWN,spawnTouch);
removeEventListener(Event.ENTER_FRAME,startScroll);
endTimer.addEventListener(TimerEvent.TIMER,endTiming);
endTimer.start();
trace("CALLL")
scrollDiff = touchPoint2 - touchPoint;
//touchTimer.reset();
}
private function endTiming(evt:TimerEvent)
{
IconSpawn.container.mouseChildren = true;
addEventListener(MouseEvent.MOUSE_DOWN,spawnTouch);
//addEventListener(Event.ENTER_FRAME,startScroll);
scrollDiff = 0;
}
}
}
While you're moving set <container_mc>.mouseChildren = false. When the container clip stops moving, set the mouseChildren property to 'true'.
Adding to Craig's answer (which I definitely recommend implementing, to make life easier!), here is the list of the event listeners you should have hooked up for this to work as planned. This is theory, so you may have to play around with it a bit.
container.addEventListener(MouseEvent.MOUSE_DOWN, response);: You'll want to raise some sort of flag that the mouse is down, and wait for the next mouse event, which determines the action.
container.addEventListener(MouseEvent.MOUSE_MOVE, response);: If the mouse is down, disable child clicking (Craig's answer) and initiate dragging. You'll also want to raise a dragging flag.
container.addEventListener(MouseEvent.MOUSE_UP, response);: If the dragging flag is raised, stop drag and enable child clicking. If it isn't raised, do nothing, so the item can take over from there.
item.addEventListener(MouseEvent.MOUSE_UP, itemResponse);: Your click action.
Theoretically, this should work fine with your nested MovieClips, as long as you use MouseEvent.MOUSE_UP as the listener on them (as shown above). Using MouseEvent.MOUSE_DOWN or MouseEvent.CLICK may mess your timing up. However, I'd experiment a bit to find the right combination, as I could be wrong on that last point.

AS3 Object Array not adding to stage

So I am new to AS3 and AS in general. I do know Java to a degree and PHP very well.
I am trying to learn by writing an app that creates a hex map programatically. I am using a library for hexagons which I will include below however, here is my issue.
When I run a for loop for say, a 10 count, and I then create a shape, add the shape and draw the shape, it has no issue. When in the same loop if I push a shape to an array, then add that array element, then draw it, I get nothing.
package
{
import flash.display.MovieClip;
import flash.display.Shape;
import flash.text.TextField;
public class Main extends MovieClip
{
private var radius:Number = 30;
private var sides:Number = 6;
private var myrotation:Number = 0;
private var lineColor:Number = 0x000000;
private var lineThickness:Number = 1;
private var l:TextField = new TextField();
private var f:Array = new Array(20);
public function Main()
{
l.text = "test";
addChild(l);
//WORKS should be red
for(var j:int = 0; j<stage.stageWidth/(radius*2);j++)
{
var t:Polygon = new Polygon();
addChild(t);
t.drawPolygon(radius,sides,2*radius*j,radius*2,0xFF0000,lineThickness,myrotation);
}
//DOES NOT WORK (note the *3 is so it is lower down) should be blue
for(var j:int = 0; j<stage.stageWidth/(radius*2);j++)
{
f.push(new Polygon());
addChild(f[j]);
f[j].drawPolygon(radius,sides,2*radius*j,radius*3,0x0000FF,lineThickness,myrotation);
}
}
}
}
The polygon class I am using is below. I grabbed it off the internets somewhere.
package
{
import flash.display.MovieClip;
import flash.events.Event;
public class Polygon extends MovieClip
{
//PROPERTIES
private var points:Array;
private var id:int;
private var ratio:Number;
private var top:Number;
private var fade_value:int;
//CONSTRUCTOR
public function Polygon()
{
addEventListener(Event.ADDED_TO_STAGE,init);
}
private function init(evt:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE,init);
stage.frameRate=31;
}
//METHODS
public function drawPolygon(radius:int,segments:int,centerX:Number,centerY:Number,tint:uint,line:int,rotating:Number):void
{
id=0;
points=new Array();
ratio=360/segments;
top=centerY-radius;
for(var i:int=rotating;i<=360+rotating;i+=ratio)
{
var xx:Number=centerX+Math.sin(radians(i))*radius;
var yy:Number=top+(radius-Math.cos(radians(i))*radius);
points[id]=new Array(xx,yy);
if(id>=1)
{
drawing(points[id-1][0],points[id-1][1],points[id][0],points[id][1],tint,line);
}
id++;
}
id=0;
}
private function radians(n:Number):Number
{
return(Math.PI/180*n);
}
private function drawing(startX:Number,startY:Number,stopX:Number,stopY:Number,tint:Number,line:int):void
{
graphics.lineStyle(line,tint,1);
graphics.moveTo(startX,startY);
graphics.lineTo(stopX,stopY);
}
public function fadeOut():void
{
fade_value=0;
addEventListener(Event.ENTER_FRAME,fade);
}
public function fadeIn():void
{
fade_value=1;
addEventListener(Event.ENTER_FRAME,fade);
}
//PRIVATE
private function fade(evt:Event):void
{
var da:Number=fade_value-alpha;
var aa:Number=da*.1;
alpha+=aa;
if(Math.abs(da)<=.05)
{
alpha=fade_value;
removeEventListener(Event.ENTER_FRAME,fade);
if(fade_value==0)
dispatchEvent(new Event('fadeOutDone'));
else
dispatchEvent(new Event('fadeInDone'));
}
}
}
}
----EDIT----
the code is now as follows with the same issues occurring. I've tried adding a vector and i tried casting the array element.
package
{
import flash.display.MovieClip;
import flash.display.Shape;
import flash.text.TextField;
public class Main extends MovieClip
{
private var radius:Number = 30;
private var sides:Number = 6;
private var myrotation:Number = 0;
private var lineColor:Number = 0x000000;
private var lineThickness:Number = 1;
private var l:TextField = new TextField();
private var f:Array = new Array(20);
private var v:Vector.<Polygon> = new Vector.<Polygon>(10);
public function Main()
{
l.text = "test";
addChild(l);
//WORKS should be red
for(var i:int = 0; i<stage.stageWidth/(radius*2);i++)
{
var t:Polygon = new Polygon();
addChild(t);
t.drawPolygon(radius,sides,2*radius*i,radius*2,0xFF0000,lineThickness,myrotation);
}
//DOES NOT WORK (note the *3 is so it is lower down) should be blue
for(var j:int = 0; j<stage.stageWidth/(radius*2);j++)
{
f.push(new Polygon());
addChild(f[j]);
Polygon(f[j]).drawPolygon(radius,sides,2*radius*j,radius*3,0x0000FF,lineThickness,myrotation);
}
for(var k:int = 0; k<stage.stageWidth/(radius*2);k++)
{
v.push(new Polygon());
addChild(v[k]);
v[k].drawPolygon(radius,sides,2*radius*k,radius*3.5,0x00FF00,lineThickness,myrotation);
}
}
}
}
compile notes...
Loading configuration file C:\Program Files (x86)\Adobe\Adobe Flash Builder 4.6\
sdks\4.6.0\frameworks\flex-config.xml
Initial setup: 64ms
start loading swcs 14ms Running Total: 78ms
Loaded 30 SWCs: 484ms
precompile: 841ms
C:\Users\jmasiello.place\Documents\flash\Main.as: Warning: This compila
tion unit did not have a factoryClass specified in Frame metadata to load the co
nfigured runtime shared libraries. To compile without runtime shared libraries e
ither set the -static-link-runtime-shared-libraries option to true or remove the
-runtime-shared-libraries option.
Files: 145 Time: 961ms
Linking... 25ms
Optimizing... 26ms
SWF Encoding... 11ms
C:\Users\jmasiello.place\Documents\flash\Main.swf (1809 bytes)
postcompile: 65ms
Total time: 1595ms
Peak memory usage: 47 MB (Heap: 29, Non-Heap: 18)
WWhen you do
private var f:Array = new Array(20);
You create an array with 20 elements in implements
Then later on you are pushing an element into the same array.
f.push(new Polygon());
By pushing an element you are adding to the last element
Which makes the array have the first 20 elements null and the 21st element be a Polygon
You can even verify it by doing.
for(var j:int = 0; j<stage.stageWidth/(radius*2);j++){
f.push(new Polygon());
trace(f)
}
So in your code you are pushing into the 21st element and then accessing the array via
addChild(f[j]);
Which j = 0 and the element in 0 is still null
Then best way to fix it would be to
private var f:Array = new Array();
Are you getting any errors? You probably need to cast to Polygon in order for the compiler to accept the drawPolygon method.
for(var j:int = 0; j<stage.stageWidth/(radius*2);j++) {
f.push(new Polygon());
addChild(f[j]);
Polygon(f[j]).drawPolygon(radius,sides,2*radius*j,radius*3,0x0000FF,lineThickness,myrotation;
}
To skip the casting you can use a Vector instead of an Array as then the compiler will know that it handles Polygons exclusively.

Dispatching event doesn't fire :(

package com.fladev.background
{
//import all classes
import caurina.transitions.Tweener;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.display.DisplayObject;
import flash.display.StageAlign;
import flash.display.StageDisplayState;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.FullScreenEvent;
import flash.events.MouseEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
public class MainClass extends Sprite
{
//create variables
private var loaderMenu:Loader;
private var loaderNames:Array = new Array ();
private var loaderContents:Array = new Array ();
private var loaderSlide:Loader;
private var swfDisplayObject:DisplayObject;
private var swfComObject:Object;
private var xmlLoader:URLLoader = new URLLoader();
private var xmlSlideLoader:URLLoader = new URLLoader();
public function MainClass()
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.addEventListener(Event.RESIZE, stageResize);
xmlLoader.addEventListener(Event.COMPLETE, showXML);
xmlLoader.load(new URLRequest("navigation.xml"));
//xmlSlideLoader.addEventListener(Event.COMPLETE, showSlideXML);
//xmlSlideLoader.load(new URLRequest("slides.xml"));
}
function showXML(e:Event):void
{
XML.ignoreWhitespace = true;
var menuBtns:XML = new XML(e.target.data);
var i:Number = 0;
for ( i = 0; i < menuBtns.navItem.length(); i++ )
{
loaderMenu = new Loader();
loaderMenu.name = menuBtns.navItem[i].name ;
loaderMenu.load(new URLRequest(menuBtns.navItem[i].swfURL));
loaderMenu.contentLoaderInfo.addEventListener(Event.COMPLETE, createSwfObjects);
}
}
private function createSwfObjects(event:Event):void
{
var swfContent = event.currentTarget.content as MovieClip ;
var swfName = event.currentTarget.loader ;
navigationContainer.addChild(event.target.loader);
showImage(swfContent);
if ( swfName.name == 'topNavigation' )
{
swfContent.addEventListener("clickHandle",topNavigationClickHandler);
}
}
private function topNavigationClickHandler():void
{
trace('Back to root');
}
private function showImage(navigationItem):void
{
try
{
navigationItem.alpha = 0;
Tweener.addTween(navigationItem, { alpha:1, time:1, transition:"easeOutSine" } );
navigationItem.smoothing = true;
} catch (e:Error) { trace('Error no tweening'); };
stageResize();
}
private function stageResize(e:Event=null):void
{
var centerImages:Array = new Array ( contentContainer, navigationContainer, backgroundImage ) ;
backgroundImage.x = 0;
backgroundImage.y = 0;
backgroundImage.scaleX = backgroundImage.scaleY = 1;
if ((stage.stageHeight / stage.stageWidth) < backgroundImage.height / backgroundImage.width) {
backgroundImage.width = stage.stageWidth;
backgroundImage.scaleY = backgroundImage.scaleX;
} else {
backgroundImage.height = stage.stageHeight;
backgroundImage.scaleX = backgroundImage.scaleY;
}
for each ( var centered:MovieClip in centerImages )
{
centered.x = stage.stageWidth / 2 - centered.width / 2;
centered.y = stage.stageHeight / 2 - centered.height / 2;
}
}
}
}
This is my code for the main.as.
And here my code for my loaded SWF on the maintimeline.
addEventListener(Event.ADDED_TO_STAGE, init);
function init(event:Event):void
{
trace('try dispatch');
dispatchEvent(new Event("clickHandle",true));
}
Try dispatch works, but it does not get back to the main to fire up "Back to root".
Any idea?
thx!
As long as all movieclips dispatching events are added to the display list, this should work. This makes me think that perhaps the event listener being added is not working. Try adding a trace statement to the block of code as shown below:
if ( swfName.name == 'topNavigation' )
{
trace("adding listener");
swfContent.addEventListener("clickHandle",topNavigationClickHandler);
}
I expect that this if condition is failing, and thus your listener is never being created. Also, you need to add a function parameter to the callback method "topNavigationClickHandler" to accept the event as the callback parameter. You have not done this, and this is an error that would be thrown at runtime when the event was received and dispatched to the callback method. You havn't seen this yet because your listener has never had to invoke the callback. So you're gonna have to fix this code like so:
private function topNavigationClickHandler(e:Event):void
{
trace('Back to root');
}
Also I just want to add that your if condition on setting this listener seems a bit redundant, since you already know you are expecting the navigation swf, because you're explicitly loading it. Also I don't believe the name property would be set like this. Typically the name is only set inside the IDE before compilation, and if it isn't, it gets dynamically generated at runtime. What might be more useful is to check the URL of the loaded SWF to see if it contains "topNavigation" or whatever the swf name is. You can do this like so:
var swfUrl:String = myLoader.contentLoaderInfo.url;
if (swfUrl.search("topNavigation") != -1){
//Match found, add listener for navigation
}

A loop in enterframe?

I'm animating a bunch of words in AS3. Because I'm going to be using this on a mobile device, I want to use bitmaps rather than Sprites. So I've created WordObjects, which have a .bitmap property that I can access.
I have the following code, which fires on the click event and loops through an array inside an enterframe event. This is probably a bad idea, but I'm not sure how to do it better. (What is surprising is that it runs just fine in Flashbuilder, but slows to a crawl in Flash CS5.)
Is there some better way to do this? I just want an efficient way to animate the array of bitmaps.
private function clickhandler (e:MouseEvent){
this.addEventListener(Event.ENTER_FRAME, blowemup);
}
private function blowemup(e:Event){
var newPosition:Number;
for(var i:int=0; i<arrWordObjects.length; i++)
{
newPosition = updatePosition(arrWordObjects[i].bitmap);
arrWordObjects[i].bitmap.x += newPosition;
arrWordObjects[i].bitmap.y += getRandomNumber();
}
}
Something that will make a huge difference is using for each(Object in Array) rather than the standard for loop.
private function blowemup(e:Event):void
{
var newPosition:Number;
var i:ArrWordsObjectClass; // <-- don't know what the class for this is, just replace
for each(i in arrWordObjects)
{
newPosition = updatePosition(i.bitmap);
i.bitmap.x += newPosition;
i.bitmap.y += getRandomNumber();
}
}
A for each loop is typed, meaning a lot of time is saved where normally it'd be trying to work out what arrWordObjects[i] is every iteration.
Also, side note: using one ENTER_FRAME driven function and looping through everything in your application that you want to handle each frame is much more efficient than applying hundreds of listeners for objects.
I normally create a handler class that contains the ENTER_FRAME and an array storing my objects, like so:
package
{
import flash.events.Event;
import flash.display.Sprite;
public class Handler extends Sprite
{
// vars
public var elements:Array = [];
/**
* Constructor
*/
public function Handler()
{
addEventListener(Event.ENTER_FRAME, _handle);
}
/**
* Called on each dispatch of Event.ENTER_FRAME
*/
private function _handle(e:Event):void
{
var i:Element;
for each(i in elements)
{
i.step();
}
}
}
}
Then I create a base class for all the objects that I want to handle, containing the step() function called above.
package
{
import flash.display.DisplayObject;
public class Element extends Object
{
// vars
public var skin:DisplayObject;
/**
* Called on each dispatch of Event.ENTER_FRAME at Handler
*/
public function step():void
{
// override me
}
}
}
Now just extend Element with your objects:
package
{
import flash.display.Sprite;
public class MyThing extends Element
{
/**
* Constructor
*/
public function MyThing()
{
skin = new Sprite();
skin.graphics.beginFill(0);
skin.graphics.drawCircle(0,0,40);
skin.graphics.endFill();
}
/**
* Override step
*/
override public function step():void
{
skin.x += 4;
}
}
}
And get it all going!:
var handler:Handler = new Handler();
var m:MyThing;
var i:uint = 0;
for(i; i<10; i++)
{
m = new MyThing();
m.y = Math.random()*stage.stageHeight;
handler.elements.push(m);
addChild(m.skin);
}
How many bitmaps do you plan to have on the stage at a time?
I have had 40 900x16px bitmaps animating on the stage at full speed running on my iphone using air 2.6.
I used a foreach loop in an enterframe event which i added on mouseclick and removed once the animation was finished.
Remember to compile it for the mobile with gpu rendering enabled. (gpu in your app.xml if you are using air 2.6)
This is worth a read too, it explains a lot about performance for mobile devices
http://help.adobe.com/en_US/as3/mobile/WS901d38e593cd1bac-3d719af412b2b394529-8000.html
Here is a basic example of what I had...
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
[SWF(frameRate="30", backgroundColor="#FF00FF")]
public class Test extends Sprite
{
private var fields:Vector.<Bitmap> = new Vector.<Bitmap>();
public function Test()
{
this.stage.scaleMode = StageScaleMode.NO_SCALE;
this.stage.align = StageAlign.TOP_LEFT;
for(var i:int = 0; i< 37; i++){
var bd:BitmapData = new BitmapData(960, 16, true, 0x000000);
bd.fillRect(new Rectangle(0, 0, 900, 16), Math.round( Math.random()*0xFFFFFFFF ));
var b:Bitmap = new Bitmap(bd);
b.x = 0;
b.y = i*16;
stage.addChild(b);
fields.push(b);
}
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
}
private var inertia:Boolean = false;
private var yCurrent:Number;
private var ySpeed:Number;
private var startY:Number;
private var cy:Number = 0;
private function onEnterFrame(e:Event):void{
if(!inertia){
ySpeed = (startY - yCurrent) ; // / 16;
startY = yCurrent
} else {
ySpeed *= 0.8;
if(ySpeed < 0.01 && ySpeed > -0.01){
inertia = false;
stage.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
}
}
cy += ySpeed;
if(cy > 640)
cy -= 640;
var ty:Number = cy;
for each(var tf:Bitmap in fields){
tf.y = ty;
ty += 16;
if(ty > 640)
ty -= 640;
}
}
private function onMouseDown(e:MouseEvent):void{
inertia = false;
startY = e.stageY;
yCurrent = e.stageY;
stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
private function onMouseMove(e:MouseEvent):void{
yCurrent = e.stageY;
}
private function onMouseUp(e:Event):void{
inertia = true;
stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
}
}
I would suggest looking at writing a custom effect on Adobe's website over registering for ENTER_FRAME event. What you've put up there means this code will forever run as long as the program is running. If you wanted to stop the effect or run for 10 frames and stop then you'll have to write more code. It gets even more complex if you want to apply this to several instances. You're going to have to resolve problems that custom effects framework solves.
I'd read how to write custom effects here:
http://livedocs.adobe.com/flex/3/html/help.html?content=createeffects_1.html