Hei, kodefreaks! Denne opplæringen vil vise deg hvordan du deler en kjørende video i blokker som om den har eksplodert. Og alt dette bruker bare ActionScript. For denne opplæringen bruker vi kameraet som videokilde, slik at du kan se endringene live.
La oss se på det endelige resultatet vi vil jobbe for:
Klikk og dra en blokk for å flytte den rundt på skjermen! (Kameraadgang er nødvendig.)
For denne opplæringen bruker vi FlashDevelop IDE (selv om du kan bruke noen AS3 editor). I tilfelle du ikke har det og vil prøve, kan du hente det herfra. En grunnleggende veiledning om hvordan du konfigurerer FlashDevelop på deg, kan du finne her.
Også hvis du har Flash Professional installert på din side, vil det også fungere. Alt du trenger å gjøre er å opprette en ekstern klassefil som nevnt nedenfor og koble den til Flash-prosjektet ditt som en Dokument-klasse.
Det setter opp vårt arbeidsmiljø.
Opprett et nytt AS3-prosjekt i FlashDevelop.
Når det er gjort, vil du ha en Hoved
klasse opprettet i src-mappen som sett i det høyre panelet:
Neste må vi lage Main.as
lag litt renere ved å eliminere noen kode. Først når du åpner Main.as
fil, det ville ha kode noe slikt:
pakke import flash.display.Sprite; importere flash.events.Event; offentlig klasse Hoved utvider Sprite offentlig funksjon Main (): void if (stage) init (); ellers addEventListener (Event.ADDED_TO_STAGE, init); privat funksjon init (e: Event = null): void removeEventListener (Event.ADDED_TO_STAGE, init); // inngangspunkt
Vi sletter en del av koden slik at den ser renere ut. Så du bør ha dette:
pakke import flash.display.Sprite; importere flash.events.Event; offentlig klasse Hoved utvider Sprite offentlig funksjon Main (): void
Nå er alt oppsettet ferdig, og det er på tide å dykke inn i noen kode.
Vårt første mål er å tegne videoen på scenen ved hjelp av kameraet; for dette må vi deklarere noen variabler. Sett disse erklæringene like over Hoved
klassekonstruktør.
// video variabler private var camW: int = 300; privat var camH: int = 300; privat var video: Video;
camW
- Bredden på kameraet / videoen.
CAMH
- Høyden på kameraet / videoen.
video
- Våre video
klasse eksempel.
Som nevnt tidligere bruker vi kamerautgangen i videoen. Så først må vi gjøre enhetens kamera klar. Følgende kode skal gå inn i klassekonstruktøren.
Var kamera: Kamera = Camera.getCamera ();
Her instanser vi en Kamera
forekomst og få tilgjengelig kamera med bruk av statisk metode getCamera ()
av Kamera
klasse.
camera.setMode (camW, camH, 30);
Vi tilbyr noen kamerainnstillinger: bredde, høyde og fps.
Merk at vi ikke gjorde kameravariablen globalt fordi vi ikke trenger å få tilgang til det hvor som helst utenfor denne funksjonen, som du vil se neste. I det neste trinnet initialiserer vi video
variabel.
video = ny video (camW, camH); video.attachCamera (kamera);
Vi har nå instansert video
variabel og brukt attachCamera ()
metode for å feste kameraet til det. Dette betyr at videoen nå bruker kamerautgangen som kilde.
Alt gjort med video og kamera ting. Husk at du må importere passende klasser i koden din. Din komplette klassekode skal se slik ut for øyeblikket:
pakke import flash.display.Sprite; importere flash.events.Event; importere flash.media.Camera; importere flash.media.Video; offentlig klasse Main utvider Sprite // video variabler private var camW: int = 300; privat var camH: int = 300; privat var video: Video; offentlig funksjon Main (): void var kamera: Kamera = Camera.getCamera (); camera.setMode (camW, camH, 30); video = ny video (camW, camH); video.attachCamera (kamera);
Hvis du kjører (F5 eller CTRL + Enter) prosjektet akkurat nå, ville det være tomt scenen, men du vil sannsynligvis få en forespørsel om kameratilgang da programmet prøver å få tilgang til enhetskameraet. Tillate det.
Grunnen til at du ikke ser noe er fordi vi ikke vil vise videoen, og vi har ikke lagt det til scenen (visningsliste). Det blir bare brukt som kilde for våre separate blokker. Hvis du vil teste at alt fungerer bra, legg du bare til følgende linje på slutten i Hoved
konstruktør:
addChild (video); // Fjern denne linjen etter testing
Nå lager vi blokkene - de separate punktene i videoen. Og det første trinnet er å erklære noen variabler som kreves for det. Så fortsett og legg opp følgende variabeldeklarasjoner like under videovariablene:
// blokkvariabler private var rader: int = 3; private var cols: int = 3; privat var blokkW: int = camW / cols; privat var blokkH: int = camH / rader; private var pointCollection: Objekt = nytt objekt ();
rader
- Antall rader for å dele videoen inn.
kolonner
- Ja. Du har det. Antall kolonner for å dele videoen inn.
blockW
- Hver blokk er bredde. Dette er en avledet variabel som det bare beregnes ved å dele den totale bredden (camW
) etter antall kolumner (kolonner
).
blockH
- Hver blokk er høyde, dvs.. CAMH
delt med rader
.
PointCollection
- Endelig, men viktigste variabel. Det er en tilknyttet matrise som vi skal bruke til å lagre det tilsvarende punktet i hver blokk. For eksempel, hvis en blokk har navn block12
, da lagret vi det tilsvarende punktet p12
som dette :
pointCollection ["block12"] = p12; // poeng er punktklasse forekomster her
Nå som vi har definert de nødvendige variablene, begynner vi faktisk å lage blokkene. Vi skal holde alle blokkopprettelseskoden i en funksjon som kalles initBlocks ()
. Denne funksjonen blir hentet fra Hoved
konstruktør etter å ha satt inn videoen.
Så, la oss først erklære en funksjon som heter initBlocks ()
like etter Hoved
konstruktør.
privat funksjon initBlocks (): void for (var r: int = 0; r < rows; r++) for (var c:int = 0; c < cols; c++) // code to create each block
Legg merke til de to til
løkker vi har plassert inne, noe som vil hjelpe oss med å lage blokkene i et 2D-rutenett, radvis. Og legg deretter til et anrop til denne funksjonen på slutten av Hoved()
:
offentlig funksjon Main (): void var kamera: Kamera = Camera.getCamera (); camera.setMode (camW, camH, 30); video = ny video (camW, camH); video.attachCamera (kamera); initBlocks ();
Før du lager blokkene, la oss forstå hva en enkelt blokk består av. Hver blokk er faktisk:
Sprite
bitmap
inni detBitmapData
Tenker på Sprite
som den ytre beholderen. Helt blank.
For å tegne blokken trenger vi en bitmap
som viser den tilsvarende videoutgangen.
Og til slutt, hver bitmap
trenger noen data for å trekke inn i den. Det er gitt i form av BitmapData
.
Den første komponenten i en blokk, som vi diskuterte, er en Sprite. Så kan vi lage en. Alle koden som vi skriver for å lage blokken, skal skrives inn i til
løkker.
var newBlock: Sprite = ny Sprite ();
Vi lager en ny forekomst av Sprite
klasse.
newBlock.name = "block" + r + c;
Da heter vi sprite slik at vi kan referere det senere i koden. Navngivningskonvensjonen er enkel: en blokk i rad r og kolonne c er oppkalt blokk + r + c
(+ betyr sammenkobling). Så en blokk i rad 2 og kolonne 1 er oppkalt block21
.
Etter å ha opprettet det, må vi plassere det på scenen i henhold til rad og kolonne. Så kan vi legge til følgende kode.
var p: Punkt = nytt punkt (c * blokkW, r * blokkH);
Vi bruker en Punkt
klasseobjekt for å lagre noen punkts koordinater her. Og så oppretter vi en ny forekomst av Punkt
og passere c * blockW
som x-verdien og r * blockH
som y-verdien. Nå kan koordinatene bare nås som p.x
og p.y
og brukes senere for å hente hver blokks clippped-region fra en komplett videoramme. Husk at hver blokk er punktene er faktisk koordinatene til det øverste venstre punktet i rutenettet.
Hvis du er i tvil om hvordan posisjonen beregnes her, vil følgende figur gjøre det klart.
newBlock.x = c * (blokkW + 1) + 20; newBlock.y = r * (blokkH + 1) + 20;
Deretter plasserer vi sprite. Cordinatene er mer eller mindre de samme forventer nå legger vi til 20 for å gi en forskyvning. Vi legger også til 1 til blockW
og blockH
å skille blokkene med 1 piksel, som det er synlig i demonstrasjonen ovenfor.
pointCollection [newBlock.name] = p;
Til slutt lagrer vi poenget vi har beregnet tidligere i PointCollection
.
Nå kommer til den andre og tredje komponenten av blokken.
var bmpd: BitmapData = ny BitmapData (blokkW, blokkH);
Først oppretter vi en BitmapData
forekomst og passere ønsket blokkbredde og høyde som vi hadde lagret før. Som diskutert tidligere, a BitmapData
forekomst er nødvendig for å opprette en bitmap
eksempel som er bestått i konstruktøren.
var bmp: Bitmap = ny Bitmap (bmpd); bmp.name = "myBmp";
Nå lager vi en bitmap
forekomst og passere den tidligere opprettede bmpd
i konstruktøren. Også, vi heter bitmappen myBmp
så vi kan referere det senere.
newBlock.addChild (BMP); addChild (newBlock);
Til slutt legger vi til bitmapet bmp
som et barn av newBlock
og newBlock
seg selv som scenens barn.
Bare for å være sikker på at du er på rett spor, din Main.as
koden skal se slik ut:
pakke import flash.display.Bitmap; importer flash.display.BitmapData; importer flash.display.Sprite; importer flash.geom.Point; importere flash.media.Camera; importere flash.media.Video; offentlig klasse Main utvider Sprite // video variabler private var camW: int = 300; privat var camH: int = 300; privat var video: Video; // blokkvariabler private var rader: int = 3; private var cols: int = 3; privat var blokkW: int = camW / cols; privat var blokkH: int = camH / rader; private var pointCollection: Array = new Array (); offentlig funksjon Main (): void var kamera: Kamera = Camera.getCamera (); camera.setMode (camW, camH, 30); video = ny video (camW, camH); video.attachCamera (kamera); initBlocks (); privat funksjon initBlocks (): void for (var r: int = 0; r < rows; r++) for (var c:int = 0; c < cols; c++) var newBlock:Sprite = new Sprite(); newBlock.name = "block" + r + c; var p:Point = new Point(c * blockW, r * blockH); newBlock.x = c * (blockW + 1) + 20; newBlock.y = r * (blockH + 1) + 20; pointCollection[newBlock.name] = p; var bmpd:BitmapData = new BitmapData(blockW, blockH); var bmp:Bitmap = new Bitmap(bmpd); bmp.name = "myBmp"; newBlock.addChild(bmp); addChild(newBlock);
Selv om vi har blokkene plassert i de riktige stillingene, ser vi fortsatt ikke noe på å kjøre prosjektet. Det er fordi vi fortsatt ikke har trukket noe inne i blokkblokkene.
Vår neste skritt er å kjøre en løpende løkke som utfører følgende operasjoner:
Så? la oss gjøre det!
Før vi implementerer sløyfekoden, trenger vi en LOOP FUNKSJON (som en spillsløyfe). Legg til følgende funksjonsdeklarasjon under initBlocks ()
funksjon:
privat funksjon oppdateringBlokker (e: Hendelse): void
Som det er synlig fra funksjonsparameteren, virker det som en hendelselytter og ja det er det. Dette er en lytterfunksjon som vi vil legge ved ENTER_FRAME
arrangement av scenen. For å legge ved lytteren, legg til denne linjen på slutten av Hoved()
konstruktør.
offentlig funksjon Main (): void var kamera: Kamera = Camera.getCamera (); camera.setMode (camW, camH, 30); video = ny video (camW, camH); video.attachCamera (kamera); initBlocks (); addEventListener (Event.ENTER_FRAME, updateBlocks);
Dette er den første operasjonen vi utfører i vår loop - the updateBlocks ()
funksjon som kalles på hver ramme. Sett inn følgende kode innvendig updateBlocks ()
funksjon.
var srcBmpd: BitmapData = ny BitmapData (camW, camH);
Hver bitmapps data i ActionScript 3.0 må være inneholdt i a BitmapData
eksempel og så oppretter vi en. Vi vil fylle denne forekomsten med de nåværende videorammedataene neste.
srcBmpd.draw (video);
Her har vi brukt tegne()
funksjon av BitmapData
klasse. Det krever et objekt av hvilken som helst klasse som implementerer IBitmapDrawable
grensesnitt. For eksempel. Sprite, MovieClip, BitmapData etc. Det som gjøres er ganske enkelt å ta de visuelle dataene til objektet som passerer og lagre det i BitmapData
forekomst.
Så nå har vi den nåværende videorammen (eller, du kan si et skjermbilde) i variabelen srcBmpd
.
Da vi trenger å oppdatere hver blokk, oppretter vi en dobbel til
-loop, ligner den vi skrev for å lage blokkene. Så gå videre og legg til det.
Funksjonen skal se ut som dette akkurat nå:
privat funksjon updateBlocks (e: Event): void var srcBmpd: BitmapData = ny BitmapData (camW, camH); srcBmpd.draw (video); for (var r: int = 0; r < rows; r++) for (var c:int = 0; c < cols; c++) // update code here
Husk at vi kalt blokkene på en bestemt måte mens du lager dem, slik at vi kan referere til en blokk ved hjelp av rad- og kolonnnummer. Det er det vi skal bruke nå for å få referansen til hver blokk.
var b_mc: Sprite = this.getChildByName ("blokk" + r + c) som Sprite;
Vi bruker getChildByName
funksjon av scene
(dette
) som returnerer en referanse til et objekt hvis navn samsvarer med strengen som er passert. Også vi skrev det til Sprite
klasse bare for å være sikker på at det returnerte objektet er a Sprite
. Nå er blokkreferansen i variabelen b_mc
.
var bmp: Bitmap = b_mc.getChildByName ("myBmp") som Bitmap;
På samme måte henter vi referansen til bitmapet som ble lagt til som et barn i blokksprite.
var p: Punkt = pointCollection [b_mc.name];
Til slutt får vi den nåværende blokkens (b_mc
) koordinerer fra arrayet der vi lagret det tidligere ved hjelp av blokkens navn.
Nå som vi har all nødvendig informasjon om hva du skal tegne hvor, kan vi faktisk DRAW det. Motivet vårt her er å få den rektangulære delen av videorammen (dvs.. srcBmpd
) med det øverste venstre punktet som det hentede punktet p
, bredde som blockW
og høyde som blockH
.
Til dette formål bruker vi copyPixels ()
metode av BitmapData
klasse. Den kopierer faktisk regionen til en annen kilde BitmapData
spesifisert ved å sende a Rektangel
gjenstand.
bmp.bitmapData.copyPixels (srcBmpd, nytt rektangel (p.x, p.y, blockW, blockH), nytt punkt ());
De tegne()
funksjon er påkalt bmp
's bitmapData
eiendom. Parametrene passerte inn i det er:
BitmapData
obeject. Skjermbildet av videoen i dette tilfellet (srcBmpd
).Rektangel
objekt som angir det øverste venstre punktet, bredden og kolonnen i regionen i kilden som skal kopieres. Punkt
gjenstand. Ferdig! Nå er det på tide å kjøre prosjektet og se den fantastiske effekten.
For å legge til dra og slipp-funksjonen som sett i demoen, trenger vi bare å knytte to muselyttere til hver blokk - en for MOUSE_DOWN
arrangement og en annen for MOUSE_UP
begivenhet. Så fortsett og definer to musen håndteringsfunksjoner på slutten av klassen:
privat funksjon onMouseDown (e: MouseEvent): void Sprite (e.currentTarget) .startDrag (); privat funksjon onMouseUp (e: MouseEvent): void Sprite (e.currentTarget) .stopDrag ();
Alt vi gjør inne i disse lytterfunksjonene, er å få referansen til hendelses-forsendelsesblokken ved hjelp av currentTarget
eiendom av Begivenhet
objekt, skriv det til en Sprite
(som det er hva våre blokker er) og ring til drag ()
og stopdrag ()
å håndtere dra og slipp.
Det er ikke helt alle ennå. Vi må fortsatt knytte disse lytterne til de tilsvarende hendelsene. Så legg disse to linjene til initBlocks ()
funksjon.
privat funksjon initBlocks (): void for (var r: int = 0; r < rows; r++) for (var c:int = 0; c < cols; c++) var newBlock:Sprite = new Sprite(); newBlock.name = "block" + r + c; var p:Point = new Point(c * blockW, r * blockH); newBlock.x = c * (blockW + 1) + 20; newBlock.y = r * (blockH + 1) + 20; pointCollection[newBlock.name] = p; var bmpd:BitmapData = new BitmapData(blockW, blockH); var bmp:Bitmap = new Bitmap(bmpd); bmp.name = "myBmp"; newBlock.addChild(bmp); addChild(newBlock); newBlock.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); newBlock.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
En siste ting bare for å gjøre det ser mer interaktiv ut. Du har kanskje lagt merke til hvordan blokkene fades inn og ut når de trykkes og slippes ut. Det er en alfa-manipulasjon vi gjør inne i lytterne. Endre lytterne til noe som:
privat funksjon onMouseDown (e: MouseEvent): void Sprite (e.currentTarget) .alpha = 0.4; Sprite (e.currentTarget) .startDrag (); privat funksjon onMouseUp (e: MouseEvent): void Sprite (e.currentTarget) .alpha = 1; Sprite (e.currentTarget) .stopDrag ();
Og der har du alfa-endringseffekten.
Effekten har mye potensial til bruk i ulike applikasjoner. Jeg har utviklet et puslespill som nylig brukte det.
Bortsett fra det, kan det brukes til å skape overgangseffekter for videospillere, eller i sammenheng med 3D for å teksturere en overflate med en video.
Jeg håper å se noen kule ting folk kommer opp med å bruke denne effekten!