Bouw een efficiënt Flash DecalSheet-systeem

Ik kwam met het idee om wat ik Flash DecalSheets noem, te maken van de stickers die bij modelvliegtuigen horen en heb sindsdien "Decals" gebruikt om mijn eigen Flash-applicaties te villen. Een DecalSheet is in feite één grote afbeelding (.JPG, .PNG of .GIF) die wordt opgedeeld in kleinere afbeeldingen, 'Decals' genaamd, dit zijn Bitmaps en kunnen overal worden gebruikt waar DisplayObjects meestal worden gebruikt.

Deze techniek is een van de meest efficiënte manieren om veel items in een Flash-toepassing te plaatsen zonder te vertrouwen op de bibliotheek (als u de Flash IDE gebruikt) of de inslabcode (als u de Flex-compilatie gebruikt). Laten we eens kijken hoe we een eenvoudig DecalSheet-systeem kunnen maken.

Met DecalSheets kunt u de geheugenvoet van uw toepassing verkleinen door kleinere afbeeldingen te consolideren tot grotere afbeeldingen. Elke afbeelding die u zou insluiten in een klas of in een FLA-bibliotheek, kan worden opgeslagen in één DecalSheet of ze kunnen worden verspreid over meerdere DecalSheets, afhankelijk van uw behoeften. Aangezien DecalSheets zodanig kan worden ingesteld dat het alleen wordt geladen wanneer het wordt aangevraagd, kunt u de grafische afbeeldingen van toepassingen precies laden wanneer u ze nodig hebt, waardoor de eerste opstarttijd en laadtijd korter worden. Ten slotte kun je je hele applicatie hersluiten door eenvoudig de BitmapData van je DecalSheets tijdens runtime te veranderen.

Dit diagram illustreert hoe we een enkele DecalSheet-afbeelding nemen en coördinaten gebruiken om een ​​nieuwe sticker uit te snijden.

In deze tutorial gaan we 2 klassen maken: de DecalSheet en het Decal. U definieert X-, Y-, Breedte- en Hoogtecoördinaten om afbeeldingen uit het DecalSheet te verwijderen en geeft Decals weer. Overdrukplaatjes zijn bitmaps en kunnen overal worden gebruikt waar DisplayObjects normaal gesproken wordt gebruikt. Wat Decals speciaal maakt, is dat ze een verwijzing behouden naar het DecalSheet waar ze uitgehaald worden. Wanneer u de BitmapData van de DecalSheet bijwerkt, worden alle Decals die uit dat blad zijn uitgeknipt ook bijgewerkt. Dit stelt u in staat om een ​​hele applicatie tijdens runtime opnieuw te hullen door simpelweg nieuwe bronafbeeldingen in te laden.

Het volgende voorbeeld toont onze bron DecalSheet aan de linkerkant en een SimpleButton aan de rechterkant met behulp van stickers voor elke knopstatus. Wanneer u op de knop klikt, wordt een nieuwe afbeelding geladen en vervangen de Bitmap-gegevens de originele skin in de DecalSheet. Alle stickers in de eenvoudige knop worden ook bijgewerkt. Het opnieuw villen is bijna onmiddellijk!

Aan het einde van de zelfstudie hebt u het volgende .SWF:

Bronplaatafbeeldingen voor stickers

Voordat we aan de slag gaan, moet je ervoor zorgen dat je de volgende twee afbeeldingen hebt. Dit zullen onze DecalSheet-bronnen zijn die we zullen gebruiken om knoptoestanden uit te knippen.


button_skin_a.png
button_skin_b.png

Stap 1: De Doc Class instellen

Het eerste dat we gaan doen, is onze hoofdcodeklasse maken. Ik heb al een eenvoudige klasse ingesteld die in een afbeelding wordt geladen en aan de weergavelijst wordt toegevoegd.

 pakket import flash.display.Bitmap; import flash.display.Loader; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageScaleMode; import flash.events.Event; import flash.net.URLRequest; public class DeaclSheetTutorial breidt Sprite uit private var loader: Loader; publieke functie DeaclSheetTutorial () configureStage (); loadDecalSheetSource ( "images / button_skin_a.png");  private function configureStage (): void stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE;  public function loadDecalSheetSource (url: String): void loader = new Loader (); loader.contentLoaderInfo.addEventListener (Event.COMPLETE, onImageLoad); loader.load (nieuwe URLRequest (url));  private function onImageLoad (event: Event): void loader.removeEventListener (Event.COMPLETE, onImageLoad); var bitmap: Bitmap = Bitmap (loader.content); addChild (bitmap); 

