As3 project with Preloader - actionscript-3

I want to use the Preloader provided by FlashDevelop but it does not react as it should.
My loader tells me 100% when no file has been downloaded.
The code should display a trace() containing the percent intermediary but does not
Could you help me?
Mains.as
package
{
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.net.URLRequest;
[Frame(factoryClass="Preloader")]
public class Main extends Sprite
{
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
var imgRequest:URLRequest = new URLRequest("http://next-web.be/actionscript/0.jpg");
var img:Loader = new Loader();
img.load(imgRequest);
addChild(img);
}
}
}
Preloader.as
package
{
import flash.display.DisplayObject;
import flash.display.MovieClip;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.utils.getDefinitionByName;
import flash.display.Sprite;
public class Preloader extends MovieClip
{
private var bar:Sprite;
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);
// TODO show loader
bar = new Sprite();
bar.graphics.lineStyle(1, 0x4444ff, 1, true);
bar.graphics.drawRect(0, 0, 100, 6);
bar.x = stage.stageWidth / 2 - bar.width / 2;
bar.y = stage.stageHeight / 2 - bar.height / 2;
addChild(bar);
}
private function ioError(e:IOErrorEvent):void
{
trace(e.text);
}
private function progress(e:ProgressEvent):void
{
// TODO update loader
bar.graphics.lineStyle(0, 0, 0);
bar.graphics.beginFill(0x8888ff);
bar.graphics.drawRect(1, 1, (e.bytesLoaded / e.bytesTotal) * 98 , 4);
bar.graphics.endFill();
trace( "loading:" + (e.bytesLoaded / e.bytesTotal) * 100 );
}
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);
// TODO hide loader
removeChild(bar);
bar = null;
startup();
//stop();
}
private function startup():void
{
var mainClass:Class = getDefinitionByName("Main") as Class;
addChild(new mainClass() as DisplayObject);
}
}
}

You need to register your listener on the contentLoaderInfo property of the Loader you use to download the data (in your case img.contentLoaderInfo).
In your code, you register progress on loaderInfo, which is a field of your Preloader class (inherited from MovieCLip), and will give you the progress on loading the SWF that contains the Preloader class.
public class Preloader extends MovieClip
{
public function Preloader()
{
// This is wrong.
loaderInfo.addEventListener(ProgressEvent.PROGRESS, progress);
// Function `progress` will show the progress of loading your SWF file,
// *not* the JPEG you're loading in class Main.
}
}
You need to register your listener on the contentLoaderInfo property of the Loader you use to download the data (in your case img.contentLoaderInfo).
img.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, progress);
Of course, then it will show only the progress of loading the JPEG file.
You'll also need to either pass the Loader object (or just the contentLoaderLinfo) to the Preloader somehow, or include the event handler in your Main class.

After a continued search, I realized my mistake.
Until now, I always use "loader" but this function does not include my pictures to swf file. So I use a library swc allowing me to generate a complete swf.

Related

AS3 debugger stops responding while trying to load image into sprite using Loader

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.

AS3 - preventDefault() doesn't work in fullscreen (AIR)

I am trying to make a fullscreen program in air that does not become windowed when you press escape. Why is my program not working as it should, and how should make it work correct?
Code:
package
{
import flash.display.*;
import flash.events.*;
import flash.desktop.*;
import flash.text.*;
public class Main extends Sprite
{
public function Main():void
{
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandeler);
}
private function keyDownHandeler(e:KeyboardEvent):void
{
if (e.keyCode == 27)
{
trace("Hello");
e.preventDefault();
}
}
}
}
I created a new project (FlashDevelop) targeting AIR 14 (also successfully tried AIR 3.9) with the following document class file:
package
{
import flash.desktop.NativeApplication;
import flash.display.NativeWindow;
import flash.display.NativeWindowInitOptions;
import flash.display.NativeWindowRenderMode;
import flash.display.NativeWindowSystemChrome;
import flash.display.Sprite;
import flash.display.StageDisplayState;
import flash.events.Event;
import flash.events.FullScreenEvent;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.ui.Keyboard;
public class Main extends Sprite
{
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
if(e) removeEventListener(Event.ADDED_TO_STAGE, init);
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyUpHandler);
var content:Sprite = new Sprite();
content.graphics.beginFill(0xFFFF00);
content.graphics.drawRect(0, 0, 400, 500);
content.graphics.endFill();
addChild(content);
this.addEventListener(MouseEvent.CLICK, fullScreen);
stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
}
private function fullScreen(e:Event):void {
stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
}
protected function keyUpHandler(event:KeyboardEvent):void {
switch(event.keyCode) {
case Keyboard.ESCAPE:
trace("ESCAPE");
event.preventDefault();
break;
default:
trace("UNHANDLED KEY: ", event.keyCode);
}
}
}
}
It worked as expected. When hitting escape, the preventDefault() method on the key event successfully kept the application in full-screen.
Notes:
It has to be on the key down. Key up had no effect. The result was the same with the key down listener on the stage or the nativeApplication.

