Why do MovieClipLoader events not fire when loaded into an AS3 wrapper? - actionscript-3

While trying to answer this question: Call to an AS2 function from the AS3 container I have come across a roadblock. The setup is an AS3 SWF which loads an AS2 SWF, which in turn loads another AS2 SWF. Communication between the AS3 SWF and the parent AS2 SWF is achieved through localConnection.
child_as2.swf - This is a very simple timeline animation of a box moving across the screen with the following code on frame 1:
stop();
function playMovie() {
play();
}
parent_as2.swf - This is the intermediary AS2 container which loads in child_as2.swf. The load is triggered by a LocalConnection call:
import mx.utils.Delegate;
this._lockroot = true;
var container:MovieClip = createEmptyMovieClip("container", 10);
//mustn't cast this or the Delegate breaks
var mcLoader = new MovieClipLoader();
mcLoader._lockroot = true;
mcLoader.onLoadInit = Delegate.create(this,onMCLoadInit);
function onMCLoadInit() {
trace("load init");
container.playMovie();
}
//LocalConnection code
var myLC:LocalConnection = new LocalConnection();
myLC.loadChild = function(){
mcLoader.loadClip("child_as2.swf", container);
trace("loading");
}
myLC.connect("AVM");
parent_as3.swf - This is the outer wrapper, written in AS3. It loads parent_as2.swf, and communicates with it via LocalConnection:
var myLC:LocalConnection = new LocalConnection();
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.INIT,onLoaded);
loader.load(new URLRequest("parent_as2.swf"));
addChild(loader);
function onLoaded(event:Event):void {
//setTimeout hack to circumvent #2000 Security context error
setTimeout(function() {
myLC.send("AVM", "loadChild");
},1);
}
The issue is that the onMCLoadInit function in parent_as2 is never called when it is loaded inside the AS3 wrapper, although the load does take place. The events also fail when using a listener object in place of Delegate. The box from child_as2.swf is visible, but never starts moving. However, if I run parent_as2.swf on it's own and start the load without the LocalConnection it works fine. It also wroks correctly when triggered from an external LocalConnection call. Why does the AS3 wrapper prevent the MovieClipLoader's events from firing?
Update:
So accepting that no events can be fired from the MovieClipLoader in parent_as2.swf, I have modified the code to detect the loadInit state by a combination of polling MovieClipLoader.getProgress() and the existance of a function in child_as2.swf. It's not pretty but it seems to work. I would still much rather be able to offer a solution using events though.
var container:MovieClip = createEmptyMovieClip("container", 10);
var mcLoader:MovieClipLoader = new MovieClipLoader();
var loadStarted:Boolean;
var checkingInt:Number;
function checkProgress() {
var progObj:Object = mcLoader.getProgress(container);
if(progObj.bytesLoaded == progObj.bytesTotal && loadStarted) {
//load complete, wait for loadInit
if(typeof(container.playMovie) == "function") {
//loadInit
clearInterval(checkingInt);
container.playMovie();
}
}
//ensures the first loop is ignored due to inaccuracy with reporting
loadStarted = true;
}
//LocalConnection code
var myLC:LocalConnection = new LocalConnection();
myLC.loadChild = function() {
loadStarted = false;
mcLoader.loadClip("child_as2.swf", container);
checkingInt = setInterval(checkProgress,5);
}
myLC.connect("AVM");

I think its the delegate scope in as2 when loaded into a parent the parent becomes _root.
So "this" would be referring to the parent root where the function does not exist.
Have you tried putting this._lockroot = true; in parent_as2?
Here is a better explanation
Also as a side note to your security hack.
The proper fix for that would be to have the child contact the parent and issue an "I am ready type command" which would start the communication events from parent to child.
setTimeout is just delaying any calls to the child giving it time to initialize which could be bad on slower computers.
I did alot of loading AS2 into AS3 a few years ago. If you can't tell lol

Related

how to go to next scene after loaded swf played in As3 Flash cc