Wanneer u deze klasse uitvoert, zou u onze moeten zien button_skin_a.png wordt weergegeven op het podium. Nu zijn we klaar om te beginnen met het maken van onze DecalSheet.

Stap 2: De klasse DecalSheet maken

Het DecalSheet breidt de bitmapklasse uit. Ik heb mijn lessen opgezet in "com.flashartofwar" -pakketten, maar je bent vrij om ze in te stellen zoals je wilt. Maak een nieuwe klasse met de naam DecalSheet en plak in de volgende code:

package com.flashartofwar import flash.display.BitmapData; import flash.display.Bitmap; public class DecalSheet breidt Bitmap uit public function DecalSheet (bitmapData: BitmapData = null, pixelSnapping: String = "auto", smoothing: Boolean = false) super (bitmapData, pixelSnapping, smoothing); 

Stap 3: Het DecalSheet testen

Nu we ons DecalSheet hebben gemaakt, laten we ervoor zorgen dat het afbeeldingen kan weergeven. We gaan dit doen door de BitmapData van de .png die we eerder hebben geladen door te geven. Ga terug naar de Doc-klasse en vervang lijn 40, waarbij we addChild noemen, met het volgende:

decalSheet = new DecalSheet (bitmap.bitmapData); addChild (decalsheet);

We gaan ook de klasse DecalSheet importeren op regel 3:

import com.flashartofwar.DecalSheet;

Evenals het instellen van een variabele om ons DecalSheet op regel 16 op te slaan:

private var decalSheet: DecalSheet;

Wanneer u nu compileert, ziet u dezelfde afbeelding, maar nu bevindt deze zich in de DecalSheet. Laten we het hebben over hoe we deze afbeeldingen kunnen verwijderen.

Stap 4: Decals opslaan in de DecalSheet

Op dit punt hebben we een eenvoudige klasse DecalSheet die de bitmapklasse uitbreidt. Ons doel is om gebieden van de DecalSheet te definiëren die kunnen worden uitgesneden en omgezet in stickers. Voordat we emblemen kunnen registreren, hebben we een plek nodig om ze op te slaan.

Voeg de volgende eigenschap toe op regel 8:

protected var decalRectangles: Dictionary = new Dictionary (true);

En importeer de Dictonary-klasse op regel 5:

import flash.utils.Dictionary;

Zoals je kunt zien, zal deze Dictonary de plaats zijn waar we de namen van een Decal kunnen associëren met zijn coördinaten.

Stap 5: Decals registreren

In wezen is een sticker eigenlijk gewoon een naam en zijn X-, Y-, breedte- en hoogtewaarden die we gebruiken om BitmapData uit de DecalSheet te verwijderen. We gaan deze informatie registreren met de volgende functie op regel 16.

public function registerDecal (name: String, rectangle: Rectangle): void decalRectangles [name] = rectangle; 

Nu kunt u de uitgesneden coördinaten van een sticker aan een naam en een rechthoek koppelen.

U moet ook de klasse Rectangle importeren op regel 5:

import flash.geom.Rectangle;

Stap 6: DecalSheet-voorbeeldmethode

We gaan de belangrijkste functie toevoegen van de DeaclSheet, de sample () -methode. Deze functie is wat we zullen gebruiken om BitmapData uit de DecalSheet te verwijderen om onze emblemen te maken. Laten we de volgende functie plaatsen op regel 22 van de klasse DecalSheet.

public function sample (name: String): BitmapData var rect: Rectangle = decalRectangles [name]; // Past de juiste offset toe bij het samplen van de gegevens var m: Matrix = nieuwe matrix (); m.translate (-rect.x, -rect.y); // Creëert nieuwe BitmapData var bmd: BitmapData = nieuwe BitmapData (rect.width, rect.height, true, 0xffffff); bmd.draw (bitmapData, m); terugkeer bmd; 

