I am working on an Air 2.6 project with an embedded SWF.
I am using the following embed code:
[Embed(source = "../../assets/click_feedback.swf", symbol="sub_circle")]
[Bindable]
public static var click_feedback:Class;
And the following code to get an instance of the click_feedback class:
private var cfb:MovieClip = new Assets.click_feedback() as MovieClip
The problems are:
The asset sub_circle has a frame labeled 'respond'. However, it just plays non stop whether or not the label is called with gotoAndPlay.
And, at the end of the animation, there is an Event.COMPLETE called, which is not being picked-up by my code.
I have tested the sub_circle asset in CS5 where I built it, and, in that environment it does not animate until 'respond' is called, and the event it triggers can be heard by my script.
Is this the correct way to handle embedded assets from an SWF?
Embedding of separate symbols from swf in general isn't a good idea:
It slows the compilation of your project, because of compiler must transcode swf format.
Embedding delete ALL AS code from timeline (I didn't check, but may be it remove labels as well, and it can be the reason of your issue).
I recommend embed the hole swf file and loads its bytes in runtime, a little more code to handle the async loading, but much more freedom and flexibility in use:
you safe all as3 code
you can choose ApplicationDomain where to load classes
you can easily switching from Embedding to runtime swf loading by url at any time, if you want to separate the as code and art/sounds assets.
organize your assets to library with the AssetsManager (with api like load(ByteArray or URL), getSkin(name):DisplyObject)
Code example adapted for your assets:
package
{
import flash.display.DisplayObject;
import flash.display.Loader;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.system.ApplicationDomain;
import flash.system.LoaderContext;
import flash.utils.ByteArray;
[SWF(width="800", height="200", backgroundColor="0x8B8B8B")]
public class astest extends Sprite
{
[Embed(source="../../assets/click_feedback.swf", mimeType="application/octet-stream")]
private static const common_art:Class;
private var loader:Loader;
private var domain:ApplicationDomain = ApplicationDomain.currentDomain;
public function astest()
{
init();
}
public function init():void
{
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
var loaderContext:LoaderContext = new LoaderContext(false, domain);
loaderContext.allowCodeImport = true;
loader.loadBytes(new common_art() as ByteArray, loaderContext);
}
private function onLoaded(event:Event):void
{
var clip:MovieClip = getSkin("sub_circle") as MovieClip;
addChild(clip);
}
private function getSkin(name:String):DisplayObject
{
if(domain.hasDefinition(name))
{
var clazz:Class = domain.getDefinition(name) as Class;
return new clazz() as DisplayObject;
}
return null;
}
}
}
Related
I decompiled a swf file using JPEXS Free Flash Decompiler v.10.0.0 , When i decompile the swf file I only see 2 scripts:
AppLoader
$gamename-web_sec$aba37a......
In the binaryData folder, there's a thing named:
DefineBinaryData(1:gamename-web_sec$aba37a........
Here's the tree of the decompiled swf:
gamename.swf
Headers
BinaryData
DefineBinaryData(1:gamename-websec$aba37a...
Frames
Scripts
AppLoader
$gamename-web_sec$aba37a...
inside the appLoader, here's the script:
package
{
import flash.display.Loader;
import flash.display.Sprite;
import flash.system.ApplicationDomain;
import flash.system.LoaderContext;
import flash.utils.ByteArray;
public class AppLoader extends Sprite
{
private var content:Class;
public function AppLoader()
{
content = §gamename-web_sec$aba37a95a98fb59f905d8915dbd77871-2007405621§;
super();
var loader:Loader = new Loader();
addChild(loader);
var ba:ByteArray = new content();
var bamod:ByteArray = new ByteArray();
bamod.writeBytes(ba,1,ba.length - 1);
loader.loadBytes(bamod,new LoaderContext(false,new ApplicationDomain()));
}
}
}
$gamename-web_sec$aba37a... actionscript:
package
{
import flash.utils.ByteArray;
public class §gamename-web_sec$aba37a95a98fb59f905d8915dbd77871-2007405621§ extends ByteArray
{
public function §chitchatcity-web_sec$aba37a95a98fb59f905d8915dbd77871-2007405621§()
{
super();
}
}
}
I see that It's loading the swf game with that BinaryData. When i try to export the bin file and try to load it again using JPEXS Flash Decompiler again. This what it shows,
[2744232]
header
shapes
sprites
binaryData
DefineBinaryData (51763)
DefineBinaryData (11730)
frames
others
ErrorTag
Unknown (ID=377)
Unknown (ID=909)
Unknown (ID=544)
...
Unknown (ID=879)
ErrorTag
Unknown (ID=777)
....
scripts
frame1
DoAction
It show's so many unknown objects in others folder.
Do P-code source: (because the actionscript source is blank)
Jump loc0005
loc0005:
Do you guys have an idea how will i able to decompile the swf file? I have a permission of the owner, and he wants me to decompile it, so we can better secure the game more.
I do not have quite knowledge about preloaders but I have read couple of articles and Adobe instructions. So I am confused about preloaders using in Flash applications.
I am planning to call all MovieClips, sounds, and etc. from library and nothing will be on the stage. For this situation, is it logical to apply preloader, if so which approach will be the most suitable one (even with smaller swf sizes)?
It's impossible to tell you which approach is the best when you're not telling the context of your application.
For banners and smaller swf ( <100k) etc I shouldn't use any sort of a preloader. Flash will handle the loading itself (only without showing a visual loader)
For bigger swf games I normally let one small swf loads the main swf.
package
{
import flash.display.Loader;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.net.URLRequest;
import flash.system.ApplicationDomain;
import flash.system.LoaderContext;
[SWF(width="992", height="768", frameRate="30", backgroundColor="0x000000")]
public class Preloader extends Sprite
{
private var percent:Number;
private var loader:Loader;
public function Preloader()
{
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
var movieurl:String = loaderInfo.parameters.movieurl;
loader = new Loader();
loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, progressHandler);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
var loaderContext : LoaderContext = new LoaderContext(false,new ApplicationDomain(null));
loader.load( new URLRequest("main.swf" + version),loaderContext);
}
private function progressHandler(event:ProgressEvent):void
{
percent = ((event.bytesLoaded / event.bytesTotal)*100);
trace ("laoded": percent)
}
private function completeHandler(event:Event):void{
//removeChild(progressBar);
addChild(loader);
}
}
}
If your application must exist of 1 swf. You could use a Preloader class
main swf class
[Frame(factoryClass="Preloader")]
[SWF(width = "950", height = "600")]
public class Main extends Sprite
{
// do your coding
}
preloader swf class
package {
import erasmus.simulation.LoaderFC;
import flash.display.DisplayObject;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.UncaughtErrorEvent;
import flash.utils.getDefinitionByName;
public class Preloader extends MovieClip {
public function Preloader(){
if (stage){
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
}
addEventListener(Event.ENTER_FRAME, checkFrame);
loaderInfo.addEventListener(ProgressEvent.PROGRESS, progress);
loaderInfo.addEventListener(IOErrorEvent.IO_ERROR, ioError);
}
private function progress(e:ProgressEvent):void {
var progress : Number = e.bytesLoaded / e.bytesTotal;
trace ("loader progress")
}
private function checkFrame(e:Event):void {
if (currentFrame == totalFrames){
stop();
loadingFinished();
}
}
private function loadingFinished():void {
removeEventListener(Event.ENTER_FRAME, checkFrame);
loaderInfo.removeEventListener(ProgressEvent.PROGRESS, progress);
loaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, ioError);
var mainClass:Class = getDefinitionByName('Main') as Class; // class must be a string reference
this.stage.addChild(new mainClass(this) as DisplayObject);
}
}
}
Nothing will be on stage - by that I assume you're using Flash IDE with timeline?
In this case (as well as other cases, in fact) you must use the preloader. There is a possibility (even when running locally) that when you try to access something from the library, it will not be fully loaded yet.
In Flash IDE a preloader can be first two frames in the timeline: some progress sprite or just a TextField that spans two frames, first frame does nothing, second frame checks bytesLoaded vs. bytesTotal and goes to first frame if the movie is not fully loaded yet. The third frame is where all main code starts.
Note that all your library assets must be set for 'export in Frame 3', i.e. not in any of frames where loader is active.
Alternately, you can use single frame with event-based loader.
When using FlashDevelop, there is a ready-made template for a project with a preloader.
There is a common mistake when people use some of their library classes or assets in the preloader to show a nice progress indicator. In that case, all that data has to be loaded first, and preloader cannot work immediately. It looks like empty screen with long pause and no preloader, and then the application is 100% loaded at once. So the preloader becomes pointless, it can't show any progress to the user.
Hi there,
i have doubt about converting .fla files to html5 canvas. i am developing the project by using Action script version 3 but now i want that project on html5 canvas for the browser compatibility and other issues to be solved..
Anyone help me to solve the issue
I am trying Swiffy Extension and CreateJS tools. But the code was not linking properly because am using action script and also i don't know how to linking files from one to another.. please anyone help me to solve the issues.
Example .FLA code:
package com.privacy_pirates.game {
//import all the Flash libraries we will need
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.display.Loader;
import flash.events.ProgressEvent;
import flash.net.URLRequest;
import flash.utils.Timer;
import flash.utils.*;
public class Main extends MovieClip{
//all the onjects that are on the stage that will need to be called
public var content_mc:MovieClip;
public var introLoader:Loader;
public var tutotrialLoader:Loader;
public var preloader_mc:Preloader;
public var btn_play:MovieClip;
public function Main() {
// constructor code
//when the class is added to the stage
addEventListener(Event.ADDED_TO_STAGE, addedToStage);
}
public function addedToStage(e:Event):void{
//trace("added to stage is executing");
removeEventListener(Event.ADDED_TO_STAGE, addedToStage);
//the swf that will be loaded
introLoader = new Loader();
//when it's ready, perform the function loadComplete
introLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadComplete);
//make the preloader
introLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, loadProgress);
//the file that will be loaded
introLoader.load(new URLRequest("Animation.swf"));
}
private function loadComplete(e:Event):void{
//trace("load is complete");
//add the file to the stage
addChild(introLoader);
}
//the progress bar at the bottom of the screen
private function loadProgress(e:ProgressEvent):void{
var percent:Number = e.bytesLoaded / e.bytesTotal;
preloader_mc.setPercent(percent);
}
}
}
I rarely use sounds in AS3/Flash. I am using Flash Pro CS6, but I can't seem to figure out how to access, control (play, stop, etc) sounds embedded in an external SWF loaded into the main SWF.
It's easy to control them when embedded on the main swf. However, on an externally loaded SWR, I get all kinds of errors. For this app, I really need to embed them in the external SWF.
I read several solutions, but none seem to work.
I embed the sound an mp3 file called soundSegment1.mp3 using Flash CS6 import tool and then open the actionscript properties panel on flash to select the class name: SoundSegment1. Then I edit the class code and create a file called SoundSegment1.as and it's saved right next to my document class main.as in the same directory. The code of the SoundSegment1 class looks like this:
package {
import flash.media.*;
public class SoundSegment1 extends Sound
{
public function SoundSegment1 ()
{
// no code in here
}
public function playSound()
{
var soundSegment1:Sound = new SoundSegment1();
var channel:SoundChannel = soundSegment1.play();
}
}
}
Then, in my main.as, I have done several attempts to play this sound such as:
var fileLocation:URLRequest = new URLRequest(SWFToLoad);
loader.load(fileLocation);
loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, progressListener);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeListener);
loader.contentLoaderInfo.addEventListener(Event.INIT, initListener);
function initListener(e:Event):void // I also placed this code on the completeListener and it didn't work
{
loader.content.soundSegment1.playSound(); // doesn't work.
}
I get:
Line XXX 1061: Call to a possibly undefined method playSound through a reference with static type flash.display:DisplayObject.
or, I also read that I should be able to do something like this anywhere in the Main.as file:
var theClass:Class = Class(loader.content.getDefinitionByName("SoundSegment1"));
var theSound:theClass = new theClass();
theSound.play() //doesn't work either.
I also tried on the completeListener:
var TheClass:Class = e.target.applicationDomain.getDefinition("SoundSegment1") as Class;
var theSound:TheClass = new TheClass();
theSound.play() //doesn't work either.
I get:
ReferenceError: Error #1065: Variable SoundSegment1 is not defined.
at flash.system::ApplicationDomain/getDefinition()
I am stuck and I really need to get this to work. I would be genuinely grateful for your help.
Thank you in advance for any help provided. I really need to get it to work, because I can't simply embed them in the main SWF or load them individually externally one by one.
Thanks again!
user SnickelFritz from Kirupa gave me a fabulous answer with much easier code, which can be very powerful when using multiple sounds. This is just great, because you can use only one preloader per SWF, instead of having multiple loader for each file:
code for the main.as file
http://www.kirupa.com/forum/showthread.php?305098-Playing-a-embedded-sound-in-an-external-swf
package
{
import flash.display.*;
import flash.media.*;
import flash.events.*;
import flash.net.*;
public class Main extends MovieClip
{
var swf:MovieClip;
public function Main()
{
var l:Loader = new Loader();
l.contentLoaderInfo.addEventListener(Event.COMPLETE, swfLoaded);
l.load( new URLRequest("child.swf") );
}
private function swfLoaded(e:Event):void
{
swf = e.target.content as MovieClip;
addChild(swf);
swf.playSound();
}
}
}
Code for the loaded swf "child.as"
package
{
import flash.display.*;
import flash.media.*;
import flash.events.*;
import flash.net.*;
public class Child extends MovieClip
{
private var s:Sound1;
private var sc:SoundChannel;
public function Child()
{
s = new Sound1();
sc = new SoundChannel();
// All of the following lines are actually optional, if all your graphic elements are already inside the swf prepared in flash pro
var g:Graphics = this.graphics;
g.beginFill(0x666666);
g.drawRect(0,0,550,400);
g.endFill();
}
public function playSound():void
{
sc = s.play();
}
}
}
User "kglad.com" on the Adobe Forums also gave me a good answer:
http://forums.adobe.com/message/5681137#5681137
I have number of SWF files which should be accessed from external server. To be able to do this I need to have Security.allowDomain in each SWF file. The problem here is that I don't have FLA for those files and there are thousands of SWFs.
If there a better way to configure those files to be accessible from other domain?
Like having some kind of config file or so.
Yes, there is one workaround, but I think it's a security hole, so it can be fixed in any release of flash player. Meanwhile it works now so here is solution - use URLLoader with BINARY dataFormat as preloader for swf bytes:
swf without Security permissions for it scripting:
package
{
import flash.display.MovieClip;
public class astest extends MovieClip
{
public function astest()
{
}
public function externalCheck():void
{
graphics.beginFill(0xFF0000);
graphics.drawCircle(100, 100, 100);
}
}
}
Loader swf that wants to load previous swf and call the externalCheck method:
package
{
import flash.display.Loader;
import flash.display.MovieClip;
import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
import flash.net.URLRequest;
import flash.utils.ByteArray;
public class astest2 extends MovieClip
{
private var loader:Loader;
private var urlLoader:URLLoader;
public function astest2()
{
init();
}
//this method works fine
protected function init():void
{
urlLoader = new URLLoader();
urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
urlLoader.load(new URLRequest("http://domain_with_your_swfs/astest.swf"));
urlLoader.addEventListener(Event.COMPLETE, function(event:Event):void
{
addChild(loader = new Loader());
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoader);
loader.loadBytes(urlLoader.data as ByteArray);
});
}
//this method will fire SecurityError when calling the 'externalCheck' method
protected function init2(event:Event = null):void
{
addChild(loader = new Loader());
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoader);
loader.load(new URLRequest("http://domain_with_your_swfs/astest.swf"));
}
protected function onLoader(event:Event = null):void
{
var swf:Object = loader.content;
swf.externalCheck();
}
}
}
Don't forget to place the crossdomain.xml file to the root of your server with swf files to load, without it URLLoader will not able to load the bytes, it's the only security requirement.