O technologii i biznesie naszym zdaniem
Posts tagged flash
Actionscript i tworzenie bibliotek zasobów
lutego 4th
Nie trudno wyobrazić sobie sytuację, kiedy w naszej aplikacji Flash/Flex chcielibyśmy wyprowadzić pewne zasoby na zewnątrz programu w celu łatwej ich podmiany/update. Przykładem może być np. pole w naszej nowej super grze, lub sprite przeciwnika z tej samej mega produkcji. Taki element programu będzie opisywany zarówno przez jego wizualna reprezentację jak i przez zestaw parametrów.
W naszej aplikacji nie chcemy znać definicji tych obiektów, chcemy załadować kontener swf zawierający taki obiekt do głównej aplikacji i uzyskać dostęp do zasobów. Do dzieła!
Nasza prosta aplikacja będzie miała za zadanie wzywanie bohaterów którzy uratują świat przed nieuniknioną zagładą. Przygotujmy interface dla takiego bohatera:
package pl.espeo.hero
{
import flash.display.Bitmap;
public interface IHero
{
function getName():String;
function getImage():Bitmap;
}
}
Jak widać jedyne co nasz bohater będzie potrafił to powiedzieć jak się nazywa i dać nam swoją pamiątkową fotografię. Dodajmy klasę po której nasi poszczególni bohaterowie będą dziedziczyć:
package pl.espeo.hero
{
import flash.display.Bitmap;
import flash.display.Sprite;
public class SuperHero extends implements IHero
{
protected var heroName:String;
protected var heroImage:Bitmap;
public function SuperHero(heroName:String, heroImage:Bitmap)
{
super();
this.heroName = heroName;
this.heroImage = heroImage;
}
public function getName():String
{
return heroName;
}
public function getImage():Bitmap
{
return heroImage;
}
}
}
Czas przedstawić naszych zbawców. Pierwszy z nich to nikt inny jak Rambo:
package
{
import pl.espeo.hero.SuperHero;
public class Hero extends SuperHero
{
[Embed(source="assets/rambo.jpg")]
private var EmbedImage:Class;
public function Hero()
{
super('Rambo', new EmbedImage());
}
}
}
Tak przygotowanego bohatera kompilujemy do pliku swf. To samo robimy z naszym następnym bohaterem, Kapitanem Planetą:
package
{
import pl.espeo.hero.SuperHero;
public class Hero extends SuperHero
{
[Embed(source="assets/captain_planet.jpg")]
private var EmbedImage:Class;
public function Hero()
{
super('Captain Planet', new EmbedImage());
}
}
}
Mamy więc naszych bohaterów, czas przygotować dla nich podium oraz opracować sposób komunikacji z nimi. Aby nasza komunikacja przebiegała poprawnie, oraz aby nie przywołać zwykłego śmiertelnika w naszej aplikacji będziemy potrzebowali interfacu pl.espeo.hero.IHero. Czas przygotować formę komunikacji z naszym bohaterem:
package pl.espeo.hero
{
import flash.display.Loader;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.net.URLRequest;
public class HeroSummoner extends EventDispatcher
{
public static const CAPTAIN_PLANET:String = 'CaptainPlanet';
public static const RAMBO:String = 'Rambo';
private var loader:Loader = new Loader();
public function HeroSummoner()
{
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderCompleteEventHandler);
}
public function callHero(heroName:String):void
{
loader.load(new URLRequest('assets/' + heroName + '.swf'));
}
private function loaderCompleteEventHandler(event:Event):void
{
var Hero:Class = event.target.applicationDomain.getDefinition('Hero') as Class;
var heroEvent:HeroEvent = new HeroEvent(HeroEvent.SUMMONED);
heroEvent.hero = new Hero();
dispatchEvent(heroEvent);
}
}
}
dzięki tak przygotowanej klasie, zostaniemy poinformowani eventem HeroEvent że nasz bohater jest już na miejscu.
package pl.espeo.hero
{
import flash.events.Event;
public class HeroEvent extends Event
{
public static const SUMMONED:String = 'pl.espeo.hero.HeroEventSummoned';
public var hero:IHero;
public function HeroEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
}
}
Tak może to wyglądać w aplikacji flex:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="init()">
<mx:Script>
<![CDATA[
import pl.espeo.hero.HeroEvent;
import pl.espeo.hero.HeroSummoner;
import mx.collections.ArrayCollection;
import pl.espeo.hero.IHero;
public static const NO_HERO:uint = 0;
[Bindable]
private var heroes:ArrayCollection = new ArrayCollection([{label:'There is no hero!', data:NO_HERO},
{label:'First hero', data:HeroSummoner.CAPTAIN_PLANET},
{label:'Second hero', data:HeroSummoner.RAMBO}]);
private var heroSummoner:HeroSummoner = new HeroSummoner();
private function init():void
{
heroSummoner.addEventListener(HeroEvent.SUMMONED, welcomeMyHero);
}
private function summonHero(event:Event):void
{
var hero:* = ComboBox(event.target).selectedItem.data;
if (hero == NO_HERO)
{
return;
}
heroSummoner.callHero(hero);
}
private function welcomeMyHero(event:HeroEvent):void
{
heroPanel.status = event.hero.getName();
heroImage.source = event.hero.getImage();
}
]]>
</mx:Script>
<mx:HBox>
<mx: Panel id="heroPanel" x="10" y="10" width="400" height="400" layout="absolute">
<mx:Image id="heroImage" x="0" y="0"></mx:Image>
</mx: Panel>
<mx:ComboBox id="heroesList" dataProvider="{heroes}" change="{summonHero(event)}"/>
</mx:HBox>
</mx:Application>
Dzięki tak przygotowanym obiektom możemy zbudować elastyczny system z zasobami zamkniętymi w łatwych do podmiany plikach. Dodając do tego prosty program narzędziowy wykorzystujący kompilator mxmlc możemy stworzyć furtkę, dzięki której przygotowanie kolejnych elementów nie będzie wymagało ingerencji programisty.