Ook moet u de Matrix Class importeren op regel 5:

import flash.geom.Matrix;

Er is veel gaande in deze functie, dus laten we regel voor regel door het proces gaan.

var rect: Rectangle = decalRectangles [name];

Hier gebruiken we de gepasseerde Decalsaam om de geregistreerde rechthoek op te zoeken uit de decalRectangles Dictonary.

Vervolgens gaan we een matrix maken om te compenseren waar we de BitmapData uitproberen.

var m: Matrix = nieuwe matrix (); m.translate (-rect.x, -rect.y);

Hier gebruiken we de X- en Y-positie van de rechthoek om de juiste voorbeeldoffset te maken.

Nu moeten we een nieuwe BitmapData maken om onze cut-out op te slaan.

var bmd: BitmapData = nieuwe BitmapData (rect.width, rect.height, true, 0xffffff);

Zoals u kunt zien, gebruiken we de breedte en hoogte van de rechthoek als de nieuwe dimensies, stelt u de parameter transparent in op true en geeft u de nieuwe BitmapData een achtergrondkleur van 0xffffff. Door transparant op true in te stellen en een achtergrondkleur te leveren, kunnen we transparante .png-afbeeldingen correct samplen, zoals de "button_skin" -voorbeelden die we laden.

Ten slotte moeten we de DecalSheets BitmapData in de nieuwe instantie BitmapData Class tekenen en de Matrix toepassen.

bmd.draw (bitmapData, m);

Nu hebben we onze samengestelde bitmapData en retourneren we eenvoudig de nieuwe BitmapData-instantie.

Stap 7: De voorbeeldmethode testen

Voordat we verder gaan, willen we een paar eenvoudige dingen doen om onze nieuwe DecalSheet-voorbeeldmethode te testen. Laten we teruggaan naar onze Doc Class en de volgende functie toevoegen op regel 49 na de onImageLoad-methode:

public function registerDecals (): void decalSheet.registerDecal ("up", nieuwe Rectangle (0,0,99,31)); decalSheet.registerDecal ("down", nieuwe Rectangle (0,32,99,31)); decalSheet.registerDecal ("over", nieuwe Rectangle (99,0,99,31)); 

Hier kun je zien dat we elk van de knoptoestanden registreren die we later nodig hebben wanneer we onze SimpleButton maken. U moet de klasse Rectangle op regel 11 importeren:

import flash.geom.Rectangle;

... en het toevoegen van registerDecals op regel 46, in de onImageLoad-functie nadat we de DecalSheet aan het podium hebben toegevoegd.

registerDecals ();

Nu gaan we een laatste functie creëren onderaan onze klas, rond lijn 54:

public function decalSheetDemo (): void var sampleBitmap: Bitmap = new Bitmap (decalSheet.sample ("up")); sampleBitmap.x = 230; addChild (sampleBitmap); 

Deze functie zal ons belangrijkste verzamelgebied zijn voor de rest van de demo. Op dit moment maken we een nieuwe bitmap van de "omhoog" geregistreerde decale coördinaten van de DecalSheet, die zijn x-positie verschuiven en deze aan het stadium toevoegen.

We zullen deze functie aanroepen na de registerDecals-aanroep die we hebben toegevoegd aan de onImageLoad op regel 46:

decalSheetDemo ();

Als we nu een compilatie maken, zouden we onze DecalSheet-afbeelding aan de linkerkant moeten zien en onze gesamplede Bitmap van de DecalSheet aan de rechterkant. U kunt alle stickers uitproberen door "omhoog" te wijzigen voor "omlaag" of "over". Nu hebben we genoeg om onze klasse Decal te starten.

Stap 8: De klasse van de stickers maken

Net als de DecalSheet zal de Decal ook de bitmapklasse uitbreiden. De sticker heeft echter een zeer gespecialiseerd doel en vertrouwt op de DecalSheet om de BitmapData te leveren in plaats van deze door te geven aan de constructor. Maak een nieuwe klasse met de naam Decal en plak in de volgende code:

pakket com.flashartofwar import flash.display.Bitmap; public class Decal breidt Bitmap uit beschermd var decalSheetSrc: DecalSheet; public function Decal (naam: String, src: DecalSheet, pixelSnapping: String = "auto", smoothing: Boolean = false) super (null, pixelSnapping, smoothing); // Bewaar de labelmap. decalSheetSrc = src; // Bewaar de naam van het embleem zodat we het van de DecalSheet kunnen samplen. this.name = naam; // Krijg bitmapgegevens van de DecalSheet src. refresh ();  public function refresh (): void bitmapData = decalSheetSrc.sample (name); 

Dus wat is er aan de hand? Zoals je ziet veranderen we de argumenten van de constructor van de originele BitmapClass's. Ons embleem moet de naam weten (we gebruiken dit om BitmapData op te vragen bij de DecalSheet via de voorbeeldmethode) en we moeten de src DecalSheet weten waarop het Decal is uitgesneden.

Als we het constructieproces doorlopen, geven we nul door aan de eigenschap BitmapData van super, samen met doorgegeven waarden voor pixelMapping en smoothing. Vervolgens slaan we een verwijzing op van de DecalSheet src in de eigenschap deaclSheetSrc. Vervolgens slaan we de doorgegeven naamwaarde op in de eigenschap inherited name uit de BitmapData. We gebruiken "this" om het verschil tussen de gepasseerde parameter en de parameter name van de klasse instantie te onderscheiden. Eindelijk noemen we de verversingsmethode.

De verversingsmethode van de Decal voert een eenvoudige taak uit. Het vraagt ​​nieuwe BitmapData op vanuit zijn bovenliggende DecalSheet en stelt het in. Dit maakt de weergave van de sticker. Het afremmen van de logica om BitmapData aan te vragen van de ouder DecalSheet zal later een belangrijke rol spelen wanneer we beginnen met het wijzigen van de BitampData van de DecalSheet.

Stap 9: Decals retourneren van het DecalSheet

Voordat we kunnen testen of de stickers werken, zullen we de mogelijkheid willen toevoegen om op de DecalSheet decals op naam aan te vragen en een Decal-instantie te laten retourneren. We kunnen dit doen door de volgende functie toe te voegen in de DecalSheet na de methode registerDecal rond regel 21:

openbare functie getDecal (naam: String): Decal return decalRectangles [name]? nieuw embleem (naam, dit): null; 

Nu kunnen we decals aanvragen op de DecalSheet door simpelweg de naam van geregistreerde stickers door te geven. Je zult deze korte hand voorwaardelijk opmerken. Kortom, het eerste item is wat we aan het testen zijn. In dit geval willen we weten of de geleverde naam is geregistreerd bij de decalRectangles Dictonary. De ? geeft aan wat er gebeurt als het bestaat. Hier maken we een nieuwe sticker, geven we dezelfde naam die is doorgegeven aan de getDecal-functie en geven we een verwijzing van de instantie DecalSheet (deze) aan de sticker. De: geeft aan wat er gebeurt als de geleverde naam niet wordt gevonden op de DeacalRectangles Dictonary. We geven simpelweg null terug. Laten we dit testen om te controleren of alles werkt.

Stap 10: Het DecalSheet en het Decal testen

We zijn nu klaar om onze sticker te testen. Hiertoe gaan we terug naar de Doc klasse en vervangen de decalSheetDemo-methode met de volgende code:

public function decalSheetDemo (): void var upDecal: Decal = decalSheet.getDecal ("up"); upDecal.x = 230; addChild (upDecal); 

We zullen de stickerklasse ook moeten importeren op regel 3:

import com.flashartofwar.Decal;

Als u de klasse compileert, ziet u de sticker aan de rechterkant van de DecalSheet-instantie waaruit deze is verwijderd. Wat is het probleem? We hadden hetzelfde 4 stappen geleden met minder code. Laat me uitleggen waarom dit een krachtige manier is om assets naar je Flash-app te brengen.

