Bygg en bedre bitmap-knapp i AS3

Å bygge en knapp fra en bitmap kan være plagsom. Hvis du bruker Flash IDE, kan du opprette en maske for å bestemme hvilke piksler som er en del av knappen, og som ikke er, men i en hvilken som helst annen arbeidsflyt, vil hele rektangelet som inneholder bitmapet - inkludert eventuelle gjennomsiktige piksler - bli klikkbart . I denne opplæringen lærer du hvordan du automatisk gjør alle gjennomsiktige piksler unclickable, med bare noen få linjer med kode.


Endelig resultatforhåndsvisning

La oss se på det endelige resultatet vi vil jobbe for:

Legg merke til at håndpekeren bare vises når du svinger over selve bildet; Selv hullene i håret fører ikke til at det kommer til syne. Og det er ikke bare for show: knappetrykkene registreres bare når du klikker på disse områdene.


Introduksjon: Hva er så spesielt?

Ved første øyekast ser SWF over det svært enkle. Men se nærmere! Legg merke til hvordan i demonstrasjonen ovenfor, blir en knappetrykk talt bare hvis du klikker et sted på selve bildet. Dette er ikke hva som normalt ville skje. Siden et bitmapbilde alltid er et rektangel, vil det normalt telle som et knappetrykk å klikke hvor som helst i rektelet. Ta en titt på eksemplet nedenfor, der jeg har skissert grense rektangelet av bildet vårt. Her kan du klikke hvor som helst i rektangelet, inkludert de gjennomsiktige områdene.

Som du kan se, er dette ikke det vi vil ha! For det første kunne en bruker ved et uhell klikke på knappen når han ikke mener det. I tillegg ser det rart ut når en håndpeker vises over tomt mellomrom. I denne opplæringen lærer du hvordan du enkelt kan rette opp disse problemene.

Hvis du ikke allerede er kjent med Object Oriented Programming eller FlashDevelop, anbefaler jeg at du sjekker ut de angitte koblingene før du starter denne opplæringen.


Trinn 1: Komme i gang

Åpne FlashDevelop og opprett et nytt AS3-prosjekt (Prosjekt> Nytt prosjekt) og kalle det noe sånn BitmapButtonProj. På høyre side åpner du src mappe og dobbeltklikk Main.as å åpne den. Legg til en ny klasse for prosjektet ditt (høyreklikk / src /> Legg til> Ny klasse) kalt BitmapButton


Trinn 2: Legge inn et bilde

Vi trenger nå et bilde å jobbe med. Her er den jeg bruker:

Hvis du vil bruke et bitmap-bilde (for eksempel en .jpeg-fil eller en .png-fil) i Actionscript 3, må vi legge det inn. FlashDevelop gjør det enkelt. Når du har lagret bildet over et eller annet sted, høyreklikker du på lib mappe til høyre, musen over Legg til, og velg Bibliotekstillatelse alternativ.

Hvis du vil bruke ditt eget bilde, vær sikker på å velge en med gjennomsiktighet.

Bildet du valgte vil nå vises i lib mappe i FlashDevelop. Høyreklikk bildet og velg Generer Embed Code.

 offentlig klasse Main utvider Sprite [Embed (source = "... /lib/face.png")] private var ButtonImg: Class;

Denne koden innbygging bildet inn i vårt prosjekt. Når du legger inn et bilde, må du definere på neste linje en klasse som representerer bildet du innebygde. I dette tilfellet kalles vår klasse ButtonImg.


Trinn 3: Legge til en TextField

Deretter legger vi til en Tekstfelt for å vise hvor mange ganger vi har klikket på knappen (som vil bli lagt til neste). Legg til dette til Hoved():

 klikkTextField = nytt TextField (); klikkTextField.width = stage.stageWidth; clicksTextField.defaultTextFormat = ny TextFormat (null, 14, 0, true, false, false, null, null, TextFormatAlign.CENTER); clicksTextField.text = "Knapppresser:" + numClicks; klikkTextField.mouseEnabled = false; addChild (clicksTextField);

Koden ovenfor formater bare teksten som skal vises øverst i midten av prosjektet. Ikke gå glipp av hvordan vi erklærte vår Tekstfelt i linje 15.


Trinn 4: Legge til knappen

Denne koden skal også gå inn Hoved():

 var-knappen: BitmapButton = ny BitmapButton (ButtonImg); button.x = stage.stageWidth / 2 - button.width / 2; button.y = scene.stageHeight / 2 - button.height / 2; addChild (knapp); button.addEventListener (MouseEvent.CLICK, onButtonClick);

Når vi ordner vår BitmapButton i linje 36 sender vi vår innebygde bildeklasse som en parameter. Dette vil bli brukt av BitmapButton klasse. Etter dette kan vi bare behandle vår BitmapButton eksempel som alle andre Displayobject: Vi kan plassere den og legge til en MouseEvent.CLICK lytter som vi normalt ville.


Trinn 5: Gjør knappen til å gjøre noe