AS3 Architecture : How to tween a single instance of an object on multiple calls?

I am new to actionscript and am having a trouble displaying a single instance of an object, using FlashDevelop.
I have a main.as in which I am displaying an image as background. Then I display a rectangle containing some text that tweens as the mouse hovers a target (appearing/disappearing on the stage). The rectangle is in a class TextBox.as .
I know my code is quite messy because it creates a new instance of the rectangle everytime I reach the target (calling the tween). But if I try to switch it around it gives me errors. Also I cannot seem to remove my rectangle (with removeChild()) once it is created, it cannot find the child.
Could anyone indicate me what is the architecture I should use so that only one instance of the rectangle is created?
Here's a bit of my code:
//IMPORT LIBRARIES
import Classes.TextBox;
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import com.greensock.TweenLite;
// Setup SWF Render Settings
[SWF(width = "620", height = "650")]
public class Main extends Sprite
{
//DEFINING VARIABLES
[Embed(source="../lib/myimage.jpg")]
private var picture:Class;
private var myTween:TweenLite;
//CONSTRUCTOR
public function Main():void
{
addChild(new TextBox);
addChild(new picture);
addEventListener(MouseEvent.MOUSE_OVER, appear);
}
//ROLLDOWN FUNCTION
public function appear(e:MouseEvent):void
{
trace("Appear");
var text:TextBox = new TextBox();
addChild(text);
addChild(new picture);
if (picture) {
removeEventListener(MouseEvent.MOUSE_OVER, appear);
//addEventListener(Event.COMPLETE, appearComplete);
myTween = new TweenLite(text, 1, { y:340 , onComplete:appearComplete, onReverseComplete:disappearComplete} );
}
}
Thanks in advance.
i dont know what tweening you want to achieve but you should reuse your textbox instance, e.g.:
import Classes.TextBox;
import com.greensock.TweenLite;
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
[SWF(width = "620", height = "650")]
public class Main extends Sprite {
[Embed(source="../lib/myimage.jpg")]
private var pictureClass:Class;
private var picture:Bitmap;
private var textbox:TextBox;
public function Main():void {
if (stage)
init();
else
addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
picture = new pictureClass();
textbox = new TextBox();
addChild(picture);
addChild(textbox);
addEventListener(MouseEvent.MOUSE_OVER, tween);
}
public function tween(e:MouseEvent):void {
removeEventListener(MouseEvent.MOUSE_OVER, tween);
TweenLite.to(textbox, 1, { y:340, onComplete:reverse } );
}
private function reverse():void {
TweenLite.to(textbox, 1, { y:0, onComplete:tweenComplete } );
}
private function tweenComplete():void {
addEventListener(MouseEvent.MOUSE_OVER, tween);
}
}

Correct method of incorporating Starling with Preloader

Hi would like to know the best method of adding a preloader. Then when the content is loaded create an instance of Starling framework. Here is what I have:
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import loaders.Preloader;
import starling.core.Starling;
//main class container
public class Game extends Sprite
{
//preloader class
private var _loader:Preloader;
//starling instance
private var _starling:Starling;
//constructor to initialise game
public function Game():void
{
this.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage)
}
private function onAddedToStage(e:Event):void
{
this.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
_loader = new Preloader();
addChild(_loader);
_loader.addEventListener("loaded_game", onGameLoaded);
}
private function onGameLoaded(e:Event):void
{
trace("game loaded");
_starling = new Starling(Game,stage,null,null,"auto","baseline");
_starling.start();
}
}
This is the Preloader class:
package loaders
{
import flash.events.Event;
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
public class Preloader extends Sprite
{
private var textLoaded:TextField;
public function Preloader()
{
this.addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}
private function onAddedToStage(event:Event):void
{
// remove added to stage listener
this.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
textLoaded = new TextField();
textLoaded.x = 300;
textLoaded.y = 300;
textLoaded.border = true;
textLoaded.autoSize = "center";
addChild(textLoaded);
//loop current load state
this.addEventListener(Event.ENTER_FRAME, loadGame);
this.addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
}
private function onRemovedFromStage(event:Event):void {
this.removeEventListener(Event.ENTER_FRAME, loadGame);
this.removeEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
}
private function loadGame(e:Event):void
{
//vars
var total:Number = parent.stage.loaderInfo.bytesTotal;
var loaded:Number = parent.stage.loaderInfo.bytesLoaded;
textLoaded.text = Math.floor((loaded/total)* 100) + "%";
if (total == loaded)
{
this.removeEventListener(Event.ENTER_FRAME, loadGame);
dispatchEvent(new Event("loaded_game", true));
}
}
}//end of class
}
Is this the best way of doing it or is there a more efficient, practical option? As you can see I am making use of Flash classes before I instantiate Starling? The Preloader is simply a textfield listing what is loaded, this should allow the application to load up faster.
Don't you think that it would make more sense to create an external SWF that preloads your game? It is always a better solution than incorporating a preloader into your main game file.