Stel je voor dat je een fotogalerij hebt. Stel dat u veel sites had die allemaal dezelfde fotogalerij gebruikten, maar dat u elke fotogalerij moest voorzien van een merk op basis van de individuele site waarop deze werd gehost. Afhankelijk van hoe je je fotogalerij maakt, kun je besluiten om een ​​.SWF te maken met elke knop als een item in de bibliotheek met een koppelings-ID. Of u kunt elke afzonderlijke afbeelding één voor één tijdens runtime laden. Lange tijd gebruikte ik beide manieren, maar vond het altijd beperkend om te wachten op één grote .SWF om te laden of veel kleinere afbeeldingen om in te laden totdat ik met het DecalSheet-systeem kwam.

Nu maak ik eenvoudig een DeaclSheet-afbeelding, definieer de coördinaten voor elke knop en ik hoef maar één afbeelding en enkele uitgesneden gegevens te beheren. Meestal plaats ik de uitgesneden coördinaten in een XML-bestand en nu kan ik het afleveren aan een ontwerper die misschien niets over Flash weet, maar eenvoudig een nieuw thema kan maken vanuit een PSD-sjabloon. Ik weet dat dit klinkt als een eenmalig voorbeeld, maar ik gebruik dit systeem in elke Flash-site die ik bouw. We hebben nog niet eens de coolste functie aangeraakt!

Wat gebeurt er als je een applicatie on the fly opnieuw moet villen? U zou alle afbeeldingen opnieuw moeten laden en nieuwe klasseninstanties moeten maken of logica moeten bouwen in uw componenten om de nieuwe activa weer zelf te kunnen opbouwen. Het opnieuw villen van een Flash-app die is gebouwd met stickers is net zo eenvoudig als het wijzigen van de BitmapData van de DeaclSheet. Ik zal je laten zien hoe.

Stap 11: DecalSheet BitmapData wijzigen

We hebben een manier nodig om alle Decals die uit een DecalSheet zijn gesneden, te vertellen dat de BitmapData is gewijzigd en dat ze opnieuw moeten worden gesampled. We kunnen dit eenvoudig doen door de set bitmapData-methode van de DecalSheet te negeren. Voeg de volgende methode toe onder de constructeur van DecalSheet op regel 17:

negeren openbare functieset bitmapData (waarde: BitmapData): void super.bitmapData = waarde; dispatchEvent (nieuw evenement (Event.CHANGE)); 

... samen met een importinstructie voor gebeurtenis op regel 5:

import flash.events.Event;

Nu een nieuwe gebeurtenis wordt verzonden wanneer de BitmapData van de DecalSheet is gewijzigd, moeten we hiernaar luisteren in de klasse Decal.

Stap 12: Luisteren naar DecalSheet-gebeurtenissen

Nu de DecalSheet een wijzigingsgebeurtenis verzendt wanneer de BitmapData is bijgewerkt, kunnen we de Decal laten luisteren naar deze gebeurtenissen en zijn eigen BitmapData opnieuw samplen vanaf de DecalSheet. Laten we de volgende 3 methoden toevoegen in de klasse Decal onder de functie vernieuwen op regel 27:

beschermde functie addListeners (doel: IEventDispatcher): void target.addEventListener (Event.CHANGE, onChange, false, 0, true);  beschermde functie removeListeners (doel: IEventDispatcher): void target.removeEventListener (Event.CHANGE, onChange);  beschermde functie onChange (event: Event): void refresh (); 

We moeten ook de IEventDispatcher- en Event-klassen importeren op regel 4:

import flash.events.Event; import flash.events.IEventDispatcher;

Ten slotte zullen we de luisteraar moeten toepassen op het ouderlijke DecalSheet van de sticker door de volgende code toe te voegen aan het einde van de constructor op regel 23 van de constructor:

addListeners (src);

Voordat we verdergaan, wil ik graag uitleggen waarom ik het toevoegen en verwijderen van gebeurtenislisteners in afzonderlijke functies uit elkaar trek. Wanneer ik lessen maak, probeer ik na te denken over hoe ik ze ga verleggen en ook hoe ik logica kan opsplitsen in de kleinst mogelijke stukken. Deze 3 functies vertegenwoordigen een hoofdkenmerk van de sticker en zijn waarschijnlijk de belangrijkste die we ooit zouden willen wijzigen bij het uitbreiden van deze klasse. Ik probeer ook waar mogelijk Interfaces te gebruiken. Ik leg dit later in meer detail uit. Zoals u kunt zien, kunnen we eenvoudig de listeners van de gebeurtenis wijzigen toevoegen en verwijderen we refresh wanneer de instantie Decal de juiste gebeurtenis hoort. In de volgende stap zullen we onze SimpleButton bouwen en deze nieuwe functionaliteit verkennen.

