Flixel - How to load and play an embedded swf file - actionscript-3

I have been searching the web and all of the codes I have found are to play external swf files that have a timeline. The file that I am trying to load does not have a timeline. I am using the Flixel framework for this project and the file that I want to play is also made in Flixel(don't have the source file just the swf file).
Most of the code I have is from a cutscene template that I found on the Flixel forum. Here is what I have so far:
package
{
import org.flixel.FlxState;
import org.flixel.FlxG;
import flash.display.MovieClip;
import flash.media.SoundMixer;
import flash.events.Event;
public class SponsorsState extends FlxState
{
//Embed the cutscene swf relative to the root of the Flixel project here
[Embed(source='assets/DirtPileLogo.swf', mimeType='application/octet-stream')] private var SwfClass:Class;
//This is the MovieClip container for your cutscene
private var movie:MovieClip;
//This is the length of the cutscene in frames
private var length:Number;
override public function create():void
{
movie = new SwfClass();
//Set your zoom factor of the FlxGame here (default is 2)
var zoomFactor:int = 2;
movie.scaleX = 1.0/zoomFactor;
movie.scaleY = 1.0 / zoomFactor;
//Add the MovieClip container to the FlxState
addChildAt(movie, 0);
//Set the length of the cutscene here (frames)
length = 100;
//Adds a listener to the cutscene to call next() after each frame.
movie.addEventListener(Event.EXIT_FRAME, next);
}
private function next(e:Event):void
{
//After each frame, length decreases by one
length--;
//Length is 0 at the end of the movie
if (length <= 0)
{
//Removes the listener
movie.removeEventListener(Event.EXIT_FRAME, next);
//Stops all overlaying sounds before state switch
SoundMixer.stopAll();
//Enter the next FlxState to switch to
FlxG.state = new PlayState();
}
}
}
}
When I run this I get this error: Type Coercion failed: cannot convert SponsorsState_SwfClass#fb5161 to flash.display.MovieClip., all I want to do is play the swf file for a set frame count then move onto the next state.
Any ideas on how to do this?

Try to replace the following:
[Embed(source='assets/DirtPileLogo.swf', mimeType='application/octet-stream')]
private var SwfClass:Class;
//This is the MovieClip container for your cutscene
private var movie:MovieClip;
into
//Mark your symbol for export and name it => MyExportedSymbol
[Embed(source='assets/DirtPileLogo.swf', symbol = "MyExportedSymbol")]
private var SwfSymbol:Class;
//Make sure that MyExportedSymbol base class is MovieClip
private var movie:MovieClip = new SwfSymbol;
Basically, you mark your symbol for export, give it a name and use that in the embed code. You will embed that symbol only.

You are incorrectly setting a mimeType on your embed. Remove the mimeType and it should work properly. See the docs on embedding assets for more information.

I believe the solution you are looking for is to use the Loader class.
[Embed (source = "assets/DirtPileLogo.swf", mimeType = "application/octet-stream")]
private var content:Class;
private var loader:Loader;
public function Main():void
{
var data:ByteArray = new content();
loader = new Loader();
addChild( loader );
loader.loadBytes( data, new LoaderContext(false, new ApplicationDomain() ) );
// ... add listener to loader if necessary, etc...
}

Related

How can I use a document class in a single AS3 movie clip?

I have a confetti generator that I am tyring to add to a single movie clip within my flash file. The clip is masked and I want to have some graphics and text appear above the confetti (which will be above a background layer as well).
I purchased a decent script and have modified it to work with some original confetti artwork but I can't figure out how to use this class (or change it for use) in just the one movie clip. Pasting the class below. I've been stressing about this for a couple of hours now, any help would be greatly appreciated.
package com.pixeljunkyard
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import caurina.transitions.*;
import fl.motion.Color;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
public class Main extends Sprite
{
//Create Heart Instance
private var hearts:Heart;
//Amount of hearts
private var totalHearts:Number = 30;
//Falling Speed
private var speed:Number = 1.5;
//Constructor
public function Main()
{
//Align top left for screen aspect ratio
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
//Loop through the amount of heart to be created
for (var i = 0; i < totalHearts; i++)
{
//Create new heart
var heart = new Heart();
//Set Random value
var randScale:Number = randRange(50, 100);
var randRotation:Number = randRange( -180, 180);
var randRotationY:Number = randRange( -360, 360);
//Random position and scale
heart.x = randRange(0, stage.stageWidth);
heart.y = randRange( -stage.stageHeight, stage.stageHeight);
heart.scaleX = randScale/100;
heart.scaleY = randScale/100;
//Name each heart with the number of creation
heart.name = "heart" + i;
var Low : int = 1;
var High : int = 8;
var myRandomNumber:int = Math.floor(Math.random()*(1+High-Low))+Low;
heart.gotoAndStop(myRandomNumber);
//Add eventlisteners for interactions
heart.addEventListener(MouseEvent.ROLL_OVER, hit_heart);
heart.addEventListener(Event.ENTER_FRAME, change_shade);
//Initial Animation
Tweener.addTween(heart, {time:randRange(1,5)/speed, rotation:randRotation,rotationY:randRotationY,y:stage.stageHeight+(heart.height/2)+20, transition:"linear", onComplete:rebirth,onCompleteParams:[heart]} );
//Add to Stage
addChildAt(heart, i);
}
}
//Change shade to give lighting effect
private function change_shade(e:Event):void
{
//New color instance
var c:Color = new Color();
//Set properties
c.brightness = e.target.rotation / 300;
//Apply color to heart
e.target.transform.colorTransform = c;
}
//Random Function
private function randRange(min:Number, max:Number):Number
{
var randomNum:Number = Math.floor(Math.random() * (max - min + 1)) + min;
return randomNum;
}
//Interactive animation
private function hit_heart(e:Event):void
{
Tweener.addTween(e.target, { time:randRange(1,3), rotationY:e.target.rotationY+180 } );
}
//Reset heart to top of the screen once fallen
private function rebirth($heart:Heart):void
{
$heart.x = randRange(0, stage.stageWidth);
$heart.y = -$heart.height;
Tweener.addTween($heart, {time:randRange(1,5)/speed, rotation:randRange(-180,180),y:stage.stageHeight+($heart.height/2)+20, transition:"linear", onComplete:rebirth,onCompleteParams:[$heart]} );
}
}
}
Now I understand your problem.
First of all, I suggest to never write code on the timeline, except simple stuff like stop() or gotoAndPlay("loop").
The easiest way to achieve what you want is to do the following:
Make a blank MovieClip in Flash IDE Ctrl + F8
Give it a linkage like this:
Then click the edit button (marked with a red rectangle)
Open in Flash Professional if asked
Save the file in your .FLA directory and copy the contents of your Main.as file into this file
Remove the package name ("com.pixeljunkyard")
Change the public class Main extends Sprite to public class ConfettiContainer extends MovieClip and import flash.display.MovieClip
Now you have a class ConfettiContainer which does the same stuff that you Main.as file did. Don't forget to copy anything that this Main.as class uses from stage to your ConfettiContainer MovieClip.
You can now create and use it like this:
var confetti:ConfettiContainer = new ConfettiContainer();
addChild(confetti);
P.S. If you can't see Export for Actionscript option when creating a Symbol in Flash, click Advanced.

