Jump to content
Search Community

structure - talking between parent + child

Yes! test
Moderator Tag

Recommended Posts

Trying to understand the new structure of as3 with regards to loading and unloading swfs.

 

I'd like to replace a swf on what used to be called level 1, with another swf on level 1, by just loading a swf on that level, from the swf currently on that level, so it kicks out the current swf that called the new swf - just like it used to be in the old days of as2 - this will help me get around a problem.

 

How can I do this with as3? Do I just do an add swf with a remove swf straight after?

 

In my first swf I have the following that works fine.

 

import com.greensock.*;
import com.greensock.loading.*;
import com.greensock.events.LoaderEvent;
import com.greensock.loading.display.*;

var queue:LoaderMax = new LoaderMax({name:"mainQueue", onProgress:progressHandler, onComplete:completeHandler, onError:errorHandler});
queue.append( new SWFLoader("testload_02.swf", {name:"childClip", estimatedBytes:3000, container:this, x:0, autoPlay:false}) );

 
//start loading
queue.load();
 
function progressHandler(event:LoaderEvent):void {
    trace("progress: " + event.target.progress);
}
 
function completeHandler(event:LoaderEvent):void {
//   var image:ContentDisplay = LoaderMax.getContent("photo1");
//    TweenLite.to(image, 1, {alpha:1, y:100});
    trace(event.target + " is complete!");
}
 
function errorHandler(event:LoaderEvent):void {
    trace("error occured with " + event.target + ": " + event.text);
}

 

Now, this loads a game on top of the first swf. When that game has ended I want to remove it and add another swf. Can the top swf with the game in it talk back to the swf that was first loaded and trigger a function to remove it and replace with a new one? Is this the way to do it? What does that talk back look like?

Link to comment
Share on other sites

I'm trying to put the following in the 2'nd swf, its not working out yet.

 

MovieClip(stage.getChildAt(0)).doSomething();

 

then in the first swf

 

function doSomething() {
trace("calling a function from the main timeline");
var queue2:LoaderMax=new LoaderMax({name:"mainQueue1",onProgress:progressHandler,onComplete:completeHandler,onError:errorHandler});
queue2.append( new SWFLoader("testload_03.swf", {name:"childClip1", estimatedBytes:3000, container:this, x:0, autoPlay:false}) );

 ;
//start loading
queue2.load();
}

 

hmmm....

Link to comment
Share on other sites

I get the following error:

 

TypeError: Error #1009: Cannot access a property or method of a null object reference.
at testload_02_fla::MainTimeline/frame1()

 

So basically its not liking the following

 

MovieClip(stage.getChildAt(0)).doSomething();

 

hmmmm.... any suggestions? Basically I'm referencing the first swf incorrectly. How do I reference it correctly in this instance?

Link to comment
Share on other sites

Depends where that code is executing from, but most likely it would be:

 

MovieClip(this.parent).doSomething();

 

If you want to use the same SWFLoader and load new content in the place of the old content, you could do:

 

loader.unload();

loader.url = "myNewURL.swf";

loader.load();

 

Or just dispose(true) the old loader and create a new one altogether. The benefit of that is you'd be able to have them coexist for a short time so that you could fade the new one in (or animate it however you want) over the top of the old one. But that's not necessary.

Link to comment
Share on other sites

Thanks Greensock. I want the base swf to consistantly be there, and swf's to load on top of that - the swf's load on top are a game, each once each game level has been played then the top swf calls to the base swf to basically unload itself and load up the next game level swf. Makes sense? So basically in old AS2 terms the swf at level 0 is constant, the swf at level 1 keeps replacing itself after the user has finished that game level - I'm using 'level' to mean two things, 1) game level, and 2) the old As2 flash meaning.

 

So, consequently the following code would go in the swf thats being loaded on top, for some reason its just not working.

 

MovieClip(this.parent).doSomething();    --- I'm now getting a different error  :  progress: 0.6466666666666666
TypeError: Error #1034: Type Coercion failed: cannot convert flash.display::Loader@459f30e1 to flash.display.MovieClip.
at testload_02_fla::MainTimeline/frame1()
progress: 1
LoaderMax 'mainQueue' is complete!

 

