PDA

View Full Version : Working with Nested DisplayObjects


rn2071
04-02-2008, 03:03 PM
Greetings,

I'm creating my first AS3 project and I've already hit my first snag, nested display objects (aka buttons and movieClips). Let's say you create a movieClip and place buttonA on frame 1 and buttonB on frame 10. You create a class for that movieClip that tells it to jump to frame X after evoking a custom method. With the same method you want to assign the buttons on that frame their functions, but you can't because Flash thinks that DisplayObject does not exist.

How do you make sure all DisplayObjects for a frame have been loaded, so that you can reference them?

I have figured a way around it by using the ADDED event listener. Apparently this event is triggered every time any DisplayObject is added, whether it is nested or not. What's interesting is the number of children (numChildren) for the parent movieClip stays constant. So, this code takes advantage of that fact.

package com {

import flash.display.*;
import flash.events.*;

public class Pages extends MovieClip {

var lbl:String;

function Pages(prmLabel:String) {
trace("Pages");
changePage(prmLabel);
}

function changePage(prmLabel:String):void {
trace("Change Page: " + prmLabel);
lbl = prmLabel;
this.gotoAndStop(lbl);
this.addEventListener(Event.ADDED, lstAdded);
}

function lstAdded(e:Event):void {
trace("lstAdded");

var frameLoaded:Boolean = true;
for (var i:Number = 0; i < numChildren; i++) {
if (getChildAt(i) == null) {
frameLoaded = false;
}
}

if (frameLoaded) {
this.removeEventListener(Event.ADDED, lstAdded);

switch (lbl) {
case "one":
getChildByName("btnNext").addEventListener(MouseEvent.CLICK, fncNext);
break;

case "two":
getChildByName("btnBack").addEventListener(MouseEvent.CLICK, fncBack);
break;
}
}
}

function fncNext(e:MouseEvent):void {
trace("NEXT");
changePage("two");
}

function fncBack(e:MouseEvent):void {
trace("BACK");
changePage("one");
}

}
}



Personally, I like having menus and such spaced along a time line, especially when they will share things like backgrounds and certain bits of text.

I don't know if there is a better way to do this, or an Event type that I'm not aware of, but this is the only way I can get'er done. Any advice is always welcome. ;)

markdesign
02-18-2009, 07:20 AM
Great solution, it worked.. but in my example when I monkey click it ( roll over and off really quickly ) it generates an error.

TypeError: Error #1009: Cannot access a property or method of a null object reference.


package {

import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.events.Event;

public class ButtonClip extends MovieClip {

public function ButtonClip() {
init();
}

private function init():void {
buttonMode = true;
addEventListener(MouseEvent.MOUSE_OVER, rollover);
addEventListener(MouseEvent.MOUSE_DOWN, down);
addEventListener(MouseEvent.MOUSE_OUT, rollout);
addEventListener(MouseEvent.MOUSE_UP, up);
}

private function rollover(e:MouseEvent):void {
gotoAndStop('over');
addEventListener(Event.ADDED, onOverAdded);
}

private function onOverAdded(e:Event):void {
var loaded:Boolean = true;
for(var i:int = 0; i < numChildren; i++) {
if(getChildAt(i) == null) {
loaded = false;
}
}
if(loaded) {
removeEventListener(Event.ADDED, onOverAdded);
getChildByName("overClip_mc").alpha = .5
}
}

private function down(e:Event):void {
gotoAndStop('down');
addEventListener(Event.ADDED, onDownAdded);
}

private function onDownAdded(e:Event):void {
var loaded:Boolean = true;
for(var i:int = 0; i < numChildren; i++) {
if(getChildAt(i) == null) {
loaded = false;
}
}
if(loaded) {
removeEventListener(Event.ADDED, onDownAdded);
getChildByName("downClip_mc").alpha = .5
}
}

private function rollout(e:MouseEvent):void {
gotoAndStop('up');
}

private function up(e:Event):void {
gotoAndStop('up');
}
}
}

rn2071
02-18-2009, 07:49 AM
I had a go with this. What I found was that I couldn't directly access the movieClips by just using their instance names. I had to use getChildByName(instanceName) to access them. But in the end it works!

Here's my version of your code (sorry, setup it up to my tastes just so I could understand what was going on):

package {

import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.events.Event;

public class ButtonClip extends MovieClip {

private var _currentLabel:String;

public function ButtonClip() {
init();
}

private function init():void {
_currentLabel = "up";

buttonMode = true;
addEventListener(MouseEvent.MOUSE_OVER, onOver);
addEventListener(MouseEvent.MOUSE_DOWN, onDown);
addEventListener(MouseEvent.MOUSE_OUT, onUp);
addEventListener(MouseEvent.MOUSE_UP, onUp);
}

private function changeState(pLabel:String):void {
_currentLabel = pLabel;
addEventListener(Event.ADDED, onAdded);
gotoAndStop(_currentLabel);
}

// Listeners //

private function onOver(e:Event):void {
changeState("over");
}

private function onDown(e:Event):void {
changeState("down");
}

private function onUp(e:Event):void {
changeState("up");
}

private function onAdded(e:Event):void {
var frameLoaded:Boolean = true;
for (var i:Number = 0; i < numChildren; i++) {
if (getChildAt(i) == null) {
frameLoaded = false;
}
}

if (frameLoaded) {
removeEventListener(Event.ADDED, onAdded);

switch (_currentLabel) {
case "up":
break;

case "over":
getChildByName("overClip_mc").rotation = 45;
break;


case "down":
getChildByName("downClip_mc").rotation = 45;
break;
}
}
}
}
}