Stap 13: Een SimpleButton maken

Laten we teruggaan naar de Doc-klasse en een SimpleButton maken met alle stickers die we in de DecalSheet hebben geregistreerd. Opnieuw gaan we de functie decalSheetDemo vervangen door de volgende code:

public function decalSheetDemo (): void var up: Decal = decalSheet.getDecal ("up"); var over: Decal = decalSheet.getDecal ("over"); var down: Decal = decalSheet.getDecal ("down"); var myButton: SimpleButton = nieuwe SimpleButton (omhoog, over, omlaag); myButton.useHandCursor = true; myButton.hitTestState = up; myButton.x = 230; this.addChild (myButton); 

We moeten ook SimpleButton importeren op regel 8:

import flash.display.SimpleButton;

Dus nu zijn we bezig met het instellen van elk van de stickers, het maken van nieuwe SimpleButton-instanties en het doorgeven van de stickers aan de constructor. Omdat de SimpeButton DisplayObjects gebruikt voor elke staat en onze stickers de bitmapklasse uitbreiden, kunnen we onze stickers vervangen overal waar DisplayObjects worden gebruikt. Stel de Doc-klasse samen en bekijk de knop. U zult zien dat de boven- en onderkant van de stickers worden weergegeven wanneer de knop van staat verandert.

Stap 14: De BitmapData van de DecalSheet updaten

Nu gaan we onze tweede knoophuid laden "button_skin_b.png"en vervang de BitmapData van de DecalSheet. Aangezien de emblemen naar de gebeurtenis Change luisteren vanaf de DecalSheet, kunnen we de SimpleButton opnieuw samenvoegen zonder een enkele eigenschap erop te wijzigen.

Dit diagram illustreert hoe we door het veranderen van de BitmapData van de DecalSheet een gebeurtenis kunnen uitzenden naar alle kinder-decals om opnieuw te samplen.

Laten we beginnen door de volgende gebeurtenislistener toe te voegen aan de knop op regel 72 van de Doc Klasse nadat we de knop toevoegen aan de displaylijst:

myButton.addEventListener (MouseEvent.CLICK, onClick);

Zodra dat is ingevoerd, voegen we de volgende drie methoden toe onder de functie decalSheetDemo:

privéfunctie onClick (event: MouseEvent): void loadBlueSkin ("images / button_skin_b.png") private function loadBlueSkin (url: String): void loader = new Loader (); loader.contentLoaderInfo.addEventListener (Event.COMPLETE, onBlueSkinLoaded); loader.load (nieuwe URLRequest (url));  private function onBlueSkinLoaded (event: Event): void loader.removeEventListener (Event.COMPLETE, onImageLoad); var bitmap: Bitmap = Bitmap (loader.content); decalSheet.bitmapData = bitmap.bitmapData; 

Eindelijk moeten we de MouseEvent op regel 13 importeren:

import flash.events.MouseEvent;

Wat we hier hebben gedaan, is een Click Event luisteraar toegevoegd aan de SimpleButton. Wanneer we die klik horen, beginnen we de nieuwe skin in te laden. Zodra de skin is geladen, tikken we de inhoud van de loader in als een bitmap en geven we de bitmapdata door aan de bitmapData-set van de DecalSheet. Wanneer u dit nu uitvoert en op de knop klikt, ziet u meteen de skin van de SimpleButton en wordt DecalSheet bijgewerkt naar de nieuwe afbeelding. De omschakeling is onmiddellijk!

Nu heb je gezien hoe we een DecalSheet maken, Decals registreren, Decals krijgen en een SimpleButton villen. We gaan ook om de knop tijdens runtime te vervangen door simpelweg een nieuwe afbeelding in te laden. Dat over dekt de kracht van het gebruik van stickers om je Flash-app te villen. De volgende stappen verwijderen eenvoudig de code die we hebben geschreven en voegen wat extra functionaliteit toe om het DecalSheet-systeem te helpen uitwerken.