My understanding is that even if I use the loader.unload(); etc then I still need to call that from the swf loaded on top of the base swf, so I still need to talk between the swfs. Wow this as3 is really complex compared to this issue in as2. :(

Link to comment
Share on other sites

I'm playing around with this doing tests etc, its just the call back from the loaded swf to the function in the pre existing swf thats the problem.

 

MovieClip(this.parent).doSomething();

TypeError: Error #1034: Type Coercion failed: cannot convert flash.display::Loader@458780e1 to flash.display.MovieClip.
at testload_02_fla::MainTimeline/frame1()

 

My actual function in the pre existing swf that unloads the old swf and loads a new swf works fine.

Link to comment
Share on other sites

I think you might be overcomplicating things.

 

There are several ways to accomplish what you're after:

 

1) Have your child swf dispatch Events that the parent listens for.

 

IN THE PARENT:

this.addEventListener(GameEvent.LEVEL_COMPLETE, levelCompleteHandler, false, 0, true);
function levelCompleteHandler(event:GameEvent):void {
   mySWFLoader.unload();
   mySWFLoader.url = "myNewLevel.swf";
   mySWFLoader.load();
}

 

IN THE CHILD:

//when the level is over, dispatch the event from your DisplayObject so that it bubbles up to the parent
this.dispatchEvent(new GameEvent(GameEvent.LEVEL_COMPLETE));

 

Obvously you'd want to create a custom GameEvent class that extends the Event class which should be relatively simple (Google it if you're not sure - it's a very common practice). This approach is probably the most flexible and "clean" because each level doesn't need to know anything about the parent/container (like MovieClip(this.parent.parent).myFunction() means you'd have to know its position in the display list hierarchy and you're relying on there being a myFunction() there - both of these things don't follow good object-oriented encapsulation practices).

 

-OR-

 

2) Call a method directly in the parent from the child:

 

IN THE CHILD:

MovieClip(this.parent.parent).myFunction();

 

And in myFunction(), you'd do the same thing as above in the levelCompleteHandler.

 

It looks like you're still using MovieClip(this.parent) instead of MovieClip(this.parent.parent) - you must account for the ContentDisplay wrapper.

Link to comment
Share on other sites

Thanks greensock, though honestly that actually makes it seem even more complicated to me. Is not getting into custom event classes extending the event class more complicated than what I'm suggesting? All that stuff is totally confusing. All I want to do is to trigger a function thats in the parent swf from the child swf. The function works fine when called inside the parent swf, but when called from the child swf I still can't get it to work. I get the error: TypeError: Error #1009: Cannot access a property or method of a null object reference.

at testload_02_fla::MainTimeline/frame1()

 

I'm using the following code in the child swf

 MovieClip(this.parent.parent).doSomething();

 

And in the parent swf the code is as follows:

import com.greensock.*;
import com.greensock.loading.*;
import com.greensock.events.LoaderEvent;
import com.greensock.loading.display.*;

var queue:LoaderMax=new LoaderMax({name:"mainQueue",onProgress:progressHandler,onComplete:completeHandler,onError:errorHandler});
queue.append( new SWFLoader("testload_02.swf", {name:"childClip", estimatedBytes:3000, container:this, x:0, autoPlay:false}) );
 
//start loading
queue.load();


function progressHandler(event:LoaderEvent):void {
trace("progress: " + event.target.progress);
}

function completeHandler(event:LoaderEvent):void {
trace(event.target + " is complete!");
}
 ;
function errorHandler(event:LoaderEvent):void {
    ;
trace("error occured with " + event.target + ": " + event.text);
}


function doSomething() {
queue.unload();
trace("calling a function from the main timeline");
var queue2:LoaderMax=new LoaderMax({name:"mainQueue1",onProgress:progressHandler,onComplete:completeHandler,onError:errorHandler});
queue2.append( new SWFLoader("testload_03.swf", {name:"childClip1", estimatedBytes:3000, container:this, x:0, autoPlay:false}) );
//start loading
queue2.load();
}

 