Legg til denne hendelseshåndteringsfunksjonen til Main.as:

 privat funksjon onButtonClick (e: MouseEvent): void numClicks ++; clicksTextField.text = "Knapppresser:" + numClicks; 

Det endelige stykket kode i vår Hoved klassen er hendelseslytteren for knappeklikk. I det legger vi bare til ett til antall klikk, numClicks, og oppdater teksten i clicksTextField.


Trinn 6: BitmapButton Constructor

Vend over til BitmapButton.as. Først importerer du disse klassene:

 importer flash.display.Bitmap; importer flash.display.BitmapData; importer flash.display.Sprite; importer flash.events.MouseEvent;

Deretter erklære disse:

 private var bitmapData: BitmapData; privat const THRESHOLD: Nummer = 0;

Du må sørge for at BitmapButton klassen strekker seg Sprite, siden a bitmap i seg selv kan ikke ha noen interaktivitet på musen. (De bitmap klassen utvider ikke InteractiveObject.)

 offentlig funksjon BitmapButton (ImageData: Class) var bilde: Bitmap = new ImageData (); addChild (image); bitmapData = image.bitmapData; addEventListener (MouseEvent.MOUSE_MOVE, onMouseMove); addEventListener (MouseEvent.CLICK, onClick); 

I vår BitmapButton konstruktør, oppnår vi et par viktige ting.

  • Først oppretter vi en ny bitmap, kalt bilde, fra bildeklassen bestått som en parameter til konstruktøren.
  • Vi legger til dette bitmap som et barn av vår Sprite.
  • Deretter setter vi verdien av bitmapData å likestille bitmapData av bildet vårt.
  • Til slutt legger vi til KLIKK og MOUSE_MOVE hendelse lyttere.

Trinn 7: MOUSE_MOVE Event Listener

 privat funksjon onMouseMove (e: MouseEvent): void var pixel: uint = bitmapData.getPixel32 (mouseX, mouseY); useHandCursor = buttonMode = ((pixel >>> 24)> THRESHOLD); 

Vår enkle utseende MOUSE_MOVE Hendelseslytter er den virkelige hjernen bak vår klasse. Hovedformålet er å avgjøre om musemarkøren er over en gjennomsiktig pixel eller ikke. La oss se på hvordan det gjør dette.

Funksjonen getPixel32 ()

Den første linjen får fargen og gjennomsiktigheten til pikselet som markøren er for tiden over. For å gjøre dette bruker vi getPixel32 () metode for variabelen bitmapData (som, husk, er bitmapdata representasjonen av bildet vårt).

Vi må passere en x- og y-koordinat til getPixel32 (), Så naturlig bruker vi musens posisjon.

Anropet returnerer deretter a UINT som representerer farge og gjennomsiktighet av piksel på stedet vi leverte.

Farger i Flash behandles normalt som en heksadesimal UINT i formatet RRGGBB. De to første sifrene representerer mengden rød i fargen, de neste to, grønne og de to siste, blå. derimot, getPixel32 () gir oss en spesiell UINT som representerer vår piksel i formatet AARRGGBB. Her representerer de to første sifrene alfa, eller mengden gjennomsiktighet, fra 00 (klar) til FF (ugjennomsiktig).

Så, for eksempel, FF980000 ville representere en helt ugjennomsiktig rød farge, mens 00980000 ville representere en fullstendig gjennomsiktig rød farge. Du vil vanligvis se disse representert som 0xFF980000 eller 0x0098000: "0x" lar deg (og Flash!) vite at tallet er i hexidekimalt (0-f), i stedet for desimal (0-9).

Den Bitwise Unsigned Right Shift Operator

På dette tidspunktet har vi en UINT kalt pixel som holder fargen og alfaen av pikselet under musen i AARRGGBB-formatet. Dessverre er dette for mye informasjon. Alt vi bryr oss om er gjennomsiktigheten av denne piksel, eller AA-delen.

Du kan skrive et matematisk uttrykk for å få denne delen - faktisk, int (pixel / Math.pow (16,6)) ville fungere. Dette er en noe vanskelig klage, og langsommere ytelsesmessig enn et annet alternativ vi har: den bitvis usignerte høyre skifteroperatøren, >>>.

Vår variabel pixel er bare et binært nummer til Flash. Vi skriver normalt det i heksadesimale bare for å gjøre det mer lesbart. Uten å gå inn i for mye detalj, kan hvert siffer i et heksadesimalt tall representeres av en streng med fire binære sifre, hver en eller en 0 eller 1. (Så, heksadesimale bruk siffer 0-f, desimal bruker 0-9, og binær bruker 0-1.)

Si at vi har et heksadesimalt tall, D4. I binær ville dette bli representert som 11010100. Legg merke til hvordan vi bruker åtte binære tall for binær representasjon: fire ganger så mange som i heksadesimale.

Med dette er tankene, la oss undersøke hva >>> operatøren faktisk gjør det. Lar oss bruke vårt tidligere eksempel, det heksadesimale nummer D4 eller 0xD4 for klarhet. La oss nå bruke >>> og så:

 0xD4 >>> 4