i am currently working in adobe flash cc 2014 and i have loaded one .swf file that contains about 5000 frames of animation. And then i want to go to next scene after this loaded file finished playing.
this is the code i have, just simple loader code :
stop();
var myLoader:Loader = new Loader();
var url:URLRequest = new URLRequest("jenissendi.swf");
myLoader.load(url);
addChild(myLoader);
now, what should i do to this code?
can someone give me a simple step, because i am still newbie here
thanks.
The thing about Loader class that can confuse beginners is that events, related to loading process, are dispatched from a LoaderInfo object attached to Loader rather than Loader itself.
stop();
var myLoader:Loader = new Loader;
var url:URLRequest = new URLRequest("jenissendi.swf");
myLoader.contentLoaderInfo.addEventListener(Event.INIT, onInit);
myLoader.load(url);
addChild(myLoader);
function onInit(e:Event):void
{
nextScene();
}
First, you will need to listen for when your content has completed it's load - as you won't know how many frames the content has until then.
Then, you need to figure out when the timeline of that loaded content has finished playing.
Here is a code example with comments explaining what's going on.
stop();
var myLoader:Loader = new Loader();
var url:URLRequest = new URLRequest("jenissendi.swf");
//before you load, listen for the complete event on the contentLoaderInfo object of your loader
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, contentLoaded, false, 0, true);
myLoader.load(url);
addChild(myLoader);
//this function runs when the content is fully loaded
function contentLoaded(e:Event):void {
var loadedSwf:MovieClip = myLoader.content as MovieClip; //this is the main timeline of the loaded content
loadedSwf.addFrameScript(loadedSwf.totalFrames - 1, contentFinished);
//the line above tells the movie clip to run the function 'contentFinished' when it reaches the last frame.
}
//this function runs when the loaded content reaches it's last frame
function contentFinished():void {
//clean up to avoid memory leaks
removeChild(myLoader);
loadedSwf.addFrameScript(loadedSwf.totalFrames - 1, null);
nextScene();
}
addFrameScript has a few nuances. First, is that it reads frame numbers as 0 based. So that means the first frame is frame 0. That's why you subtract 1 from the totalframes to get the last frame. Second, addFrameScript is an undocumented feature - which means it may on some future flash player/AIR release not work anymore - though that's very unlikely at this point.
It's also very important to remove your frame scripts (by passing null as the function) to prevent memory leaks.

Go to specific frame after external swf has been loaded AS3

I have been looking for solutions around here but I can't seem to get it right.
Basically I am trying to load an external swf after clicking on a 'Next' button and it will automatically go to a specific frame eg. frame 8 instead of frame 1.
At first I've got an error of using of using MovieClip function in a Loader and such.
Here's my code
nextBtn.addEventListener(MouseEvent.CLICK, fl_ClickToLoadUnloadSWF_1);
var fl_Loader1:Loader;
var fl_ToLoad1:Boolean = true;
function fl_ClickToLoadUnloadSWF_1(event:MouseEvent):void
{
if(fl_ToLoad1)
{
fl_Loader1 = new Loader();
fl_Loader1.load(new URLRequest("projectnowd.swf"));
addChild(fl_Loader1);
var fl_Loader1:MovieClip = event.target.content as MovieClip;
fl_Loader1.gotoAndStop(8);
}
else
{
fl_Loader1.unload();
removeChild(fl_Loader1);
fl_Loader1 = null;
}
fl_ToLoad1 = !fl_ToLoad1;
}
You can access content of loaded swf only after event. Complete was dispatched while loading swf file on to the stage.
Define event handler method to start from 8 th frame
function loaderCompleteHandler(evt:Event):void {
var loadedMovie:MovieClipp = evt.currentTarget.content as MovieClip;
loadedMovie.gotoAndStop(8);
}
Replace if block with below lines of code
if(fl_ToLoad1)
{
fl_Loader1 = new Loader();
fl_Loader1.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderCompleteHandler);
fl_Loader1.load(new URLRequest("projectnowd.swf"));
addChild(fl_Loader1);
}
Happy coding :)

Flash Loader works only inside of Flash

I need to load flex swf file into a flash (a button on witch I need to apply flex skin). I'm using flash Loader() and inside of Flash it works fine (swf is loaded and displayed). But when I try run a compiled flash swf, the Loader does not load the flex swf. There are no errors handled with IOErrorEvent.IO_ERROR and the ProgressEvent.PROGRESS just sais that 0 bytes was loaded. Than nothing else happen.
Here is a part of my code (just display flex button and set a label):
var flexBtn:String = "button.swf"; //swf file is in the same folder as flash source code
var myLoader:Loader = new Loader();
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,loadComplete);
myLoader.load(new URLRequest(flexBtn));
stage.addChild(myLoader);
var timer:Timer;
function loadComplete(event:Event):void
{
timer = new Timer(200);
timer.addEventListener(TimerEvent.TIMER, timeHandler);
timer.start();
}
function timeHandler(event:Event):void
{
timer.stop();
var myClip:MovieClip = myLoader.content as MovieClip;
myClip.x = 10;
myClip.y = 10;
if (myClip.currentFrame == 2){
myClip.application.flexButton.label = "FlexButton";
}
}
I have tried different versions of SDK and different Loaders but it didn't work.
All suggestion will be appreciated :-)
Add SecurityErrorEvent - I guess it's because of a privacy policy error.
And of course you must be sure they are in the exact same folder (correct url).