What could possibly be the problem here? why is flash reading the code in the child swf as a null object reference?

Link to comment
Share on other sites

ok, in the child swf when I do

 trace(this.parent);

I get the result: [object Loader] When I do

 trace(this.parent.parent);

I get the result: null -

 

If this is so, then what's the correct path to a function in the parent?

Link to comment
Share on other sites

Don't worry - push though it and you'll learn to absolutely love AS3. Ask anyone who has made the jump from AS2 and they'll agree.

 

Anyway, I bet the problem you're running into has to do with the fact that you're trying to run that code immediately on the first frame of the child swf. The parent can't add the child to the display list until it has initted (basically after the first frame of the child runs). So when you do MovieClip(this.parent.parent), there's no parent (yet). It returns null. You need to wait until the child is added to the display list. So in your child, you could accommodate that requirement like:

 

if (this.stage != null) {
   init(null);
} else {
   this.addEventListener(Event.ADDED_TO_STAGE, init);
}

function init(event:Event=null):void {
   MovieClip(this.parent.parent).doSomething();
}

Link to comment
Share on other sites

Ok I got it, that looks like it was a part of the problem, the other part was that I had autoPlay:false set on the child swf being loaded... lol.

 

THANK YOU!

 

man this AS3... such a damn simple thing to accomplish took so long to figure out.

 

Anyhow, I very much appreciate your help.

Link to comment
Share on other sites

  • 1 month later...

Hey there,

 

i've been searching the net and slowly ripping my hair out for days for this exact situation.

 

i have a main SWF that loads another SWF(a scene). once a certain button is clicked in the scene SWF, i need the parent SWF to do an action . which is exactly what this thread is about. However, i have followed all of the steps (i want to achieve this through events rather than parent.parent path)

 

i can fire off a custom event inside the scene SWF, listen for it and catch it no problem. but i CANNOT get the main SWF to listen to the event and catch it. i cant even access the function in the parent SWF through the parent.parent path

 

i even created a custom event and still nothing seems to work.

 

i've also tried:

 

MovieClip(_loader.content).addEventListener("my event", eventHandler);

- where "my event" is fired from the scene SWF once a button is clicked:

 

dispatchEvent(new Event("my event"));

- and that got me nowhere

 

 

this is what my Container class looks like (the parent)

 

public class Container extends MovieClip

{

private var _loader:Loader;

private var _loading:Loader_MC;

private var _path:String = "SWF/Scene.swf";

 

public function Container()

{

startLoad();

}

 

private function startLoad():void

{

_loader = new Loader();

_loader.load(new URLRequest(_path));

_loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, showLoading);

_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadComplete);

}

 

 

private function showLoading(e:ProgressEvent):void

{

_loading = new Loader_MC();

_loading.x = stage.stageWidth * 0.5;

_loading.y = stage.stageHeight * 0.5;

 

addChild(_loading);

 

}

 

 

private function loadComplete(e:Event):void

{

 

removeChild(_loading);

 

_loader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, showLoading);

_loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, startLoad);

 

addChild(_loader);

 

MovieClip(_loader.content).addEventListener(ResponseEvent.CONTROL_SCENE, eventHandler, false, 0, true);

 

 

 

}

 

private function eventHandler(e:ResponseEvent):void

{

trace("heard the event!!!!!");

}

 

}

 

 

please shed some light on this. i am at a loss. i know its something small...

 

much appreciated!

 

Serge.

Link to comment
Share on other sites

This forum is for GreenSock related tools like LoaderMax. According to your code, you're not using it. There are a bunch of problems with the built-in Loader class from Adobe so you might want to use LoaderMax instead (see http://www.greensock.com/loadermax/#bugs). Your problem likely has to do with not setting the LoaderContext properly - by default Flash won't allow a child swf to communicate with the parent swf.

 

Have you tried loading it with LoaderMax yet?

Link to comment
Share on other sites

Ah, my apologies for not looking around enough. i will go through the Loader Max documentation and see if i can get it to work. And i see what you are saying with the Loader class so thank you so much for clearing that up. im hoping to get it to work without bugging you again (this time with LoaderMax) so we'll see.

 

