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.
Related
I'm trying to create a simple Menu in AS3. There is a sprite called startButton, which when pressed will call the function startGame, and that's it! But, not so easy. I'm using flashdevelop IDE so I'm trying to call a loader to get a .png image file for the spite startButton. But, it doesn't work. There are no error messages, the debugger just does not respond. Any help? Here is the code for both files
Main code:
package {
//Other Files
import Menu;
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.ui.Mouse;
public class Main extends Sprite {
//Game values
public static var gameWidth:int = 750;
public static var gameHeight:int = 750;
public function Main() {
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
addChild(Menu.startButton);
Menu.startButton.addEventListener(MouseEvent.CLICK, startGame);
stage.addEventListener(Event.ENTER_FRAME, update);
}
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
}
//Function starts game
public function startGame(evt:MouseEvent):void {
removeChild(Menu.startButton);
}
//Updates every 60 seconds
public function update():void {
trace("Updated");
}
}
}
And Menu Image code:
package {
//Other files
import Main;
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.net.URLRequest;
public class Menu extends Sprite {
public static function imageLoaded():void {
startButton.addChild(loader);
//initizlize values for startButton Bitmap
startButton.x = (Main.gameWidth / 2) - (startButton.width / 2);
startButton.y = (Main.gameHeight / 2) - (startButton.height / 2);
}
//create startButton Bitmap
public static var startButton:Sprite = new Sprite();
public static var loader:Loader = new Loader();
loader.load(new URLRequest("lib/menustartbutton.png"));
loader.addEventListener(Event.COMPLETE, imageLoaded);
}
}
By the way, I wait for the loader to successfully load the image before working with it, just in case the image takes more time and it draws errors.
The problem is that you misuse static. all static methods/properties are initialized before the classes themselves. As a result static can receive values but they cannot run any code. Running code has to happen after all classes are ready to go which is not the case when static is initialized. In your case startButton and loader are created correctly but the next line never runs 'loader.load'.
Don't misuse static, you are obviously trying to use static to make you code writing and life easier but at the end because you are misusing it you will always end up with more problems.
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 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;
}
}
}
I am just trying to make a simple .swf file that plays a piece of audio when it loads. This compiles but when I bring it up into the browser nothing happens. I could only find sprite based tutorials so I took a stab that you can extend Sound the same way as you would extend Sprite. The final version is going to be headless and called my Java Script to play audio on Events.
package {
import flash.media.Sound;
import flash.net.URLRequest;
public class typeRight extends Sound {
public function HelloWorld( ) {
load(new URLRequest('./sound.mp3'));
play();
}
}
}
I am NOT working in Flash so please no GUI advice ; )
Rather than subclassing the Sound class, create a document class like this that contains a Sound class in it:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.net.URLRequest;
public class SoundPlayer extends Sprite
{
protected var _sound : Sound;
protected var _channel : SoundChannel;
public function SoundPlayer()
{
_sound = new Sound();
_sound.addEventListener(Event.COMPLETE, soundLoadCompleteHandler);
_sound.addEventListener(IOErrorEvent.IO_ERROR, loadError);
_sound.load(new URLRequest("./sound.mp3"));
}
protected function soundLoadCompleteHandler(evt : Event) : void
{
// Use the _channel object to control sound properties such as pan and volume.
_channel = _sound.play();
}
protected function loadError(evt : IOErrorEvent) : void
{
trace ("ERROR :: " + evt);
// You could try recovering from the error here.
}
}
}
I have an an class a fla called draw.fla . The document class associated with draw is Draw.as The code inside Draw.as is as follows
package
{
import flash.display.MovieClip;
import flash.display.Graphics;
public class Draw extends MovieClip
{
public function drawCircle1(color:Number):void
{
graphics.beginFill(color);
graphics.drawCircle(100,100,40);
graphics.endFill();
}
}
}
The resulting swf is called draw.swf.
I have another fla called test.fla.
The following is the code on the first frame on the main time line.
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.display.Loader;
var swfLoader = new Loader();
var color:Number;
color = Math.round(Math.random()*0xFFFFFF);
var urlReq:URLRequest = new URLRequest("draw.swf");
swfLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, swfLoadComplete);
swfLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, swfLoadError);
swfLoader.load(urlReq);
function swfLoadComplete(evt:Event):void
{
var loader:Loader = Loader(evt.target.loader);
addChild(loader.content);
swfLoader.removeEventListener(Event.COMPLETE, swfLoadComplete);
}
function swfLoadError(evt:IOErrorEvent):void
{
trace("Unable to load swf ");
swfLoader.removeEventListener(IOErrorEvent.IO_ERROR, swfLoadError);
}
I have loaded dwaw.swf into test.swf as you can see. Is there anyway I can access the drawCircle1 function of Draw from the test.fla. Actually I need to pass the value color as an argument while accessing this function.
If I'm not wrong, once the loader is complete you could simply make MovieClip(loader.content).drawCircle1(0xFF0000);.
Loader.content should be that class, and function can be called by name with square bracket syntax:
function swfLoadComplete(evt:Event):void
{
var loader:Loader = Loader(evt.target.loader);
addChild(loader.content);
//trying to call function drawCircle1
loader.content["drawCircle1"](0xFF0000);
swfLoader.removeEventListener(Event.COMPLETE, swfLoadComplete);
}