Stap 15: verwijder het embleem

We kunnen niet zomaar onze DecalSheet verlaten zonder de mogelijkheid om emblemen te verwijderen die we hebben geregistreerd, dus laten we een deleteDecal-methode toevoegen na de methode registerDecal:

public function deleteDecal (name: String): Boolean return delete decalRectangles [name]; 

Stap 16: verkrijg geregistreerde naamstickers

Het zou waarschijnlijk nuttig zijn om een ​​lijst te krijgen van alle geregistreerde Decal-namen van een DecalSheet, dus laten we toevoegen in Array om alleen de Decal-namen op te slaan. We zullen de volgende eigenschap na decalRectangles rond regel 13 moeten toevoegen:

public var decalNames: Array = new Array ();

En vervang de methode registerDecal en deleteDecal met de volgende functies:

public function registerDecal (name: String, rectangle: Rectangle): void decalRectangles [name] = rectangle; decalNames.push (name);  public function deleteDecal (name: String): Boolean var index: Number = decalNames.indexOf (name); if (index! = -1) decalNames.splice (index, 1); return delete decalRectangles [naam]; 

We kunnen dit testen door het volgende in de Doc-klasse uit te voeren:

trace ("Decals", decalSheet.decalNames); decalSheet.deleteDecal ( "down"); trace ("Resterende stickers", decalSheet.decalNames);

Stap 17: maak een sticker los van het DecalSheet

De verbinding tussen de sticker en de bovenliggende DecalSheet is ongelooflijk krachtig, maar soms willen we dat Decals iets onafhankelijker zijn. Daarom gaan we een verwijdermethode toevoegen aan de klasse Decal na de methode onChange:

public function detach (): void removeListeners (decalSheetSrc); decalSheetSrc = null; 

Zodra de methode voor het loskoppelen wordt aangeroepen, verwijderen we de listeners van de gebeurtenis en wordt de verwijzing naar de sferische DecalSheet teniet gedaan. Hiermee wordt de verbinding met het bovenliggende DecalSheet volledig verbroken.

Stap 18: Een DecalSheet-interface maken

Een van de fundamentele concepten van het bouwen van OO (Object Oriented) code en ontwerppatronen is "Program to a Interface", niet een implementatie ". Helaas is het volledig uitsluiten van dit concept buiten het bestek van deze zelfstudie, maar dat betekent nog niet dat we niet kunnen proberen om enkele praktische tips in te voeren. Als u nog nooit Interfaces hebt gebruikt voordat ze heel eenvoudig zijn. Het enige dat een interface doet, is een set openbare functies definiëren die een klasse moet bevatten. Dus, in ons DecalSheet-systeem gaan we een IDecalSheet-interface maken en onze Decal ernaar typen. Hierdoor blijven onze emblemen losjes gekoppeld aan de DecalSheet en is de meeste flexibiliteit mogelijk bij het uitbreiden van ons systeem.

Om te beginnen moeten we een nieuwe interface maken in hetzelfde pakket als onze DecalSheet- en Decal Classes. Hier is de structuur van de interface:

package com.flashartofwar import flash.display.BitmapData; import flash.display.IBitmapDrawable; import flash.events.IEventDispatcher; import flash.geom.Rectangle; openbare interface IDecalSheet breidt IBitmapDrawable uit, IEventDispatcher function registerDecal (name: String, rectangle: Rectangle): void; function deleteDecal (name: String): Boolean; function getDecal (name: String): Decal; function sample (name: String): BitmapData; 

In onze interface definiëren we de meest gebruikte openbare functies die deel uitmaken van onze DecalSheet. Merk ook op dat zelfs onze interface andere interfaces kan uitbreiden. We gaan IBitmapDrawable en IEventDispatcher uitbreiden. Hierdoor kunnen onze DecalSheet dezelfde taken uitvoeren als de Bitmap-klasse en kunnen we evenementen uitzenden en beluisteren.

Nu moeten we de DecalSheet vertellen om deze interface te implementeren. Ga naar de klasse DecalSheet en vervang de klassedefinitie rond regel 10 door het volgende:

