Choose your own Tween Library
to decouple Tweener from the LayoutManager pass tweens in functions to the action sequence like :
myActionSequence.push(function():void
{
LayoutManager.addChild(mc);
TweenLite.to( mc, 0.1, {alpha:1});
});you could accomplish this with a sequence function but anonymous functions get swept by garbage collection once they are done and lost reference.
Author: Jovan Alleyne
GLOBAL PACKAGES
Commonly we have layout elements that are global, such as logos and homescreen buttons. we may transfer them from state to state to allow garbage collection, which is a pain.
to get around that here is one solution that should work in most cases.
Define your display object:
package com.companyName.clientName.states
{
import flash.display.Sprite;
public var packageElement : Sprite = new Sprite( );
}Define your event handler method:
package com.companyName.clientName.projectName.states
{
import org.hive.managers.StateManager;
import flash.events.MouseEvent;
public function packageHandler( e:MouseEvent ):void
{
StateManager.switchState( new CustomState( ), e );
}
}setup your listeners once probably inside a conditional:
import org.hive.states.packageElement;
import org.hive.states.packageHandler;
packageElement.addEventListener( MouseEvent.CLICK, packageHandler );
Note: .as class files should be named the same as the property or method and can only implement one property or method per file.
Author: Jovan Alleyne
GOPHR Webservice
If you are working with .NET WSDL and need a library to handle soap, look no further than Carlo's gophr library. It does all the heavy lifting by pulling down the wsdl, exposing the web methods, and sending/receiving the soap requests. He even provides a class to completely remove the xml namespaces and turn them in straight up xml.
I've used this library a few times now and added it to 0.2 release of Hive where I've added some modifications including deeper error handling and the ability to add a soap authentication header. In my project, I like to take his Webservice class and extend to ProjectNameWebserivce with a WebService instance called "ws" and include the following method for setup:
public function createConnection( includeHeader:Boolean = false, headerNodeObjArray:Array = null ):void
{
ws = new WebService();
if ( includeHeader ) WebService(ws).setHeader( headerNodeObjArray );
ws.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler, true);
ws.addEventListener(Event.CONNECT, campaignConnectHandler);
ws.connect(_wsdlPath, true);
ws.addEventListener(WebServiceErrorEvent.EVENT_WSDL_ERROR, wsdlErrorHandler, false, 0, true);
ws.cacheResults = true;
}
I've also provided a class in the xml folder that works with (instead of nuking) the soap namespaces, and turns it into an array of objects. You may need to examine your raw response and the xmlns to tweak it accordingly.
If you find that you have to hit a webservice multiple times and it fails to return a result, try setting that cacheResults to false.
This library has been tested against .NET 3.5 with great results.
author: brandon flowers
TYPE CONVERSION
Its been a constant thing we have had to do since day 1 of developing in AS3. Example events have a target property which is typed as a base class of DisplayObject. Now lets say your target object is actually a custom type like MyCustomImage which extends Sprite and has a custom property imageTitle.
calling event.target.imageTitle would throw a compiler error reporting the property might be undefined.
a common way to get around this is to use (event.target as MyCustomImage).imageTitle, the limitation with that is your IDE does not understand the type conversion thus code hinting does not function. To work around this and even just to be a bit more elegant this syntax accomplishes the same MyCustomImage(event.target).imageTitle.
Note: with both methods be sure that the class you are trying to convert an object to is part of that objects prototype chain or a null result will be returned in either case and you will throw a runtime error.
Author: Jovan Alleyne
USING TWEENER WITH SEQUENCER
This demonstrates how to set the state of a new movieclip and then pass it into an action sequence called "showPreloader" and use the tweener object to animate it.
Sample:
preloader_mc = new Preloader( infoObject );
preloader_mc.x = 250;
preloader_mc.y = 250;
preloader_mc.scaleX = 0;
preloader_mc.scaleY = 0;
preloader_mc.rotation = 90;
preloader_mc.alpha = 0;
showPreloader.push({scope:preloader_mc, time:1, transition:"linear", scaleX : 1, scaleY: 1, alpha:1});
showPreloader.push({scope:preloader_mc, time:2, rotation:0, transition:"easeOutExpo" });
showPreloader.push({scope:preloader_mc, time:2, transition:"easeOutExpo", x : 600 });
StateManager.playSequence( showPreloader );In the above sequence, all those objects are fired at the same time. If you want to stack them, and have them fire one after another use: showPreloader.push(new SequenceDelay(2000)); between each object like so:
showPreloader.push({scope:preloader_mc, time:2, transition:"linear", scaleX : 1, scaleY: 1, alpha:1, x: preloaderCenterX, y: preloaderCenterY});
showPreloader.push(new SequenceDelay(2000));
showPreloader.push({scope:preloader_mc, time:1, transition:"easeOutExpo" });
showPreloader.push(new SequenceDelay(2000));
showPreloader.push({scope:preloader_mc, time:2, transition:"easeOutExpo", rotation:0 });Author:Brandon Flowers
USE LOADMANAGER TO CREATE A BUTTON WITH ROLLOVER AND ROLLOUT
private var animal_mc:MovieClip = new MovieClip();
private function setupButton():void
{
animal_mc.buttonMode = true;
animal_mc.addEventListener(MouseEvent.ROLL_OVER, buttonRollOverHander);
animal_mc.addEventListener(MouseEvent.ROLL_OUT, buttonRollOutHander);
var animalRollOver:MovieClip = new MovieClip();
var animalRollOut:MovieClip = new MovieClip();
animalRollOver.name = "animalRollOver";
animalRollOut.name = "animalRollOut";
animal_mc.addChild( LoadManager.getLoaderByName('navAnimalRollOver'));
animal_mc.addChild( LoadManager.getLoaderByName('navAnimalRollOut'));
animal_mc.getChildByName("animalRollOver").visible = false;
animal_mc.getChildByName("animalRollOut").visible = true;
}Author:Brandon Flowers
FINDING STAGE HEIGHT AND WIDTH FROM WITHIN ANY CLASS IN YOUR APPLICATION
var stageHeight = StateManager.layoutManager.stageHeight;
var stageWidth = StateManager.layoutManager.stageWidth;
READING FLASH VARS
If you're looking for a flashvar named "location" to can access it like so:
LayoutManager.stage.root.loaderInfo.parameters.location
you can also cycle through the parameters to find other FlashVars
Author: Brandon Flowers
CHECKING A SEQUENCE
You can find out if a current sequence is playing by checking the sequencer on the StateManager like so:
private function acceptHandler(e:Event){
if ( StateManager.sequencer.currentSequence.name != "mySequenceName" )
playNextSequence();
}
}This will play the next sequence once and not play it again if the user quickly clicks on the accept button.
STATE CLOSE METHOD
To make an object eligible for garbage collection all external references to that object and its properties must be removed ( set to null ). Or otherwise determined by the FP9 mark and sweep method of garbage collection.
As with the public override create( ):ActionSequence method, there is a similar way to close a sequence. And as you may expect its called the close method public override close( ):CloseSequence.
This method differs in that is must return a CloseSequence or null. A CloseSequence extends ActionSequence but does not give access to the state related events and properties such as nextState.
public override function close( ):CloseSequence
{
layoutManager.removeChild( displayObject );
var closeSequence:CloseSequence = new CloseSequence( 'testCloseSequence' );
closeSequence.push( {scope: displayObject2, time:1, alpha:0, onComplete:layoutManager.removeChild, onCompleteParams:[displayObject2] );
return closeSequence;
}
Author: Jovan Alleyne
REMOVING DISPLAY OBJECTS USING A SEQUENCE
at the end of your sequence, you can easily remove display objects through the layoutManager on the onComplete event like so:
mySequence.push({scope:my_mc, time:1, alpha:0, transition:"linear", onComplete:layoutManager.removeChild, onCompleteParams:[my_mc]});Author:Brandon Flowers
LOAD AN IMAGE AND APPLY BITMAP SMOOTHING VIA AN ANONYMOUS FUNCTION
private function loadPhoto(photoPath:String, ldrName:String):void
{
var ldr:Loader = new Loader();
var urlReq:URLRequest = new URLRequest(photoPath);
ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, addLoader(ldr) );
ldr.load(urlReq);
}
private function addLoader(ldr:Loader ):Function
{
return function(e:Event)
{
var bmp:Bitmap = new Bitmap( Bitmap(ldr.content).bitmapData, "auto", true);
var mc:MovieClip = new MovieClip();
mc.addChild(bmp);
addChild(mc);
}
}
APPLY BITMAP SMOOTHING TO IMAGES ALREADY LOADED INTO LOADMANAGER
myImageHolder.addChild( new Bitmap( LoadManager.getLoaderByName('myImageId').content.bitmapData, "auto", true));Author:Brandon Flowers
ON ENTER FRAME EVENT
If you want an individual state to listen to an enterframe event, you can add an event listener to your Main class and dispatch the enterframe event through the StateManager so that each state could listen to that event.
example:
// Main.as
private function init()
{
trace ("Main / init()");
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(e:Event):void
{
StateManager.layoutManager.dispatchEvent(new Event("MAIN_ENTER_FRAME"));
} // State.as
private function catchEnterframe()
{
this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
StateManager.layoutManager.addEventListener("MAIN_ENTER_FRAME", onEnterFrame);
}
private function onEnterFrame(e:Event)
{
//trace ("running");
}Author:Brandon Flowers
USING THE SAME GRAPHIC FOR MULTIPLE SPRITES THROUGH LOADMANAGER
If you want to use the same bitmap graphic for multiple sprites, you need to make sure that each bitmap has a unique label. In the below example, I use a loaderSet and loadManager to load 1 schoolyard graphic and 8 snowballs with unique names that each point to the same graphic.
// LoadingState.as
var mySchool:Yard = new Yard("kinglear", 100, 200);
var snowballFightGraphicNameArray:Array = new Array();
snowballFightGraphicNameArray.push(mySchool);
for (var snowballCounter:uint; snowballCounter< snowballCounter; snowballCounter++)
{
var snowballName:String = "snowball" + snowballCounter;
var snowballPath:String = "images/objects/" + fightList[0].@folder.toString() + "/" + snowballList[0].@imagepath.toString();
loadManager.add( new LoaderData( snowballName, snowballPath) );
//
snowballFightGraphicNameArray.push(snowballName);
}
var snowballFightLoaderSet:LoaderSet = new LoaderSet("snowballFightLoaderSet", 10, snowballFightGraphicNameArray);
}
snowballLoadSequence.push(snowballFightLoaderSet);
So that when I want to show the snowballs in the fight state, I can grab those graphics like so:
// FightState.as
for (var snowballCounter:uint=0; snowballCounter< totalSnowballs; snowballCounter++)
{
var snowball:SnowballSprite = new SnowballSprite (loadManager.getLoaderByName("snowball" + snowballCounter).contentLoaderInfo.content,
contentList.getObjectProp("snowball", "decreasehealthby"),
);
snowball.x = Math.floor(Math.random() * 400 - 100);
snowball.y = Math.floor(Math.random() * 100);
snowball.alpha = 0;
snowball.vx = Math.random() * 20 - 1;
snowball.vy = Math.random() * 20 - 1;
snowballArray.push(snowball);
fightSetupSequence.push({scope:snowballArray[snowballCounter], alpha:1, time:1, transition:"linear"} );
}
Author:Brandon Flowers