Ta opp en video i sanntid med AS3

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.


Endelig resultatforhåndsvisning

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.)


Trinn 1: Oppsett - IDE

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ø.


Trinn 2: Oppsett - Nytt prosjekt

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:


Trinn 3: Oppsett - Hovedklassen

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.


Trinn 4: Deklarere video- og kameravariablene

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.


Trinn 5: Klargjør enhetskameraet

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.


Trinn 6: Opprett faktisk videoen!

 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

Trinn 7: Deklarere blokkvariablene

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

Trinn 8: Start å lage blokkene

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 (); 

Trinn 9: Komponenter av en blokk

Før du lager blokkene, la oss forstå hva en enkelt blokk består av. Hver blokk er faktisk:

  • EN Sprite
  • med en bitmap inni det
  • som igjen trenger en BitmapData

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.


Trinn 10: Opprett blokkens base - Sprite

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.


Trinn 11: Plassering av det

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.


Trinn 12: Legge til bitmapet til blokken

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);     

Trinn 13: Oppdatering av blokkene - Konsept

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:

  1. Få gjeldende videoramme.
  2. Gå gjennom alle blokkene.
  3. Hent hver blokk poeng og bitmap barn.
  4. Tegn den tilsvarende delen av videorammen på blokkens bitmap.

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); 

Trinn 14: Capture Frame

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.

Trinn 15: La oss gå

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   

Trinn 16: Hent blokkens bitmap og punkt

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.

Trinn 17: Tegn det!

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:

  1. Kilden BitmapData obeject. Skjermbildet av videoen i dette tilfellet (srcBmpd).
  2. EN Rektangel objekt som angir det øverste venstre punktet, bredden og kolonnen i regionen i kilden som skal kopieres.
  3. Poenget i destinasjonen der den klippede delen skal kopieres. (0,0) i dette tilfellet. Så vi sender bare en ny Punkt gjenstand.

Ferdig! Nå er det på tide å kjøre prosjektet og se den fantastiske effekten.

Trinn 18: Legge til Drag-and-Drop-funksjonalitet

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);   

Trinn 19: Final Touch

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.

Konklusjon

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!