AS3 Retrieving a file from FZip

I am currently coding a game and I am storing all external files in a zip file to save space.
I am trying to use Fzip to load an image out of the Zip file and display it on stage but I am having no luck.
FZip Site - http://codeazur.com.br/lab/fzip/
Example 1 Site - http://www.tuicool.com/articles/7VfQr2
I have got the zip file to load and return me the number of files inside it but I cannot figure out how to retrieve an image called "test.png".
import deng.fzip.FZip;
import deng.fzip.FZipFile;
import deng.fzip.FZipLibrary;
import flash.display.*;
var zip:FZip = new FZip();
var loaderzippy:Loader = new Loader();
function unzipObb():void {
zip.load(new URLRequest("file://"+File.applicationStorageDirectory.nativePath+"/cake2.zip"​));
zip.addEventListener(Event.OPEN, onOpen);
zip.addEventListener(Event.COMPLETE, dosomething); }
function dosomething(evt:Event):void {
trace("dosomething");
var img_file:FZipFile = zip.getFileByName("test.png");
var loaderzip:Loader = new Loader();
loaderzip.loadBytes(img_file.content);
var image:Bitmap = Bitmap(loaderzip.content);
addChild(image); }
I just get returned #2007: Parameter child must be non-null.
Any help would be great. Thanks.
When you load the PNG bytes using loaderzip.loadBytes(), you need an event listener to check when it's done loading. The documentation itself states:
The loadBytes() method is asynchronous. You must wait for the "init" event before accessing the properties of a loaded object.
Because you're trying to access the code directly after you called loadBytes(), at which point it hasn't actually loaded anything, you're getting a null bitmap.
Although you can access the data once the "init" event has been dispatched, it's best to wait for the "complete" event, since you want your image to be done loading (rather than halfway done).
I've tweaked your code to something that should work:
function dosomething(evt:Event):void {
trace("dosomething");
var img_file:FZipFile = zip.getFileByName("test.png");
var loaderzip:Loader = new Loader();
loaderzip.contentLoaderInfo.addEventListener(Event.COMPLETE, getImage);
loaderzip.loadBytes(img_file.content);
}
function getImage(e:Event):void {
var loaderInfo:LoaderInfo = e.currentTarget as LoaderInfo;
var image:Bitmap = Bitmap(loaderInfo.content);
addChild(image);
}
(I haven't tested this myself but it's just to give you the general idea anyway.)
Note that you should add the event listener to loaderzip.contentLoaderInfo, not just loaderzip. That's what actually dispatches the event and it also contains the loaded content.

AS3 objects (buttons) from library not accessible from within certain functions

I'm working on a simple image processor in AS3 and as usual I almost had it finished when an annoying little problem appeared. I want to open an image using a dialog box, and once the image is open I want the "selectBtn" (which is in my Library) to disappear. However when I try the code below I get a: "Error #1009: Cannot access a property or method of a null object reference". I'm sure it's something simple but I just can't figure it out!
// declare variables
var image:Bitmap;
var loader:Loader = new Loader();
var fileRef:FileReference= new FileReference();
selectBtn.addEventListener(MouseEvent.CLICK, openImage);
function openImage(event:MouseEvent):void {
fileRef.browse([new FileFilter("Images", "*.jpg;*.gif;*.png")]);
fileRef.addEventListener(Event.SELECT, onFileSelected);
}
function onFileSelected(e:Event):void {
fileRef.addEventListener(Event.COMPLETE, onFileLoaded);
fileRef.load();
}
function onFileLoaded(e:Event):void {
loader.loadBytes(e.target.data);
image = Bitmap(loader.content);
selectBtn.visible = false;
}
What Todd says is accurate: where is "selectBtn" defined? Is it on a stage, or nested within some movieclip instance?
Assuming the button exists on the stage, and the code runs in the same frame as the button exists, you could try this.stage.selectBtn.visible = false;
Otherwise, trace that you have selectBtn as a reference. Or you could declare a variable to reference it. i.e.:
var selectBtnRef:Button = this.stage.selectBtn;