CS5+AS3 Preloader starts at 50%; no clue why

I know there are a lot of previous topics about preloaders and I've tried to follow every one of them but I still get the same problem (well they have helped me go from 80% -> 50%)
Right now it starts at 61450 / 125207 which is about 50%.
Here is my Main Document (default class file for the entire project) class:
public class MainDocument extends MovieClip
{
private var preloader:Preloader;
private var sB:startButton;
public function MainDocument()
{
preloader = new Preloader();
preloader.x = 300;
preloader.y = 400;
addChild(preloader);
loaderInfo.addEventListener(Event.COMPLETE,addStartButton,false,0,true);
}
private function addStartButton(e:Event):void
{
sB = new startButton();
sB.x = 300;
sB.y = 450;
sB.addEventListener(MouseEvent.CLICK,sMainMenu,false,0,true);
addChild(sB);
loaderInfo.removeEventListener(Event.COMPLETE,addStartButton);
}
private function sMainMenu(e:Event):void
{
sB.removeEventListener(MouseEvent.CLICK,sMainMenu);
removeChild(sB);
removeChild(preloader);
sB = null;
preloader = null;
var menuScreen = new MenuScreen();
addChild(menuScreen);
//I have heard that the following code might work better:
//var menuScreen:Class = getDefinitionByName("MenuScreen") as Class;
//addChild(new menuScreen() as DisplayObject);
}
}
And the Preloader that it attaches:
public class Preloader extends MovieClip
{
public function Preloader()
{
addEventListener(Event.ENTER_FRAME,Load);
}
private function Load(e:Event):void
{
//"bar" is a movieclip inside the preloader object
bar.scaleX = loaderInfo.bytesLoaded/loaderInfo.bytesTotal;
//"percent" is a dynamic text inside the preloader object
percent.text = Math.floor(loaderInfo.bytesLoaded/loaderInfo.bytesTotal*100)+"%";
trace(loaderInfo.bytesLoaded+" / "+loaderInfo.bytesTotal);
if (loaderInfo.bytesLoaded == loaderInfo.bytesTotal)
{
removeEventListener(Event.ENTER_FRAME,Load);
}
}
}
-> Nothing is set to Export on Frame 1 except for the Preloader
-> No objects exist on the first frame; the only code on first frame is stop();
-> I placed a copy of every single MovieClip in the second frame and when the startButton is clicked, a gotoAndStop(3); is run so no one ever sees frame 2.
If anyone knows of anything simple that I could have forgotten, please let me know!
Thanks!
You're tying to use a preloader in the file being preloaded. In that case, there is going to be bloat from the rest of the project's code and assets. The reason you are seeing your preloader seemingly delayed is because a swf must load completely before any code will execute. This includes all assets on stage regardless of what frame they are on, even if you have settings in place to export on something other than frame 1. Instead, try using a blank shell as your preloader. This shell will have nothing in it but the loader code and a preloader graphic or animation. When the load is finished, hide your preloader and add your loaded content to the stage of the shell, or a container movieclip in the shell.
All the following code goes in your shell, which is just another FLA file with nothing in it but this code, and a preloader bar. The dimensions of this file should be the same as the file you are loading into it, ie your original swf file you were trying to preload.
Use it by calling loadSwf( "mySwfNameOrURLToSwf.swf" );
The variable _percent will populate with the current load percentage, which you can correspond to your loading bar scale. Presuming the preloader bar is named "bar", the line bar.visible = false; in the onSwfLoaded function will hide it. addChild( _swf ) adds the loaded swf to the shell's stage. The line _swf.init(); references a function in the loaded swf you will need to add called init() that starts your loaded swf doing whatever it is its supposed to do. Have everything in the loaded swf start on the first frame now, including the init() function.
import flash.display.MovieClip;
import flash.display.DisplayObject;
import flash.display.Loader;
import flash.display.Bitmap;
import flash.net.URLRequest;
import flash.system.ApplicationDomain;
import flash.system.SecurityDomain;
import flash.system.LoaderContext;
import flash.system.Security;
import flash.events.Event;
import flash.events.ProgressEvent;
var _swfLoader:Loader;
var _swf:DisplayObject;
var _percent:Number;
function loadSwf( swfURL:String ):void
{
_swfLoader = new Loader();
var req:URLRequest = new URLRequest( swfURL );
var loaderContext:LoaderContext = new LoaderContext();
loaderContext.applicationDomain = ApplicationDomain.currentDomain;
loaderContext.checkPolicyFile = true;
_swfLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onSwfProgress);
_swfLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onSwfLoaded);
_swfLoader.load(req, loaderContext);
}
function onSwfProgress( evt:Event ):void
{
_percent = Math.round( ( evt.target.bytesLoaded / evt.target.bytesTotal ) * 100 );
}
function onSwfLoaded( evt:Event ):void
{
_swfLoader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, onSwfProgress);
_swfLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onSwfLoaded);
_swf = _swfLoader.content;
addChild( _swf );
bar.visible = false;
_swf.init();
_swfLoader = null;
}
your code looks ok.
when you are not on a http server, loading process are simulated.
After compiling, press crtl + B.
In menu you can choose the downloading speed and simulate a download by pressing again ctrl+enter.
it might help you to debug your preloader
#Lee Burrows What you said was right but would have been better if you looked at what I mentioned at the end of the code (three bold points)
The solution I used was:
-> I set everything to Export on Frame 2 on my 3 frame document.
-> Removed everything on Frame 2
-> Created a TextField via constructor and used drawRectangle for loading bar
-> No movieclips present on frame 1, and used
var menuScreen:Class = getDefinitionByName("MenuScreen") as Class;
addChild(new menuScreen() as DisplayObject);
instead of the previous code.
The reason why what I had originally didn't work because, as Lee Burrows mentioned, the Export for Actionscript hangs the loading if X = 1 in Export on Frame X, regardless if Export on Frame 1 was checked or not. Changing it to 2 or unchecking Export for Actionscript were the two solutions (except if it isn't exported for actionscript, then its code cant be referenced to).
Preloader starts at about 2% now.

