Hallo, code freaks! In deze zelfstudie leer je hoe je een lopende video in blokken splitst alsof deze is geëxplodeerd. En dit alles met alleen ActionScript. Voor deze zelfstudie gebruiken we de camera als videobron, zodat je de wijzigingen live kunt bekijken.
Laten we eens kijken naar het eindresultaat waar we naartoe zullen werken:
Klik en sleep een blok om het over het scherm te verplaatsen! (Toegang tot de camera vereist.)
Voor deze tutorial gebruiken we de FlashDevelop IDE (hoewel je elke AS3-editor zou kunnen gebruiken). Als je het niet hebt en het wilt proberen, kun je het vanaf hier pakken. Een eenvoudige tutorial over het instellen van FlashDevelop op uw machine vindt u hier.
Ook als u Flash Professional aan uw zijde hebt geïnstalleerd, werkt ook dat. Het enige wat u hoeft te doen is een extern klassenbestand maken zoals hieronder vermeld en het koppelen aan uw Flash-project als een klasse Document.
Dat schept onze werkomgeving.
Maak een nieuw AS3-project in FlashDevelop.
Als het klaar is, heb je een Hoofd
klasse gemaakt in de map src zoals te zien in het rechterdeelvenster:
Vervolgens moeten we de Main.as
bestand een beetje schoner door het elimineren van een code. Aanvankelijk wanneer u de Main.as
bestand, zou het code iets als dit hebben:
pakket import flash.display.Sprite; import flash.events.Event; public class Hoofd breidt uit openbare functie Main (): void if (stage) init (); else addEventListener (Event.ADDED_TO_STAGE, init); private function init (e: Event = null): void removeEventListener (Event.ADDED_TO_STAGE, init); // ingangspunt
We zullen een deel van de code verwijderen om het er schoner uit te laten zien. Dus je zou dit moeten hebben:
pakket import flash.display.Sprite; import flash.events.Event; public class Hoofd breidt uit openbare functie Main (): void
Nu is alle installatie voltooid en is het tijd om in een code te duiken.
Ons eerste doel is om de video op het podium te tekenen met behulp van de camera; hiervoor moeten we enkele variabelen declareren. Zet deze verklaringen net boven de Hoofd
klassenbouwer.
// videovariabelen private var camW: int = 300; private var camH: int = 300; privé var video: video;
camW
- De breedte van de camera / video.
CAMH
- De hoogte van de camera / video.
video-
- Onze Video
klasse instantie.
Zoals eerder vermeld, gebruiken we de camera-uitvoer in de video. Dus eerst moeten we de camera van het apparaat klaar maken. De volgende code zou in de klassenbouwer moeten gaan.
var camera: Camera = Camera.getCamera ();
Hier nemen we een Camera
bijvoorbeeld en verkrijg de beschikbare apparaatcamera met behulp van de statische methode getCamera ()
van de Camera
klasse.
camera.setMode (camW, camH, 30);
We bieden enkele camera-instellingen: breedte, hoogte en fps.
Merk op dat we de camera-variabele niet globaal hebben gemaakt, omdat we deze nergens anders nodig hebben buiten deze functie, zoals je hierna zult zien. In de volgende stap initialiseren we de video-
veranderlijk.
video = nieuwe video (camW, camH); Video.attachCamera (camera);
We hebben nu het video-
variabele en gebruikte de attachCamera ()
methode om de camera eraan te bevestigen. Dit betekent dat de video nu de camera-uitgang als bron gebruikt.
Alles gedaan met de video en camera dingen. Vergeet niet dat u de juiste klassen in uw code moet importeren. Uw volledige klassecode zou er op het moment zo uit moeten zien:
pakket import flash.display.Sprite; import flash.events.Event; import flash.media.Camera; import flash.media.Video; public class Hoofd breidt Sprite uit // videovariabelen private var camW: int = 300; private var camH: int = 300; privé var video: video; public function Main (): void var camera: Camera = Camera.getCamera (); camera.setMode (camW, camH, 30); video = nieuwe video (camW, camH); Video.attachCamera (camera);
Als je het project nu (F5 of CTRL + Enter) uitvoert, zou het een lege fase zijn, maar je zult waarschijnlijk een cameratoegangsverzoek ontvangen terwijl de applicatie probeert toegang te krijgen tot de camera van het apparaat. Sta het toe.
De reden waarom u niets ziet, is omdat we de video niet willen weergeven en daarom hebben we deze niet aan het podium toegevoegd (weergavelijst). Het zal alleen worden gebruikt als een bron voor onze afzonderlijke blokken. Als je wilt testen of alles goed werkt, voeg je gewoon de volgende regel toe aan het einde in de Hoofd
bouwer:
addChild (video); // Verwijder deze regel na het testen
Nu maken we de blokken - de afzonderlijke stukken van de video. En de eerste stap is om een aantal variabelen te declareren die daarvoor vereist zijn. Dus ga je gang en tel de volgende variabelenverklaringen op net onder de videovariabelen:
// blokvariabelen privé var-rijen: int = 3; private var cols: int = 3; private var blockW: int = camW / cols; private var blockH: int = camH / rows; private var pointCollection: Object = new Object ();
rijen
- Aantal rijen om de video in te splitsen.
cols
- Ja. Je hebt het. Aantal kolommen om de video in te splitsen.
blockW
- De breedte van elk blok. Dit zijn afgeleide variabelen omdat het eenvoudigweg wordt berekend door de totale breedte te delen (camW
) op aantal colums (cols
).
blockH
- De hoogte van elk blok, d.w.z.. CAMH
gedeeld door rijen
.
pointCollection
- Laatste maar belangrijkste variabele. Het is een associatieve array die we zullen gebruiken om het corresponderende punt van elk blok op te slaan. Als een blok bijvoorbeeld een naam heeft block12
, dan zouden we het bijbehorende punt opslaan p12
zoals dit :
pointCollection ["block12"] = p12; // punten zijn hier Point-class instanties
Nu we de vereiste variabelen hebben gedefinieerd, beginnen we met het maken van de blokken. We houden alle code voor het maken van blokken in een functie met de naam initBlocks ()
. Deze functie wordt aangeroepen vanuit de Hoofd
constructor na het instellen van de video.
Laten we dus eerst een functie noemen initBlocks ()
net na de Hoofd
bouwer.
private functie initBlocks (): void for (var r: int = 0; r < rows; r++) for (var c:int = 0; c < cols; c++) // code to create each block
Let op de twee voor
loops die we erin hebben geplaatst, wat ons helpt om de blokken in een 2D-raster rijvormig te maken. En voeg vervolgens aan het eind van deze maand een oproep toe aan deze functie Hoofd()
:
public function Main (): void var camera: Camera = Camera.getCamera (); camera.setMode (camW, camH, 30); video = nieuwe video (camW, camH); Video.attachCamera (camera); initBlocks ();
Voordat we de blokken maken, laten we begrijpen waaruit een enkel blok bestaat. Elk blok is eigenlijk:
sprite
Bitmap
in hetBitmapData
Denken aan sprite
als de buitenste container. Helemaal leeg.
Om het blok te tekenen, hebben we een Bitmap
die de bijbehorende video-uitvoer zal tonen.
En tot slot, elke Bitmap
heeft wat gegevens nodig om erin te tekenen. Dat wordt gegeven in de vorm van BitmapData
.
Het eerste onderdeel van een blok, zoals we hebben besproken, is een Sprite. Dus laten we er een maken. Alle code die we schrijven om het blok aan te maken, moet in de. Worden geschreven voor
loops.
var newBlock: Sprite = nieuwe Sprite ();
We maken een nieuw exemplaar van de sprite
klasse.
newBlock.name = "block" + r + c;
Vervolgens noemen we de sprite, zodat we er later in de code naar kunnen verwijzen. De naamgevingsconventie is eenvoudig: een blok op rij r en kolom c heeft de naam blok + r + c
(+ betekent aaneenschakeling). Dus een blok in rij 2 en kolom 1 wordt genoemd block21
.
Nadat je het hebt gemaakt, moeten we het op het podium plaatsen volgens de rij en kolom. Dus laten we de volgende code toevoegen.
var p: Point = new Point (c * blockW, r * blockH);
We gebruiken een Punt
class object om de coördinaten van elk punt hier op te slaan. En dus creëren we een nieuw exemplaar van Punt
en ga voorbij c * blockW
als de x-waarde en r * blockH
als de y-waarde. Nu zijn de coördinaten eenvoudig toegankelijk p.x
en p.y
en wordt later gebruikt om het clippped-gebied van elk blok op te halen uit een volledig videoframe. Onthoud dat het punt van elk blok eigenlijk de coördinaten is van het punt linksboven in het raster.
Als u twijfelt over hoe de positie hier wordt berekend, zal de volgende afbeelding duidelijk maken.
newBlock.x = c * (blockW + 1) + 20; newBlock.y = r * (blockH + 1) + 20;
Vervolgens plaatsen we de sprite. De cordinaten zijn min of meer hetzelfde, dus we voegen nu 20 toe om een offset te geven. We voegen ook 1 toe aan de blockW
en blockH
om de blokken met 1 pixel te scheiden, zoals zichtbaar is in de demo hierboven.
pointCollection [newBlock.name] = p;
Ten slotte besparen we het punt dat we eerder in de pointCollection
.
Nu komt het naar de 2e en 3e component van het blok.
var bmpd: BitmapData = nieuwe BitmapData (blockW, blockH);
Eerst maken we een BitmapData
bijvoorbeeld en geef de vereiste blokbreedte en hoogte door die we eerder hadden opgeslagen. Zoals eerder besproken, BitmapData
instantie is vereist om een te maken Bitmap
instantie die wordt doorgegeven in de constructor.
var bmp: Bitmap = nieuwe Bitmap (bmpd); bmp.name = "myBmp";
Nu maken we een Bitmap
exemplaar en geef de eerder gemaakte door bmpd
in de constructor. We noemen ook de bitmap myBmp
zodat we er later naar kunnen verwijzen.
newBlock.addChild (BMP); addChild (newBlock);
Uiteindelijk voegen we de bitmap toe bmp
als een kind van newBlock
en newBlock
zichzelf als het kind van het podium.
Om er zeker van te zijn dat u op de goede weg bent, uw Main.as
code zou er ongeveer zo uit moeten zien:
pakket import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Sprite; import flash.geom.Point; import flash.media.Camera; import flash.media.Video; public class Hoofd breidt Sprite uit // videovariabelen private var camW: int = 300; private var camH: int = 300; privé var video: video; // blokvariabelen privé var-rijen: int = 3; private var cols: int = 3; private var blockW: int = camW / cols; private var blockH: int = camH / rows; private var pointCollection: Array = new Array (); public function Main (): void var camera: Camera = Camera.getCamera (); camera.setMode (camW, camH, 30); video = nieuwe video (camW, camH); Video.attachCamera (camera); initBlocks (); private functie 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);
Hoewel we de blokken op de juiste posities hebben geplaatst, zien we nog steeds niets over het uitvoeren van het project. Dat komt omdat we nog steeds niets hebben getekend binnen de blokbitmaps.
Onze volgende stap is het uitvoeren van een constant lopende lus die de volgende bewerkingen uitvoert:
Zo? laten we het doen!
Voordat we de loop-code implementeren, hebben we een LOOP-FUNCTIE nodig (een beetje zoals een gamelus). Voeg de volgende functieverklaring toe onder de initBlocks ()
functie:
persoonlijke functie updateBlocks (e: Event): void
Zoals zichtbaar is vanuit de functieparameter, lijkt het een gebeurtenislistener en ja, dat is het. Dit is een luisterfunctie die we zullen koppelen aan de ENTER_FRAME
evenement van de etappe. Om de luisteraar te bevestigen, voegt u deze regel toe aan het einde van de Hoofd()
bouwer.
public function Main (): void var camera: Camera = Camera.getCamera (); camera.setMode (camW, camH, 30); video = nieuwe video (camW, camH); Video.attachCamera (camera); initBlocks (); addEventListener (Event.ENTER_FRAME, updateBlocks);
Dit is de eerste bewerking die we uitvoeren in onze loop - de updateBlocks ()
functie die op elk frame wordt aangeroepen. Plaats de volgende code erin updateBlocks ()
functie.
var srcBmpd: BitmapData = nieuwe BitmapData (camW, camH);
De gegevens van elke bitmap in Actionscript 3.0 moeten worden opgenomen in a BitmapData
instantie en dus maken we er een. We vullen dit exemplaar vervolgens met de huidige videoframegegevens in.
srcBmpd.draw (video);
Hier hebben we de trek()
functie van de BitmapData
klasse. Het vereist een object van de klasse die het implementeert IBitmapDrawable
interface. Voor bijvoorbeeld. Sprite, MovieClip, BitmapData enz. Wat het doet is simpelweg de visuele gegevens van het object halen en opslaan in de BitmapData
aanleg.
Dus nu hebben we het huidige videoframe (of, zou je kunnen zeggen, een screenshot) in de variabele srcBmpd
.
Omdat we elk blok moeten bijwerken, maken we een dubbel voor
-loop, vergelijkbaar met degene die we hebben geschreven voor het maken van de blokken. Dus ga je gang en voeg het toe.
De functie zou er op dit moment hetzelfde uit moeten zien:
private function updateBlocks (e: Event): void var srcBmpd: BitmapData = nieuwe BitmapData (camW, camH); srcBmpd.draw (video); voor (var r: int = 0; r < rows; r++) for (var c:int = 0; c < cols; c++) // update code here
Vergeet niet dat we de blokken op een bepaalde manier hebben benoemd tijdens het maken ervan, zodat we naar elk blok kunnen verwijzen met behulp van het rij- en kolomnummer. Dat is wat we nu gebruiken om de referentie van elk blok te krijgen.
var b_mc: Sprite = this.getChildByName ("block" + r + c) als Sprite;
Wij gebruiken de getChildByName
functie van de stadium
(deze
) die een verwijzing retourneren naar een object waarvan de naam overeenkomt met de doorgegeven string. We typeren het ook sprite
class om er zeker van te zijn dat het geretourneerde object een is sprite
. Nu is de blokverwijzing in de variabele b_mc
.
var bmp: Bitmap = b_mc.getChildByName ("myBmp") als Bitmap;
Op dezelfde manier halen we de verwijzing naar de bitmap op die als een kind van de bloksprite is toegevoegd.
var p: Point = pointCollection [b_mc.name];
Eindelijk krijgen we de huidige blok (b_mc
) coördinaten van de array waarin we het eerder hebben opgeslagen met behulp van de naam van het blok.
Nu we alle benodigde informatie hebben over waar we naartoe moeten tekenen, kunnen we het eigenlijk TEKENEN. Ons motief hier is om het rechthoekige gebied van het videoframe (d.w.z.. srcBmpd
) met het punt linksboven als het opgehaalde punt p
, breedte als blockW
en hoogte als blockH
.
Voor dit doel gebruiken we de copyPixels ()
methode van de BitmapData
klasse. Het kopieert eigenlijk de regio van een andere bron BitmapData
gespecificeerd door het passeren van een Rechthoek
voorwerp.
bmp.bitmapData.copyPixels (srcBmpd, nieuwe Rectangle (p.x, p.y, blockW, blockH), new Point ());
De trek()
functie wordt ingeschakeld bmp
's bitmapData
eigendom. De parameters die erin worden doorgegeven zijn:
BitmapData
obeject. Het screenshot van de video in dit geval (srcBmpd
).Rechthoek
object dat het punt, de breedte en de kolom linksboven in de regio in de bron die moet worden gekopieerd, opgeeft. Punt
voorwerp. Helemaal klaar! Nu is het tijd om je project uit te voeren en het geweldige effect te zien.
Om de drag-and-drop-functie toe te voegen zoals te zien is in de demo, hoeven we slechts twee muisluisteraars aan elk blok te hechten - een voor de MOUSE_DOWN
evenement en een andere voor de MOUSE_UP
evenement. Dus ga je gang en definieer twee muis-handler-functies aan het einde van de les:
private function onMouseDown (e: MouseEvent): void Sprite (e.currentTarget) .startDrag (); private function onMouseUp (e: MouseEvent): void Sprite (e.currentTarget) .stopDrag ();
Alles wat we doen in deze listener-functies is om de verwijzing naar het blok voor gebeurtenisafhandeling te krijgen met behulp van de currentTarget
eigendom van de Evenement
object, typ het naar een sprite
(zoals dat is wat onze blokken zijn) en noem het startDrag ()
en stopDrag ()
om het slepen-en-neerzetten af te handelen.
Dat is nog niet alles. We moeten deze luisteraars nog steeds koppelen aan hun bijbehorende evenementen. Dus voeg deze twee regels toe aan de initBlocks ()
functie.
private functie 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);
Een laatste ding om het alleen maar interactiever te laten lijken. Je hebt misschien gemerkt hoe de blokken vervagen in en uit wanneer ze worden ingedrukt en losgelaten. Dat is een alfamanipulatie die we binnen de luisteraars doen. Pas je luisteraars aan op iets als:
private function onMouseDown (e: MouseEvent): void Sprite (e.currentTarget) alpha = 0,4; Sprite (e.currentTarget) .startDrag (); private function onMouseUp (e: MouseEvent): void Sprite (e.currentTarget) .alpha = 1; Sprite (e.currentTarget) .stopDrag ();
En daar heb je het alpha-veranderingseffect.
Het effect heeft veel potentieel dat in verschillende toepassingen kan worden gebruikt. Ik heb onlangs een puzzelspel ontwikkeld om er gebruik van te maken.
Afgezien daarvan kan het worden gebruikt om overgangseffecten voor videospelers te creëren, of in combinatie met 3D om een oppervlak met een video te structureren.
Ik hoop dat ik een aantal leuke dingen zie die mensen bedenken om dit effect te gebruiken!