Legg merke til at 4 er en vanlig desimalrepresentasjon av et tall (det er ikke "0x" ved starten). Dette uttrykket skifter i det vesentlige hver binær siffer i D4 fire steder til høyre, og glemmer om et hvilket som helst tall som ville gå ut av slutten av nummeret.

0xD4, i binær, er 11010100. Bruk fire skift, og det blir 1101. I heksadesimale er dette 0xD.

Hvis du har problemer med å forstå dette, tenk de binære tallene som blokker som sitter på høyre side av et bord. De >>> operatør er akkurat som å skyve blokkene til høyre. Her er vårt opprinnelige binære nummer:

Nå er det vårt nye nummer, etter at vi har gjort det 0xD4 >>> 4 :

Legg merke til hvordan etter at vi skiftet 0xD4 med 4 biter, endte vi med bare 0xD? Det er ikke en tilfeldighet. Som sagt tidligere, består hvert heksadesimale siffer av 4 binære sifre - slik at hver gang vi skifter det til høyre ved 4, slår vi i hovedsak ett heksadesimale siffer fra slutten. Du kan sikkert se hvor vi skal med dette!

Tilbake til vår piksel, i 0xAARRGGBB-format. Hvis vi skifter den med 24, skifter vi faktisk med 6 heksadesimale siffer. Dette betyr at RRGGBB-delen blir slått av, og vi ender opp med bare 0xAA-delen igjen, som er vår alfakomponent.

Et raskt numerisk eksempel: Si at vår piksel er lik FF980000. I binær er dette 1111 1111 1001 1000 0000 0000 0000 0000. (Hver gruppe på 4 sifre representerer ett heksadesimale siffer.) Når vi skifter dette med 24, slutter vi bare med 1111 1111, eller FF, våre to gjennomsiktighetssifre.

Ta en titt på det igjen:

 useHandCursor = buttonMode = ((pixel >>> 24)> THRESHOLD);

Ok, den (piksel >>> 24) En del er fornuftig nå, men hva med resten?

Det er lett. Vi sjekker om vår alfakomponent (resultatet av pixel >>> 24) er større enn verdien av TERSKEL (som nå er satt til 0). Hvis det er, useHandCursor og buttonMode er satt til ekte, som vil gjøre markøren forandret til en hånd. Dette gjør at bildet ser ut som en knapp.

Hvis alfakomponenten er mindre enn eller lik TERSKEL, Markøren vil forbli normal, siden musen er over en (halv) gjennomsiktig piksel. Siden vi har satt den til 0, blir bare helt gjennomsiktige piksler ikke inkludert som en del av vår knapp, men du kan sette dette til, si 0x80, og da vil det vise håndmarkøren for alt som er mer enn halv gjennomsiktig.

Trinn 8: CLICK Event Listener

 privat funksjon onClick (e: MouseEvent): void if (! useHandCursor) e.stopImmediatePropagation (); 

Den siste delen av vår BitmapButton klassen er MouseEvent.CLICK hendelse lytter. Denne funksjonen blir kalt hver gang bildet klikker, uansett om den piksel er gjennomsiktig eller ikke. (Endring av musepekeren som vi gjorde før, vil ikke påvirke selve Mouseevent.)

Så, hver gang det er et klikk, sjekker vi useHandCursor eiendom. Hvis det er ekte, Dette betyr at musen er over en vanlig piksel i bildet vårt, og vi trenger ikke å gjøre noe. Dette er fornuftig - arrangementet fortsetter videre til hendelseslytteren vi lagt til Main.as. Men hvis useHandCursor er falsk, må vi gjøre noe for å stoppe arrangementet fra å fortsette videre til andre hendelselyttere.

For dette bruker vi stopImmediatePropagation () metode som alle Begivenhet objekter har. Enkelt sagt, dette stopper strømmen av arrangementet, og ikke flere hørere vil motta det. Så vår funksjonslytter fungerer i Main.as vil aldri bli kalt.

Advarsel: Dette kan ha en stygg bivirkning - en hvilken som helst global hendelselytter vil ikke få arrangementet heller. Hvis du er bekymret for dette, kan du prøve å legge til linjen parent.dispatchEvent (e.clone ()); etter e.stopImmediatePropogation (). Selv om dette er utenfor omfanget av opplæringen, anbefaler jeg at du leser mer om arrangementssystemet her.


Konklusjon

Dette bryter opp vår opplæring! Takk for at du leser, og jeg håper du har lært noe nytt.

En advarsel når du bruker vår BitmapButton klasse - andre MouseEvents vil fortsatt fungere som normalt, siden vi bare behandlet MouseEvent.CLICK. Hvis du vil, kan du bruke den samme teknikken vi brukte MouseEvent.CLICK og bruk den til andre hendelser, for eksempel MouseEvent.MOUSE_DOWN.

Våre BitmapButton klassen lar oss raskt og enkelt lage flotte knapper fra bitmap-bilder med gjennomsiktighet, som vi gjorde i denne demoen. Hvis du har noen spørsmål, vil jeg gjerne svare på dem, bare legg igjen en kommentar nedenfor.