Is it possible to load on frame 2 a swf embed in another swf?
I need to produce a single, main swf that contains a sound swf. The sound swf contains exported sound files for instantiation in code. The sound swfs vary based on the version of the main swf hence the desire to embed at compile time. I currently embed the sound swf in the main swf code using an [Embed] metadata tag which all works. However, this seems to load the swfs on frame 1 and I'd rather it load on frame 2 after my preloader runs.
I've checked around the web and this question seems to get asked but never really answered.
To clarify, I am embedding a swf and its symbols in a main class with code like this:
[Embed(source = 'sound.swf', symbol = 'music')] public var music:Class;
The embed swf and symbols load on the initial main swf load. If I set the sound swf to export on frame 2, it does not compile. Library contents in the main swf load on frame 2 to allow the preloader in frame 1 to run. I'm trying to find out if there is a way to make the assets in the sound.swf to also load on frame2.
This seems to solve the issue for me. Sample code below. I embed a swf containing sound assets, but use "application/octet-stream" for the mimeType. Then later I can "load" the swf using the ActionScript Loader class. A symbol in the loaded swf can then be instantiated using "getDefinitionByName". Also, you can instantiate using "getDefinition" if you have a reference to the loaded swf, see the commented out line below. So far this works for me.
package
{
import flash.display.Loader;
import flash.display.MovieClip;
import flash.media.Sound;
import flash.events.Event;
import flash.system.LoaderContext;
import flash.system.ApplicationDomain;
import flash.utils.getDefinitionByName;
public class TestEmbed extends MovieClip
{
[Embed(source="EmbedAudio.swf", mimeType="application/octet-stream")]
public var EmbedAudio : Class;
public function TestEmbed()
{
super();
// load embed swf
var context : LoaderContext = new LoaderContext (false,ApplicationDomain.currentDomain);
context.allowCodeImport = true;
var loader : Loader = new Loader ();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loader_complete);
loader.loadBytes (new EmbedAudio (), context);
}
private function loader_complete(evt:Event):void {
// instantiate the class
/*var ClassDefinition:Class = evt.target.applicationDomain.getDefinition("k3n1_01") as Class;*/
var ClassDefinition:Class=getDefinitionByName("k3n1_01") as Class;
var k3n1_01:Sound = new ClassDefinition();
k3n1_01.play();
}
}
}
Related
I created a movieclip, I imported a video inside it ,as3 code that loads an image, and animate that image on the video.I use as3 codes like below
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
var imgLoader:Loader = new Loader();
imgLoader.load(new URLRequest(File.applicationStorageDirectory.resolvePath("imagem.jpeg").url));
imgLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,imageLoaded1);
because of performence issues, I choose Starling to record that movieclip. and I use below code for that,
var kmcv2:mcv2 = new mcv2();
kmcv2.x=304;
kmcv2.y=208;
kmcv2.width=750;
kmcv2.height=382;
Starling.current.nativeOverlay.addChild(kmcv2);
but this code does not record it, because my movieclip is on the top.
stage.drawToBitmapData( _bmp );
how can I handle it?
thank you.
I have an AS3 project that has all its assets embedded using the [Embed] metadata tag because I would like the resulting SWF to be completely self-contained for the sake of portability on the internet.
Problem:
The file size is rather large, and I would like a progress bar to be displayed as it loads itself instead of a blank screen until it's completely finished. I can already achieve this with Adobe Animate (Flash Professional) by having a timeline with a light frame 1 and a heavy frame 2 which has a MovieClip that embeds the bulk of the assets.
I'm trying to switch over to Adobe Flash Builder, which has no IDE timeline, but I'm at a loss on how to do the same thing as the Flash IDE. Does anyone have any ideas on how to accomplish this?
Option №1. The one I'd picked, because it's easier to comprehend: external loader. A lightweight SWF with the only purpose of displaying some preloading info like % or progress while loading the heavyweight main module.
Option №2. There's a certain metatag that allows you to emulate that frame 1 preloader behavior. Keep in mind that is is not supported by ASC2.0 compiler (AIR SDK, I assume) but only by ASC1.0 compiler (Flex SDK). Flash Builder is a descendant of Flex Builder, so it's fine, I guess, but if it does not work for you, the first thing you should check is the compiler version your Flash Builder is packed with.
So, your main (the one you set as the document class in the settings) class should have that one metatag:
package
{
import flash.events.Event;
import flash.display.Sprite;
// Brace for the magic impact.
[Frame(factoryClass="Preloader")]
public class Main extends Sprite
{
public function Main()
{
// This is important, because at the moment of creation
// the instance is not attached to the stage.
if (stage) onStage(null);
else addEventListener(flash.events.Event.ADDED_TO_STAGE, onStage);
}
private function onStage(e:Event):void
{
removeEventListener(flash.events.Event.ADDED_TO_STAGE, onStage);
// This is the entry point of your actual application.
// The rest of the class goes normally from this point on.
Then, the mentioned preloader class. Its name should qualify exactly as mentioned in the metatag above.
package
{
import flash.display.DisplayObject;
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.utils.getDefinitionByName;
// This class represents the multi-framed main timeline
// thus it should subclass the basic MovieClip.
public class Preloader extends MovieClip
{
public function Preloader()
{
// Subscribe to all necessary points to monitor the loading.
addEventListener(Event.ENTER_FRAME, onFrame);
loaderInfo.addEventListener(IOErrorEvent.IO_ERROR, ioError);
loaderInfo.addEventListener(ProgressEvent.PROGRESS, onProgress);
}
private function ioError(e:IOErrorEvent):void
{
// Handle loading errors here.
}
private function onProgress(e:ProgressEvent):void
{
// Display loading progress here.
// Use e.bytesLoaded and e.bytesTotal values
// to calculate the % loaded and the overall loading progress.
}
private function onFrame(e:Event):void
{
// When the loading is finished, the main timeline,
// represented by Preloader class moves to the frame 2.
if (currentFrame == totalFrames)
{
stop();
onComplete();
}
}
// This method concludes the loading,
// cleans up the preloader itself
// and instantiates the Main class.
private function onComplete():void
{
removeEventListener(Event.ENTER_FRAME, onFrame);
loaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, ioError);
loaderInfo.removeEventListener(ProgressEvent.PROGRESS, onProgress);
// So, here's the thing. You don't import the Main class
// because if you import it, then it will be embedded into
// the Preloader, then it must be loaded before Preloader
// can be initialized, which kind of fails the whole idea.
// Thus, you don't import the Main class but obtain it
// via the other means, like the "getDefinitionByName" method.
// Again, the fully qualified class name is to be provided.
var aMain:Class = getDefinitionByName("Main") as Class;
stage.addChild(new aMain as DisplayObject);
// Remove this instance as it no longer needed for anything.
parent.removeChild(this);
}
}
I found a solution that works with ASC2 / AIR SDK. Although his example preloader extends Sprite, and I believe you need to extend MovieClip to make it work, since you need a frame 2. And you need a gotoAndStop(2) once it has finished loading itself. Additional information here. Man, it's not a good sign when all your reference links go through web.archive.org!
Greatings!
I have yet another question concerning the loading of a .swf inside a existing one.
In my game. I have a introduction screen in which I load another .swf (which is a movie).
This all works fine and the URLRequest is this:
request = new URLRequest("Movie.swf");
As I said, this works fine. However when I copy my game.swf and movie.swf to a USB stick.
(I put them in the same directory to prevent other issues).
It doesn't seem to find the movie.swf.
Now I know that it has to do with the path given in the URLRequest and/or the publish settings. But I do not know how to make this so that it searches in the same directory
as the game.swf is in.
I hope you guys have an answer for this issue.
Thanks in advance,
Matti.
Matti, I believe Lukasz's comment is correct about it being a security error.
You can avoid this security error by embedding Movie.swf instead of using a Loader. If you do this, then at compile-time the Movie.swf needs to sit next to the Game.as file, and it will be included in the Game.swf (no need to deliver both files, just Game.swf).
The syntax is:
package
{
import flash.display.Sprite;
public class Game extends Sprite
{
[Embed(source="MyMovie.swf")]
private var myMovieClass:Class;
private var myMovie:DisplayObject;
public function Game():void
{
myMovie = new myMovieClass();
// Technically myMovie is now a Loader, and once
// it's loaded, it'll have .content that's a
// MovieClipLoaderAsset, and .content.getChildAt(0)
// will be your MyMovie.swf main timeline.
}
}
}
Alternately, if you embed it as mimeType="application/octet-stream", you can get the bytes of the SWF and use it in your existing Loader's .loadBytes() method:
package
{
import flash.display.Sprite;
import flash.utils.ByteArray;
public class Game extends Sprite
{
[Embed(source="MyMovie.swf", mimeType="application/octet-stream")]
private var movieBytes:Class;
private var myMovie:DisplayObject;
public function Game():void
{
// Treat this loader the same as your current loader,
// but don't call .load(url), call loadbytes():
var l:Loader = new Loader();
l.loadBytes(new movieBytes() as ByteArray);
}
}
}
I have a game that I've made that runs in two files, one the preloader and one the swf. When I use these two files together they work fine, however some flash portals require only one SWF, so I'm trying to find the shortest-path way to convert it to use only one.
The game swf uses a Document Class that includes the package, class constructor, and tons of functions, and runs fine. I have lots of movieclips on the stage that I refer to in my code. The code is something like this (abridged):
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
...
public class Game extends MovieClip {
var EnemyArray:Array;
var HeroArray:Array;
...
public function Game() { // class constructor
EnemyArray = new Array();
addEventListener(Event.ENTER_FRAME,onEnterFrame);
mainRestartButton.addEventListener(MouseEvent.CLICK, RestartLevel);
...
}
public function KeyPressed(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.SPACE)
{
attack();
...
}
} // End of class
} // End of package
I also have another swf, my preloader, which has the following code in frame 1:
import flash.display.Loader;
import flash.net.URLRequest;
import flash.events.ProgressEvent;
import flash.events.Event;
var myLoader:Loader = new Loader();
myLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onLoading);
var myURL:URLRequest = new URLRequest("Game.swf");
myLoader.load(myURL);
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
function onLoading(event:ProgressEvent):void {
var loaded:Number = event.bytesLoaded / event.bytesTotal;
percent_txt.text = "Loading: " + (loaded*100).toFixed(0) + "%";
}
function onComplete(event:Event):void {
myLoader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, onLoading);
myLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onComplete);
this.addChild(myLoader);
}
I've been through the gamut of solutions online and none of them seem to work with the way that my code is set up, such as: How to create Preloader in AS3
I tried his option 1 by taking all the code in my Document Class other than the package and constructor and pasted it into frame 2. However it returns "Error #1009: Cannot access a property or method of a null object reference." for any references to items on the stage, such as:
mainRestartButton.addEventListener(MouseEvent.CLICK, RestartLevel);
As he mentions, "This works well if you organized your project in a way that the most of the assets (images, etc) are in the Flash IDE Library and are not loaded on the first frame (you can check that in each library item's properties)." My project is NOT organized in such a way.
What is the easiest way for me to reorganize my FLA/code so they can have a preloader in a single swf?
Thanks so much for your time and help!
I use FlashDevelop (no FLAs) so I'm not sure if it'll work for you but I use the solution described here.
I'm loading swf externally. I need to access it's methods and variables. This is the code I'm using:
import flash.display.Loader;
import flash.net.URLRequest;
import flash.events.Event;
import flash.display.MovieClip;
var loader:Loader;
var req:URLRequest = new URLRequest("aaa.swf");
var mc:MovieClip;
createLoader();
function createLoader():void {
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.INIT, onSWFLoad);
loader.load(req);
}
function onSWFLoad(e:Event):void {
mc = MovieClip(loader.content);
addChild(mc);
trace(loader.content)
}
EM is loaded SWF's document class. If questioned if variable gameEnded is declared publicly, the answer is yes. The game loads, but there is an error when calling the variable :
ReferenceError: Error #1069: Property gameEnded not found on EM__Preloader__ and there is no default value.
at main_fla::MainTimeline/onSWFLoad()
Check your preloader setting in the ActionScript settings panel of your game.fla - EM__Preloader__ looks to me like an auto-generated class (and not your main EM class).
Also, your EM class should implement a simple interface that you can cast your loader.content to (instead of MovieClip). This way, you can be sure that the methods you need are available, and your code is type-safe. Embed this interface into your preloader.fla instead of the EM class to prevent unnecessary bloating of your SWFs.
It turned out that I had to embed all the code in SWF (I was using some TLF in it)