as3 Air - AddChild works but is slooooooooooow - actionscript-3

I am creating an app where when a button is pressed a very large picture is added to the stage (it is larger than the screen but can be dragged around by the user)
When the button is pressed the picture (well, movieClip) does come up and it able to be dragged fine, buttons inside it work.
The problem though is that there is a pause of about 6 seconds between the button press and the image appearing. I am using one .fla file for publishing and compiling (let's just call it Main.fla for now), and another one to hold all the graphics. The graphics are then added with this embed command:
[Embed (source = "assets/graphic.swf", symbol = "Content")]
private var Content:Class;
private var _content:*;
I have these lines where all the variables are declared (in between the class definition and the constructor function) I was under the impression that embedding it like this was equivalent to loading it at compile time. Is this true? What could be causing this lag when the button is pressed?
If I can't cut out the lag, another idea I had was to make some spinning circle or something to tell the user, "hey, don't worry. It's loading!"

If the slowness is at addChild you can add the asset to the stage much earlier and set it's visiblility to false, then when the button is clicked set it back to true. Obviously this is a small hack but might be sufficient for what you are doing.
var asset:MovieClip;
private function init():void
{
asset = new Content();
assset.visible = false;
addChild(asset);
button.addEventListener(MouseEvent.CLICK, onMouseClick);
}
private function onMouseClick(e:MouseEvent):void
{
asset.visible = true;
}

Embedding your SWF is probably not what is causing the delay.. or rather it would not likely be better if you imported the SWF into your FLA. Is this on a device? Chances are you would either have to devise a different way of loading your asset, or be satisfied with a loading animation.
If the main K size is coming from a large image, you could consider loading it in segments, starting with the part that is initially visible.

Related

Replacing movieclip

I m currently working on converting one of my as2 game project into as3 (flash pro cs4). But there is a problem on the background movieclip.
I have a function called disposemc:
function disposemc(mcname:MovieClip):void{
mcname.parent.removeChild(mcname);
mcname = null
}
Another function called changelayer:
function changelayer(mcname:MovieClip,layer:MovieClip):void{
layer.addChild(mcname)
}
So in main timeline frame 2 I have a movieclip on stage (placed in IDE) with instance name "bg_mc", then on main timeline frame 3 I have a DIFFERENT mc on stage with the SAME instance name "bg_mc". The purpose of this is to replace the old bg_mc by the new one.
The problem is,
In frame 2, I applied changelayer function to bg_mc and moved it into a child mc of root by addChild, and then applied a function of my CPU image post processing framework and added the bg_mc into an array.
After some stuffs happened, I went nextFrame to frame 3, and found that the new bg_mc didnot replace the old one, instead it overlaps.
So I tried disposemc function when leaving frame 2 to get rid of the old bg_mc, and at frame 3 I applied changelayer to bg_mc and added bg_mc to my render array.
And I found that the old bg_mc is off the stage but it is still rendering onto my bitmap data, means it is not nullified like it suppose to be in disposemc function. And it is also hard to access it because the name overlaps. When I call bg_mc in frame 3 it is the new one, but the old one still exists, and from the rendered bitmap data it can see it is still playing.
Will making the old mc stop in disposemc function help?
Can anyone give any help? If my structure of making bg is bad, is there any other way to override an instance with a different mc in library?
The purpose of this is to replace the old bg_mc by the new one
You work with MovieClip and frames. So use keyframes by design. If you need to place different background in third frame, don't program it, place it. If you want program, don't use MovieClip with keyframes as main navigation instrument.
Main timeline could be easily swapped with very simple logic and several movie clips with only one frame
//Some MovieClips from the library, with only one frame, still designed in Flash IDE
var currentScene:DisplayObject;
var home: MyHove = new MyHove()
var intro:MyIntro = new MyIntro();
navigate(home);
//after some interaction from the user, go to another page
navigate(intro);
//It will work like gotoAndStop... but better, and give you more control
function navigate(scene: DisplayObject):void{
if(currentScene != null){
removeChild(currentScene);
}
currentScene = scene;
if(currentScene != null){
addChild(currentScene);
//apply logic for swapping background
}
}

How to properly add "Replay" functionality to a self-preloaded Flash movie?

I made a Flash project in FlashDevelop to create an Ad.
The Preloader is setup by making use of the Additional Compiler argument:
-frame=NameOfLabel,NameOfMainClass
My main class is simply called "Main", at the top / default package level.
So frame #1, being the Preloader portion of the SWF, has:
Very few bitmaps, vector-graphics and text (to stay under 50kb);
A YouTube video player in the center (does not count in the filesize limit);
The frame #2 has everything else (the Main class basically embeds all it's dependencies). This includes:
Assets from precompiled SWF (Bitmaps, Symbols, Fonts, XML data);
All classes imported (this is recursive for every classes importing other classes);
Now my big problem is, my client requested the "replay" functionality long after I've completed 99.9% of the project.
I have the project more-or-less broken into different states (Intro, Ready, SlideMenu, etc.), but I'm not sure how I can easily reset the Flash movie back to the very beginning (where it was preloading and showing the YouTube video).
The easy solution would be to simply call an ExternalInterface JavaScript method that would refresh the Flash container, BUT I don't think I have control over what's going on the HTML / JavaScript side.
Is there an easy way to invoke a replay function from AS3?
Would not simply going back to frame 1 do the trick ?
The following seems to do the trick!
private function onReplayClick(e:MouseEvent):void {
var theStage:Stage = this.stage; //Temporarly store the stage.
//Kill any animations happening:
TweenMax.killAll(); //3rd party, may not be applicable for you :P
//Remove ALL containers / child DisplayObjects
SpriteUtils.recursiveRemove(theStage); //custom-made
// (this object is no longer attached to the stage at this point)
//Nullify any Singleton / Static variables:
Main.INST = null;
// Load the 'bytes' of the current SWF in a new Loader, then...
// add it to the stage
var swf:Loader = new Loader();
swf.loadBytes( theStage.loaderInfo.bytes );
theStage.addChild( swf );
}
By doing a deep recursive cleanup of the DisplayObjects, and any static variables (like Singleton instances), it leaves you with a blank stage.
After that, you can instantiate a new Loader that will load the SWF itself via the current LoaderInfo's bytes property.
Add the Loader to the Stage, and you're up and running again!

Unloading external SWF files

I'm loading multiple swf files from the main menu which is never unloaded. I've done this with the following code... Only issue is that instead of unloading to the main menu I just see a white screen as if nothing is loaded.
function BackToMenu(i:MouseEvent):void
{
var BaseMovie:MovieClip = parent.parent as MovieClip;
BaseMovie.parent.removeChild(BaseMovie);
}
EDIT: I'll explain from the start I have a MainMenu.swf. The games are loaded from MainMenu.swf when the button relating to the game is clicked. When a game button is clicked on MainMenu.swf the game loads. When the player completes a game they are presented with the exit button which unloads the current game and shows the MainMenu.swf without having to re-load it.
First, you should remove one parent to make sure you are actually removing only the game:
function BackToMenu(i:MouseEvent):void
{
var BaseMovie:MovieClip = parent as MovieClip;
BaseMovie.parent.removeChild(BaseMovie);
}
This should take care of your most pressing problem, and allow you to return to the menu. You have, however, not really unloaded the game, but only removed it from the display list. This often means, that there are still sounds running, active key and/or mouse listeners, etc. - these must all be taken care of!
And, like I said, this will only fix your immediate problem. It is, however, neither a permanent solution, nor a good one: Since the main SWF is responsible for loading the games, it should also be responsible for disposing of them. You should put cleanup code into your game, but it should only be concerned with stopping any running scripts, sounds, etc. - simple rule: anything that is started within the game, should be stopped within the game. But it should not try to access objects further up in the display hierarchy, or try to unload itself.
The much better way to do this is by replacing all the above code, and letting the main SWF take care of removing the game, as well as unloading it from memory. For this, you have to do three things:
Instead of writing actual removeChild calls, etc., let your button dispatch a custom event to notify the main SWF that it should now be removed:
function onBackButtonClicked( event:MouseEvent ):void {
destroyGame(); // this would be the function that stops all the scripts
dispatchEvent( new Event( "FINISH_GAME", true ) );
}
Note that "FINISH_GAME" is now a "bubbling" event, i.e. it travels downward in the display hierarchy. We can now listen for this event in any ancestor display object containing the game.
In your main SWF, add an event listener to the Loader when the game was successfully loaded. This is done in the event listener that is called when the load process completes:
function onLoadComplete( event:Event ):void {
var loader:Loader = event.target.loader;
loader.addEventListener( "FINISH_GAME", onFinishGame, true );
}
Use the corresponding event handler to remove the game clip:
function onFinishGame( event:Event ):void {
var loader:loader = event.currentTarget;
loader.parent.removeChild( loader );
loader.unloadAndStop();
}
A few more things to consider:
The naming conventions in ActionScript advise us to use lower case names for methods and variables, and upper case only for types.
The same naming conventions suggest we use either "on" or "handle" as a prefix for event listeners, along with the name of the event. Thus, it should be onBackToMenu or rather, onBackButtonClicked, etc.
Since I don't know anything about the code you use for loading, I just assumed you have a complete listener, and you don't keep references to the loader. If you use a member variable, you can use that instead of event.target, resp. event.currentTarget.

Flash Actionscript 3.0 Loading screen

I'm trying to get a loading screen to work in Flash. This is how my project is set up:
All of the game occurs in "Layer 1," which is set up into many different scenes: "Level 0," "Level 1," etc. Its code is run in a ".as" file
I tried implementing a simple loading screen (with a progress bar) in a new layer, "Preloader." Its code is run in the layer's "Actions."
I realize that putting the Preloader's code in its "Actions" wasn't the best idea because I had Layer 1's ".as" file load Level 0 at first. So the "Preloader" and "Layer 1" layers tried to run at the same time. This caused problems.
Now I have tried putting the Preloader into a scene of its own. That is not working.
Here is the code I've tried using for the Preloader - "scene" version:
// This function loads the Preloader
public function loadPL(event:Event) {
// Load the Scene associated with the Preloader
this.gotoAndStop(1, "PL");
// Prevent the MovieClip (game) from playing right away
stop();
// Add an EventListener that calls the 'loading()' function
this.addEventListener(Event.ENTER_FRAME, loadingPL);
} // End of 'loadPL()' method
// 'loading()' function
// This function calculates how much of the game has been loaded vs. how much data
// the game contains. The loading progress bar is resized accordingly.
public function loadingPL(e:Event):void{
// How much data does the game have in all?
var totalData:Number = this.stage.loaderInfo.bytesTotal;
// How much data has been loaded so far?
var loadedData:Number = this.stage.loaderInfo.bytesLoaded;
// Scale the 'plBarIns' according to the loadedData:totalData ratio
plBarIns.scaleX = loadedData/totalData;
// If the 'loadedData' == 'totalData' (all of the game's data has been loaded), allow
// the game to play
if (loadedData == totalData) {
play();
// Remove the EventListener that calls the 'loading()' function. It's not needed now
this.removeEventListener(Event.ENTER_FRAME, loadingPL);
}
}
Could anyone help me?
Thanks,
Christian
You need to put your preloader in frame 1 and have the rest of your project start on frame 2. After that you need to setup your ActionScript settings so it knows to load all of your classes on frame 2 instead of frame 1.
Here's what settings you need to change:
File > ActionScript Settings...
Change "Export classes in frame:" to 2
Change "Default linkage:" to Merged into code
Your loaderinfo should now return the proper progress of the file loading instead of instantly jumping to completed.

As3 Preloader (Blank until 100%)

I have an FLA file with two frames. On the first frame I have nothing but a textfield and some code to do the preloading. After it is done preloading it does gotoAndStop(2)
On frame 1 I have:
stop();
stage.scaleMode = StageScaleMode.SHOW_ALL;
//Import the required assets
import flash.display.*;
//Stop the playhead while loading occurs
this.stop();
//Create a listener to call the loading function as the movie loads;
this.loaderInfo.addEventListener(ProgressEvent.PROGRESS, PL_LOADING);
this.loaderInfo.addEventListener(Event.COMPLETE, PL_FINISH);
function PL_LOADING(event:ProgressEvent):void
{
var pcent:Number = event.bytesLoaded / event.bytesTotal * 100;
//Display the % loaded in textfield
txt.text = int(pcent) + "%";
//If the movie is fully loaded, kick to the next frame on the main timeline
}
function PL_FINISH(event:Event):void
{
removeChild(txt);
gotoAndStop(2);
}
On frame 2 I have nothing except:
var game:Game = new Game();
addChild(game);
In my publisher settings I have export to frame 2.
My problem is that the preloader won't display until 100%. Does anyone know why?
P.S. For testing I put a large image file on the stage in frame 2 and the result is the same.
This normally happens if you haven't deselected "Export in frame 1" in each of the library symbols that you are exporting for ActionScript.
You'll need to make sure that you create reference to these objects (so that ActionScript can access them) by placing them onto the stage in frame 2 (out of sight).
What's happening is that all of the symbols are being loaded before the preloader itself has loaded.
If this isn't the issue, then please provide some code so I can better assess your issue.
Have you tried putting something static on frame one? Just because there is a preloader, that doesn't mean that your swf will be displaying at all...
I know that I had one swf once which simply took a minute to actually get the Flex preloader to even show up because of network latency. It could be that your swf isn't displaying until 90% of it has already loaded.
I´m dealing with similar problems, and there is something i found out: my antivirus contains a kind of "browser protection" feature, which sort of checks all files in advance before it allows the browser to actually display them. If this antivirus feature has not been installed on the system, the preloader works beautifully. I´ve checked some other web-sites with flash content, and they also behave "wrong" under these circumstances. Now, some people seem to have found a way to stop the antivirus from messing around, but i don´t know how they do it... not yet...