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.
Related
I am sure this is an easy one. I have one Main.as class calling a another class that is loading a StageWebView. If called by itself the StageWebView works fine, but when I call it from another class it will not display. What simple thing am I forgetting?
Perhaps it has something to do with the "stage" in the loaded class?
Main.as
public function addPopeNews()
{
thePopeNews = new popeNews();
addChild(thePopeNews);
}
PopeNews.as
package com
{
import flash.display.MovieClip;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.*;
import flash.net.URLRequest;
import flash.media.StageWebView;
import flash.geom.Rectangle;
public class popeNews extends MovieClip
{
public var backBar:popeNewsBar;
public var webView:StageWebView;
public function popeNews()
{
webView=new StageWebView();
webView.stage = this.stage;
webView.loadURL("www.myUrl.com");
trace("POPE NEWS!!!"); /// trace works!
backBar = new popeNewsBar();
backBar.width = Main._screenX;
backBar.scaleY = backBar.scaleX;
webView.addEventListener(Event.COMPLETE, webLoaded);
webView.addEventListener(LocationChangeEvent.LOCATION_CHANGING,onChanging);
}
public function webLoaded(e:Event)
{
trace("web loaded"); // trace works!!
if (webView.isHistoryBackEnabled)
{
addChild(backBar);
backBar.bb.addEventListener(MouseEvent.CLICK, goBack);
webView.viewPort = new Rectangle(0,backBar.height,Main._screenX,Main._screenY - backBar.height);
}
else
{
webView.viewPort = new Rectangle(0,0,Main._screenX,Main._screenY);
}
}
public function goBack(e:Event)
{
if (webView.isHistoryBackEnabled)
{
trace("Called GO BACK");
webView.historyBack();
removeChild(backBar);
backBar.bb.removeEventListener(MouseEvent.CLICK, goBack);
return;
}
if (webView.isHistoryForwardEnabled)
{
webView.historyForward();
return;
}
}
public function onError(e:ErrorEvent):void
{
//infoBox.text="Page is not available. Try reloading.";
}
public function onChanging(e:LocationChangeEvent):void
{
//webView.viewPort = null;
trace("Called CHANGING!!!");
}
///
}
}
You are right, the stage is null in the PopeNews constructor. You should put your initialization code into a new method, and listen for the ADDED_TO_STAGE event.
public function popeNews()
{
addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
}
private function addedToStageHandler(ev:Event):void
{
webView=new StageWebView();
webView.stage = this.stage;
webView.loadURL("www.myUrl.com");
trace("POPE NEWS!!!"); /// trace works!
backBar = new popeNewsBar();
backBar.width = Main._screenX;
backBar.scaleY = backBar.scaleX;
webView.addEventListener(Event.COMPLETE, webLoaded);
webView.addEventListener(LocationChangeEvent.LOCATION_CHANGING,onChanging);
}
Also, by convention class names are capitalized.
i am making a simple game. here is the problem i am facing, but first i will tell you my class structure.
(i am using flash cs5.5)
Enemy.as : this class is linked with a MovieClip(in library), having code of simple enemy movment and directions.
Hero.as : Linked with a MovieClip in library. Code of Hero simple Movment
EnemyManager.as : Creates new enemy Every 20 Second.
HeroManager.as : Creates Hero(Only Once, other functionality will be added later).
HittingManager.as : checks for collusions(Problem Here)
Now My Problem is in HittingManager.as class because i want to add HitTestObject Functionalty in this class. i will post code of 3 important classes. (EnemyManager.as, HeroManager.as, HittingManager.as )
package
{
import flash.display.MovieClip;
import flash.events.Event;
public class HeroManager extends MovieClip
{
private var hManager:HittingManager = new HittingManager();
public static var hero:Hero = new Hero();
public function HeroManager()
{
addEventListener(Event.ADDED_TO_STAGE, added);
}
private function added(event:Event):void
{
trace("hero manager added");
}
}//class
}//package
Here is the code of EnemyManager.as class
package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.sampler.Sample;
import flash.display.Sprite;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.sampler.NewObjectSample;
public class EnemyManager extends MovieClip
{
private var hManager:HittingManager = new HittingManager();
private var timer:Timer = new Timer(2000);
public static var hitting:Boolean = false;
public static var enemy:Enemy;
public function EnemyManager()
{
addEventListener(Event.ADDED_TO_STAGE, added);
}
public function addEnemy(newEnemy:Enemy):void
{
addChild(newEnemy);
hManager.registerEnemy(newEnemy);
}
private function added(event:Event):void
{
addEventListener(Event.ENTER_FRAME, update);
trace("added enemy manger");
timer.addEventListener(TimerEvent.TIMER, onTimer);
timer.start();
}
private function onTimer(event:TimerEvent):void
{
enemy = new Enemy();
this.addEnemy(enemy);
}
private function update(event:Event):void
{
}
}
}
And here Hittest.as class (i have tried many techniqes but all in vain ) so i am leaving if statment empty
package
{
import flash.display.MovieClip;
import flash.events.Event;
public class HittingManager extends MovieClip
{
private var eManager:EnemyManager;
private var hEnemy:Enemy = new Enemy();
private var _enemies:Array;
private var _hero:Hero;
public function HittingManager()
{
//trace("Hitting Manager working");
_enemies = [];
addEventListener(Event.ADDED_TO_STAGE, added);
}
public function registerEnemy(newEnemy:Enemy):void
{
_enemies.push(newEnemy);
}
public function registerHero():void
{
//trace("heroRegisterd");
_hero = HeroManager.hero;
addChild(_hero);
}
private function added(event:Event):void
{
if(!_hero)
{
this.registerHero();
}
trace("Hitting manger added");
addEventListener(Event.ENTER_FRAME, update);
}
private function update(event:Event):void
{
if(_hero)
{
for each( newEnemy:Enemy in _enemies)
{
if(_hero.hitTestObject(newEnemy) )
{
trace("Hitting")
}
}
}
}
}//class
}//package
The revision below gets your code working with as few changes as possible, however it is in no way an ideal solution.
You should probably refactor your code so that the enemy manager doesn't need a public static reference to the HittingManager
package
{
import flash.display.MovieClip;
import flash.events.Event;
public class HeroManager extends MovieClip
{
public static var hero:Hero = new Hero();
public function HeroManager()
{
addEventListener(Event.ADDED_TO_STAGE, added);
}
private function added(event:Event):void
{
trace("hero manager added");
}
} //class
} //package
package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.sampler.Sample;
import flash.display.Sprite;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.sampler.NewObjectSample;
public class EnemyManager extends MovieClip
{
public static var hManager:HittingManager;
private var timer:Timer = new Timer(2000);
public static var hitting:Boolean = false;
public static var enemy:Enemy;
public function EnemyManager()
{
addEventListener(Event.ADDED_TO_STAGE, added);
}
public function addEnemy(newEnemy:Enemy):void
{
addChild(newEnemy);
hManager.registerEnemy(newEnemy);
}
private function added(event:Event):void
{
addEventListener(Event.ENTER_FRAME, update);
trace("added enemy manger");
timer.addEventListener(TimerEvent.TIMER, onTimer);
timer.start();
}
private function onTimer(event:TimerEvent):void
{
enemy = new Enemy();
this.addEnemy(enemy);
}
private function update(event:Event):void
{
}
}
}
package
{
import flash.display.MovieClip;
import flash.events.Event;
public class HittingManager extends MovieClip
{
private var _enemies:Array;
private var _hero:Hero;
public function HittingManager()
{
//trace("Hitting Manager working");
_enemies = [];
addEventListener(Event.ADDED_TO_STAGE, added);
}
public function registerEnemy(newEnemy:Enemy):void
{
_enemies.push(newEnemy);
}
public function registerHero():void
{
//trace("heroRegisterd");
_hero = HeroManager.hero;
addChild(_hero);
}
private function added(event:Event):void
{
if (!_hero)
{
this.registerHero();
}
trace("Hitting manger added");
addEventListener(Event.ENTER_FRAME, update);
}
private function update(event:Event):void
{
if (_hero)
{
for each (var newEnemy:Enemy in _enemies)
{
if (_hero.hitTestObject(newEnemy))
{
trace("Hitting")
}
}
}
}
} //class
} //package
In your main document class, you should have something like:
var hittingManager:HittingManager = new HittingManager();
EnemyManager.hManager = hittingManager;
var enemyManager:EnemyManager = new EnemyManager();
var heroManager:HeroManager = new HeroManager();
addChild(heroManager);
addChild(enemyManager);
addChild(hittingManager);
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);
}
}
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);
}
}
}
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.