AS3 Preloader Timing

I did the following
package classes
{
// imports removed
public class Main extends MovieClip {
// vars removed
public function Main():void {
trace('--> Main Function started ...');
/**************************************
Preloader
**************************************/
var preLoader:PreLoader = new PreLoader(); // init
stage.addChild(preLoader); // to Stage
stage.loaderInfo.addEventListener(ProgressEvent.PROGRESS, preLoader.preloaderProgress); // calling the function
doThis();
}
}
With the PreLoader Class looking like this:
package classes {
// imports removed
public class PreLoader extends MovieClip {
public var totalBytes:uint;
public var loadedBytes:uint;
public function PreLoader() {
trace('--> PRELOADER Started ...');
this.addEventListener(Event.ADDED_TO_STAGE, addedHandler);
this.loaderBar.scaleX = 0;
}
private function addedHandler(e:Event):void {
trace('Adding Preloader ...');
totalBytes = this.stage.loaderInfo.bytesTotal;
trace('PL: Total ' + totalBytes + ' / ' + loadedBytes);
this.removeEventListener(Event.ADDED_TO_STAGE, addedHandler);
preloaderProgress(e);
}
public function preloaderProgress(e:Event):void {
trace('Progress...');
loadedBytes = this.stage.loaderInfo.bytesLoaded;
this.loaderBar.scaleX = loadedBytes / totalBytes;
this.loaderBar.alpha = 1 - this.loaderBar.scaleX;
if (totalBytes == loadedBytes) {
trace('Removing PreLoader ...');
this.parent.removeChild(this);
}
}
}
}
The Problem: The Preloader is not displayed BEFORE the inital SWF-file has finished loading. Even all the tracing outputs start when the main movie is finished - i did some profiling on 'slow connections'.
If you wonder: doThis() is loading data from a xml-file, from here everything is fine, tracing outputs are at the right time (but too late at all :D)
Thank you in advance!
Edit: Maybe the question is: Is there a way to determine when the main movie is starting to load?
Make sure that you don't have any content other than the preloader on stage in the first frame. Otherwise all that content will have to load before the preloader starts up.
If you are working in FlashIDE you have to put your preloader into the first frame. If you prefer to use another IDE you should use Frame metatag. Example:
Main.as
package com.sample.preloader
{
import flash.display.Sprite;
import flash.events.Event;
/**
* ...
* #author Author
*/
[Frame(factoryClass="com.sample.preloader.Preloader")]
public class Main extends Sprite
{
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
}
}
}
Preloader.as
package com.sample.preloader
{
import flash.display.DisplayObject;
import flash.display.MovieClip;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.utils.getDefinitionByName;
/**
* ...
* #author Author
*/
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);
// TODO show loader
}
private function ioError(e:IOErrorEvent):void
{
trace(e.text);
}
private function progress(e:ProgressEvent):void
{
// TODO update loader
}
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);
// TODO hide loader
startup();
}
private function startup():void
{
var mainClass:Class = getDefinitionByName("com.sample.preloader.Main") as Class;
addChild(new mainClass() as DisplayObject);
}
}
}