thanks again!

serge.

Link to comment
Share on other sites

hello again

 

it seems that i have found the problem:

 

dispatchEvent(new Event("my event", true));

*bubbling must be set to "true";

 

this.addEventListener("my event", handleEvent, false, 0, true);

*must be set in the constructor

 

so yes, you were right, the listener cannot be added to contentLoaderInfo.

 

ALSO, i have checked out LoaderMax and - what a great piece of work. already tested and working.

 

one thing a little hazy though, how does the prioritizing work? i know it can be done, i have 12 SWFs that i want loaded in a specific order one-after-the-other? any quick thoughtS?

 

many thanks!

 

cheers,

serge.

Link to comment
Share on other sites

one thing a little hazy though, how does the prioritizing work? i know it can be done, i have 12 SWFs that i want loaded in a specific order one-after-the-other? any quick thoughts?

Sure, that should be pretty simple. You just append() them or insert() them in the order you want. LoaderMax gives you a lot of control over that. So...

 

var queue:LoaderMax = new LoaderMax({maxConnections:1});
queue.append( new SWFLoader(...) );
queue.append( new SWFLoader(...) );
...

 

It will load the first one, then the second, then the third, etc. Notice I set maxConnections to 1 in the LoaderMax so that it loads only 1 at a time. The default is 2 which can make the overall loading of the entire group go about 20-30% faster. But if you need to make sure things are sequential, set maxConnections to 1.

 

If you ever need to prioritize a particular loader on the fly, you can do it very easily by either calling prioritize() on the loader instance or call the static LoaderMax.prioritize("myLoaderNameOrURL", true) method. That will immediately halt other files in the LoaderMax instance from loading and load the prioritized file right away.

 

Does that answer your question?

Link to comment
Share on other sites

yes, it makes perfect sense, however, once its done loading, it places all the SWFs into DisplayObject, whereas i want it to place the first one on stage, store the others for future use(and not play them until a certain even). i have the event system set up that will trigger play for each of those later on...

 

what am i missing?

Link to comment
Share on other sites

yes, it makes perfect sense, however, once its done loading, it places all the SWFs into DisplayObject, whereas i want it to place the first one on stage, store the others for future use(and not play them until a certain even). i have the event system set up that will trigger play for each of those later on...

 

what am i missing?

By default, SWFLoader doesn't place the content anywhere on the stage unless you defined a "container" or manually did an addChild() or something. So I'm a little confused. Maybe it would help if you posted a simple set of files that demonstrates the issue with a brief explanation. Don't miss Rich Shupe's videos too at http://www.greensock.com/loadermax-tips/

Link to comment
Share on other sites

my guess is that it's in the "container" that im specifying to place them all on stage when i just used separate loaders, but in this case, its only specified on the .prepend SWF

this is what i had in the code but ended up with all of them on stage and playing

 

 

LoaderMax.activate([sWFLoader]);

 

queue = LoaderMax.parse(["SWF/SceneNorthPole.swf","SWF/ScenePostOffice.swf"], {maxConnections:1}, {autoPlay:false});

queue.prepend( new SWFLoader("SWF/SceneBedroom.swf", {container:this, onInit:initHandler, autoPlay:true}) );

queue.load();

 

 

private function initHandler(event:LoaderEvent):void

{

 

_scene0 = _loader.content;

_scene0.alpha = 0;

_scene0.addEventListener("load adventure", loadMain);

TweenLite.to(_scene0, 1, {alpha:1});

 

trace(event.target + " is complete!");

 

}

Link to comment
Share on other sites

Hmm, I'm pretty sure that's impossible. Could you upload a sample FLA that demonstrates that behavior? According to your code, only SWF/SceneBedroom.swf should show up on the stage unless you have other code somewhere that's adding the other loaders' content to the stage.

Link to comment
Share on other sites

.... aaaand right you are, i kept going over it and over, i was assigning the loaders to the display object instead of movieclips. got it working now.

Once again, really great work you've done, saved my project and hours of insanity...

cheers!

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...