how do I access the main class's stage? + Can I pass functions as arguments like this?

There are two files in my actionscript project named "TestAPP", TestAPP.as and Draggable.as
TestAPP.as:
package {
import flash.display.Sprite;
import flash.display.Stage;
public class TestAPP extends Sprite
{
var _mainStage:Stage;
public function TestAPP()//This is where we test the UI components.
{
var sp:Sprite = new Sprite();
_mainStage = stage;
_mainStage.addChild(sp);
sp.graphics.beginFill(0x00FF00);
sp.graphics.drawCircle(0,0,10);
sp.graphics.endFill();
sp.x = 50;
sp.y = 50;
var draggable1:Draggable = new draggable(sp,_mainStage,limitingfunc);
}
public function limitingfunc(x:Number,y:Number):int{
return 0;
}
}
}
And for the draggable.as:
package
{
import flash.display.Sprite;
import flash.display.Stage;
import flash.events.MouseEvent;
public class Draggable
{
private var _limitingFunc:Function;
private var _which:Sprite;
private var _MouseSavedX:Number;
private var _MouseSavedY:Number;
private var _stage:Stage;
public function Draggable(which:Sprite,stage:Stage,limitingfunc:Function)
{
_limitingFunc = limitingfunc;
_which = which;
_stage = stage;
_which.addEventListener(MouseEvent.MOUSE_DOWN,begin_drag);
}
//limiting func: returns 0 when the object is free to move that place.
//returns -1 when the user wants to block X coordinate changes (but maintain Y free)
//returns -2 when the user wants to block Y ...
//returns -3 or less when the user wants to block both X and Y from changing.
//returns
private function Return_0(x:Number = 0,y:Number = 0):int{
return 0;
}
private function begin_drag(ev:MouseEvent):void{
var xTo:Number = _stage.mouseX - _MouseSavedX + _which.x;
var yTo:Number = _stage.mouseY - _MouseSavedY + _which.y;
var limitingFuncReturnValue:int = _limitingFunc(xTo,yTo);
if(limitingFuncReturnValue == 0){//free to move.
_which.x = xTo;
_which.y = yTo;
}
else if(limitingFuncReturnValue == -1){//free to move Y
_which.y = yTo;
}
else if(limitingFuncReturnValue == -2){
_which.y = yTo;
}
//else:do nothing.
}
}
}
In "my actionscript theory", I'm supposed to see a circle that follows the mouse when I click it. (The draggable is not fully implemented) But the circle doesn't even budge :(
...I've been trying to figure out how to access the main class's stage property. I've googled for it, but still no progress.
Please help this helpless newb!!! I'll really appreciate your help:)
Thank you!
You're implementing your 2nd class as "draggable", when you named it (and it has to be named) "Draggable" with an upper case. Change it and see if that works. You seem to be passing in the parent classes stage correctly though.
If TestAPP is your document class. You can access to the stage thru the stage property (like your are doing in your example).
If TestAPP is not the document class, you should listen first to the ADDED_TO_STAGE event and then access to the stage property.
There is no need to add _mainStage property because you already have the stage property.
In order to move objects around, you need to use the ENTER_FRAME event.
You can access the main class' stage property the same way you do it for any DisplayObject on the stage: Use this.stage.
So just this should be enough:
var sp:Sprite = new Sprite();
stage.addChild(sp);
You could then pass the sprite and the main class' stage as a parameter, the way you did - but I would recommend creating a subclass Draggable extends Sprite and instantiate the whole thing using new Draggable() instead.
The new object will automatically have its own reference to stage as soon as it is added to the display list, and limitingFunc could be a member of Draggable, as well.
Also, you can use the startDrag() and stopDrag() methods, no need to implement your own: You can specify a Rectangle as a parameter to startDrag() to limit the permitted movement.
if you need it so much you may:
private static var _instance: TestAPP;
//...
public function TestAPP(){
_instance = this;
//...
}
public static function get instance():TestAPP{
return _instance;
}
public static function set instance(newVal: TestAPP):void{
_instance = newVal;
}
and you'll be able to reference its stage from any class where your TestAPP will be imported just with TestAPP.instance.stage.
but _instance is a property of the class TestAPP itself, not its instances

Flash AS3: Unable to view loaded swf after loading it inside of package

Good morning friendly Flashers ;) So I've been trying since yesterday to just load a SWF file into my main movie. I've done this before just placing code inside a movieClip, but this time I'm working inside of Class files. I have my main class which calls a function inside of my sub class which contains the loader. My problem is that the swf will load (I can tell via traces) but I cannot see the loaded swf :(
Below is the code inside of my sub class
package src.howdinicurtain {
import flash.net.*;
import flash.display.*;
import flash.events.Event;
public class HowdiniFrame extends MovieClip {
//public var splashLoader;
public var introLoader:Loader = new Loader();
public var introContainer:MovieClip;
private var holdX:Number;
private var holdY:Number;
public function HowdiniFrame(url:String, loadX, loadY):void {
holdX = loadX;
holdY = loadY;
this.addChild(introLoader);
//this.addChild(introContainer);
introLoader.load(new URLRequest(url));
introLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,swfLoaded);
}
public function swfLoaded(e:Event):void {
introLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE, swfLoaded);
introContainer = introLoader.content as MovieClip;
//introContainer = MovieClip(introLoader.contentLoaderInfo.content);
addChild(introContainer);
introContainer.x = holdX;
introContainer.y = holdY;
trace("holdX = "+holdX);
trace("holdY = "+holdY);
}
}
}
The code above will load the swf file, I can see the swf files trace statements from the start of the animation to the end, but I cannot actually see the swf file inside of the main swf.
Traces:
The SWF file is = intro.swf
Intro Movie Starts :)
contentLoaderInfo event removed
Intro Movie Ends :(
Here is the code in my main class that calls the sub class function that loads the movie:
var introPath:String = xmlOutput.intro;
trace("The SWF file is = "+introPath+"\r"+"\r");
hc = new HowdiniFrame(introPath, 0, 20);
I swear I throw my code into the first frame of a movieClip and it works fine, I see the animation in the loaded SWF play instantly, but when I have my code inside of Class files I cannot see my SWF at all :( thoughts? ideas? Thanks for any tips!
~ Leon
Always treat your children right. Don't forget to add them in everything you do or else you're a bad parent.
What is hc? Is that a MovieClip on the stage? What if you try:
hc.addChild(new HowdiniFrame(introPath, 0, 20));
or if hc is not a clip on the stage
hc = new HowdiniFrame(introPath, 0, 20);
addChild(hc);

Using the Loader display object to load X jpegs, then resize each of the images differently while they're on the stage

Hey there, I was wondering if this is possible to do
I am able to load the image in and have it displayed easily enough by using addChild(myLoader); where myLoader is in the classWide private scope.
The problem is, whenever I call my function inside that class which adds the loader to the stage, it clears the old one and puts this new one in even if I add a bit where I change myLoader.name to something related to how many images it has completed.
This is a serious hinderance as I can't do anything besides KNOW how many images I will need to load and write the code X times. The problem being is that the urls are read from an XML file.
My main desire was to have a classWide private Array which contained my loaders and I would assign them using myArray.push(myLoader) each time the load had completed. There is a problem which is that it compiles but they never get displayed
it would work as this is written
public class Images extends Sprite
{
private var imagesLoaded = 0;
private var myLoader:Loader;
...
public function Images():Void
{
myLoader = new Loader;
//loop calling a myLoader.load(imageURL) for a bunch of urls
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoaded);
}
public function imageLoaded
{
myArray[imagesLoaded] = myLoader;
trace("does\'nt get to here!!");
addChild(myArray[imagesLoaded]);
imagesLoaded++;
}
}
You could create multiple Loaders to load your multiple files:
public class Images extends Sprite
{
private var imagesLoaded = 0;
private var myArray:Array;
...
public function Images():Void
{
myArray = [];
for each (var url:String in myBunchOfURLS)
loadURL(url);
}
private function loadURL(url:String):void
{
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoaded);
loader.load(new URLRequest(url));
// you'll need to add the loader to the display list to see anything!
addChild(loader);
}
private function imageLoaded(event:Event):void
{
var info:LoaderInfo = LoaderInfo(event.currentTarget);
info.removeEventListener(Event.COMPLETE, imageLoaded);
var loader:Loader = info.loader;
myArray[imagesLoaded++] = loader;
// or you could add the loader to the display list here instead?
}
}
If you have to have one loader, then you'll need to wait for each load to complete, get the bitmap data out of the loaded bitmap, add it to a new bitmap, then start loading the next image. That's a bit more of a pain - I'd stick to this approach if I were you.