public class DecalSheet verlengt Bitmap implementeert IDecalSheet

Als uw interface in hetzelfde pakket zit als uw DecalSheet, hoeft u zich geen zorgen te maken over het importeren van de IDecalSheet-interface.

Vervolgens moeten we de interface implementeren in onze Decal Class. Waar we ook het type DecalSheet gebruiken, we zullen het willen vervangen door IDecalSheet:

Rond lijn 9:

beschermd var decalSheetSrc: IDecalSheet;

Rond lijn 11:

openbare functie Decal (naam: String, src: IDecalSheet, pixelSnapping: String = "auto", smoothing: Boolean = false)

Rond lijn 32:

beschermde functie addListeners (doel: IDecalSheet): ongeldig

Rond lijn 37:

beschermde functie removeListeners (doel: IDecalSheet): void

Nu is onze sticker volledig getypt naar de interface van de DecalSheet in plaats van naar de eigenlijke klasse. We hebben ook afgedwongen dat elke klasse die de klasse klasse wil gebruiken dezelfde openbare functies moet implementeren als de DeccalSheet.

Stap 19: wis stickers van het DecalSheet

De laatste functie die we zullen toevoegen, is de mogelijkheid om een ​​DecalSheet van de stickers te verwijderen en alle geconverteerde stickers los te koppelen die aan de DecalSheet zijn gekoppeld. Laten we beginnen om de volgende methode toe te voegen aan de DecalSheet:

public function clear (): void dispatchEvent (new Event (Event.DEACTIVATE, true, true)); decalRectangles = new Dictionary (true); decalNames = new Array (); 

Wanneer we nu de duidelijke methode op het DecalSheet noemen, sturen we een Deactivate Event en verwijderen we de Dictonary en de array. Nu moeten we een gebeurtenislistener toevoegen aan de sticker. Vervang in de klasse Decal de addListeners en removeListeners-functie met het volgende:

beschermde functie addListeners (doel: IDecalSheet): void target.addEventListener (Event.CHANGE, onChange, false, 0, true); target.addEventListener (Event.DEACTIVATE, onDeactivate);  beschermde functie removeListeners (doel: IDecalSheet): void target.removeEventListener (Event.CHANGE, onChange); target.removeEventListener (Event.DEACTIVATE, onDeactivate); 

We zullen ook de volgende methode moeten toevoegen na de functie onChange:

beschermde functie onDeactivate (event: Event): void event.stopPropagation (); losmaken (); 

We kunnen testen of alle decals zijn losgekoppeld door de Clear-methode op de DecalSheet aan te roepen en vervolgens proberen de BitmapData van de DecalSheet te wijzigen. U zult zien dat de stickers zichzelf niet meer bijwerken.

Stap 20: Het DecalSheet-systeem uitbreiden

Er zijn veel mogelijkheden om het DecalSheet-systeem uit te breiden. Een interessante spin-off is om TextField DecalSheet te maken. U kunt eenvoudig een klasse DecalSheet maken die de IDecalSheet-interface implementeert, maar in plaats van BitmapData in plaats daarvan een TextField gebruiken en dit opsplitsen in Decals. Door TextLineMetrics te gebruiken, kunnen decals worden gemaakt door regel voor regel door een TextField of Character by Character te gaan. Dit is een geweldige manier om tekst over het scherm te verplaatsen en de vervorming te voorkomen die u soms tegenkomt bij het verplaatsen van bewegende dynamische tekstvelden.

PaperVision is ook een uitstekende plek om DecalSheets te gebruiken. Stel je voor dat je een 3D-model meteen kunt bijwerken! Door Decals als texturen in te stellen, kunt u de BitmapData van de DecalSheet bijwerken om de afbeelding van uw 3D-modellen te wijzigen.

Het einde!

Dit was een vereenvoudigde versie van het DecalSheet-systeem gevonden in Flash Camoflauge, een grafisch framework dat ik schreef. Ik heb deze techniek al meer dan een jaar in mijn eigen projecten gebruikt en denk niet dat ik er zonder kan. Ik hoop dat je er net zo van geniet als ik!

Download de handleiding ActionScript-bestand