Bonjour, freaks de code! Ce tutoriel vous montrera comment scinder une vidéo en cours d'exécution en blocs comme si elle avait explosé. Et tout cela en utilisant seulement ActionScript. Pour ce tutoriel, nous utiliserons l'appareil photo en tant que source vidéo afin que vous puissiez voir les modifications en direct..
Jetons un coup d'œil au résultat final sur lequel nous allons travailler:
Cliquez et faites glisser un bloc pour le déplacer sur l'écran! (Accès à la caméra requis.)
Pour ce tutoriel, nous allons utiliser l'EDI FlashDevelop (bien que vous puissiez utiliser n'importe quel éditeur AS3). Au cas où vous ne l'avez pas et que vous voulez essayer, vous pouvez le récupérer à partir d'ici. Un tutoriel de base sur la configuration de FlashDevelop sur votre machine est disponible ici.
De plus, si Flash Professional est installé sur votre côté, cela fonctionnera également. Tout ce que vous avez à faire est de créer un fichier de classe externe comme indiqué ci-dessous et de le lier à votre projet Flash en tant que classe Document..
Cela met en place notre environnement de travail.
Créer un nouveau projet AS3 dans FlashDevelop.
Quand ce sera fait, vous aurez un Principale
classe créée dans le dossier src, comme indiqué dans le panneau de droite:
Ensuite, nous devons faire la Main.as
déposer un peu plus propre en éliminant du code. Initialement, lorsque vous ouvrez le Main.as
fichier, il aurait du code quelque chose comme ça:
package import flash.display.Sprite; import flash.events.Event; classe publique Main étend Sprite fonction publique Main (): void if (stage) init (); sinon addEventListener (Event.ADDED_TO_STAGE, init); fonction privée init (e: Event = null): void removeEventListener (Event.ADDED_TO_STAGE, init); // point d'accès
Nous allons supprimer une partie du code pour le rendre plus propre. Donc, vous devriez avoir ceci:
package import flash.display.Sprite; import flash.events.Event; classe publique Main étend Sprite fonction publique Main (): void
Maintenant, toute la configuration est terminée et il est temps de plonger dans un code.
Notre premier objectif est de dessiner la vidéo sur scène à l'aide de la caméra. pour cela, nous devons déclarer certaines variables. Mettez ces déclarations juste au-dessus de la Principale
constructeur de classe.
// variables vidéo private var camW: int = 300; var camH privé: int = 300; var vidéo privée: vidéo;
camW
- La largeur de la caméra / vidéo.
camH
- La hauteur de la caméra / vidéo.
vidéo
- Notre Vidéo
instance de classe.
Comme mentionné précédemment, nous utiliserons la sortie de la caméra dans la vidéo. Nous devons donc commencer par préparer l'appareil photo de l'appareil. Le code suivant devrait aller dans le constructeur de la classe.
var camera: Camera = Camera.getCamera ();
Ici, nous instancions un Caméra
instance et obtenir la caméra de périphérique disponible en utilisant la méthode statique getCamera ()
du Caméra
classe.
camera.setMode (camW, camH, 30);
Nous fournissons quelques réglages de caméra: largeur, hauteur et fps.
Notez que nous n'avons pas rendu la variable de caméra globale car nous n'avons pas besoin d'y accéder ailleurs que dans cette fonction, comme vous le verrez ensuite. Dans l'étape suivante, nous initialisons le vidéo
variable.
vidéo = nouvelle vidéo (camW, camH); video.attachCamera (caméra);
Nous avons maintenant instancié le vidéo
variable et utilisé le attachCamera ()
méthode pour y attacher la caméra. Cela signifie que la vidéo utilise maintenant la sortie de la caméra comme source.
Tout est fait avec la vidéo et la caméra. N'oubliez pas que vous devez importer les classes appropriées dans votre code. Votre code de classe complet devrait ressembler à ceci pour le moment:
package import flash.display.Sprite; import flash.events.Event; import flash.media.Camera; import flash.media.Video; classe publique Main étend Sprite // variables vidéo private var camW: int = 300; var camH privé: int = 300; var vidéo privée: vidéo; fonction publique Main (): void var camera: Camera = Camera.getCamera (); camera.setMode (camW, camH, 30); vidéo = nouvelle vidéo (camW, camH); video.attachCamera (caméra);
Si vous exécutez actuellement le projet (F5 ou CTRL + Entrée), il s'agira d'une étape vide, mais vous obtiendrez probablement une demande d'accès à la caméra car l'application tente d'accéder à la caméra du périphérique. Permettez-ceci.
La raison pour laquelle vous ne voyez rien, c'est parce que nous ne voulons pas montrer la vidéo et nous ne l'avons donc pas ajoutée à la scène (liste d'affichage). Il sera simplement utilisé comme source pour nos blocs séparés. Si vous voulez vérifier que tout fonctionne correctement, ajoutez simplement la ligne suivante à la fin du Principale
constructeur:
addChild (vidéo); // supprime cette ligne après le test
Maintenant, nous créons les blocs - les parties distinctes de la vidéo. Et la première étape consiste à déclarer certaines variables nécessaires. Alors allez-y et additionnez les déclarations de variable suivantes juste en dessous des variables vidéo:
// variables de bloc private var rows: int = 3; vars privés: int = 3; private var blockW: int = camW / cols; private var blockH: int = camH / rows; private var pointCollection: Object = new Object ();
rangées
- Nombre de lignes pour diviser la vidéo en.
cols
- Oui. Vous avez ça. Nombre de colonnes dans lesquelles scinder la vidéo.
bloc
- La largeur de chaque bloc. Il s’agit d’une variable dérivée, car elle est simplement calculée en divisant la largeur totale (camW
) par nombre de colonnes (cols
).
bloc
- La hauteur de chaque bloc i.e. camH
divisé par rangées
.
pointCollection
- Variable finale mais la plus importante. C'est un tableau associatif que nous allons utiliser pour stocker le point correspondant de chaque bloc. Par exemple, si un bloc a un nom bloc12
, alors nous stockerions le point correspondant p12
comme ça :
pointCollection ["block12"] = p12; // les points sont des instances de la classe Point ici
Maintenant que nous avons défini les variables requises, nous commençons réellement à créer les blocs. Nous allons garder tout le code de création de bloc dans une fonction appelée initBlocks ()
. Cette fonction sera appelée à partir du Principale
constructeur après avoir réglé la vidéo.
Alors, déclarons d'abord une fonction appelée initBlocks ()
juste après Principale
constructeur.
fonction privée initBlocks (): void pour (var r: int = 0; r < rows; r++) for (var c:int = 0; c < cols; c++) // code to create each block
Remarquez les deux pour
les boucles que nous avons placées à l'intérieur, ce qui nous aidera à créer les blocs dans une grille 2D, en lignes. Et puis ajoutez un appel à cette fonction à la fin de Principale()
:
fonction publique Main (): void var camera: Camera = Camera.getCamera (); camera.setMode (camW, camH, 30); vidéo = nouvelle vidéo (camW, camH); video.attachCamera (caméra); initBlocks ();
Avant de créer les blocs, comprenons en quoi consiste un seul bloc. Chaque bloc est en réalité:
Lutin
Bitmap
à l'intérieurBitmapData
Penser à Lutin
comme conteneur le plus à l'extérieur. Complètement vierge.
Pour dessiner le bloc, il nous faut un Bitmap
qui montrera la sortie vidéo correspondante.
Et enfin, chaque Bitmap
a besoin de quelques données pour y puiser. Cela est donné sous la forme de BitmapData
.
Comme nous en avons discuté, le premier composant d'un bloc est un Sprite. Alors laisse en créer un. Tout le code que nous écrivons pour créer le bloc doit être écrit à l'intérieur du pour
boucles.
var newBlock: Sprite = new Sprite ();
Nous créons une nouvelle instance du Lutin
classe.
newBlock.name = "block" + r + c;
Ensuite, nous nommons le sprite pour pouvoir le référencer plus tard dans le code. La convention de nommage est simple: un bloc à la ligne r et à la colonne c est nommé bloc + r + c
(+ signifie concaténation). Donc, un bloc à la ligne 2 et à la colonne 1 est nommé bloc21
.
Après l'avoir créé, nous devons le positionner sur la scène en fonction de ses rangées et de ses colonnes. Ajoutons donc le code suivant.
var p: Point = nouveau Point (c * blocW, r * blocH);
Nous utilisons un Point
objet de classe pour stocker les coordonnées de tout point ici. Et donc nous créons une nouvelle instance de Point
et passe c * bloc
comme la valeur x et r * blockH
comme la valeur y. Maintenant, les coordonnées peuvent être consultées simplement comme p.x
et p.y
et est utilisé plus tard pour extraire la région rognée de chaque bloc d'une image vidéo complète. Rappelez-vous que le point de chaque bloc correspond aux coordonnées du point en haut à gauche de la grille..
Si vous avez un doute sur le calcul de la position ici, l’illustration suivante indique clairement.
newBlock.x = c * (blockW + 1) + 20; newBlock.y = r * (blockH + 1) + 20;
Ensuite, nous positionnons le sprite. Les ordonnances sont plus ou moins les mêmes que ce à quoi nous nous attendons maintenant nous ajoutons 20 pour donner un décalage. Nous ajoutons aussi 1 à la bloc
et bloc
pour séparer les blocs d'un pixel, comme cela est visible dans la démo ci-dessus.
pointCollection [newBlock.name] = p;
Enfin, nous sauvegardons le point que nous avions calculé plus tôt dans la pointCollection
.
Passons maintenant aux 2ème et 3ème composants du bloc.
var bmpd: BitmapData = new BitmapData (blockW, blockH);
Nous créons d'abord un BitmapData
exemple et passez la largeur de bloc requise et la hauteur que nous avions stockées auparavant. Comme discuté plus tôt, un BitmapData
instance est nécessaire pour créer un Bitmap
instance qui est passée dans le constructeur.
var bmp: Bitmap = new Bitmap (bmpd); bmp.name = "myBmp";
Maintenant, nous créons un Bitmap
instance et passer le précédemment créé bmpd
dans le constructeur. Aussi, nous nommons le bitmap myBmp
afin que nous puissions le référencer plus tard.
newBlock.addChild (bmp); addChild (newBlock);
À la fin nous ajoutons le bitmap bmp
comme un enfant de newBlock
et newBlock
lui-même comme l'enfant de la scène.
Pour être sûr que vous êtes sur la bonne voie, votre Main.as
le code devrait ressembler à ceci:
package import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Sprite; import flash.geom.Point; import flash.media.Camera; import flash.media.Video; classe publique Main étend Sprite // variables vidéo private var camW: int = 300; var camH privé: int = 300; var vidéo privée: vidéo; // variables de bloc private var rows: int = 3; vars privés: int = 3; private var blockW: int = camW / cols; private var blockH: int = camH / rows; private var pointCollection: Array = new Array (); fonction publique Main (): void var camera: Camera = Camera.getCamera (); camera.setMode (camW, camH, 30); vidéo = nouvelle vidéo (camW, camH); video.attachCamera (caméra); initBlocks (); fonction privée initBlocks (): void pour (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);
Même si les blocs sont placés aux bons emplacements, nous ne voyons toujours rien dans la gestion du projet. C'est parce que nous n'avons toujours rien dessiné à l'intérieur des bitmaps de bloc.
Notre prochaine étape consiste à exécuter une boucle à exécution constante qui effectue les opérations suivantes:
Alors? Faisons le!
Avant d’implémenter le code de la boucle, il nous faut une fonction LOOP (un peu comme une boucle de jeu). Ajoutez la déclaration de fonction suivante sous le initBlocks ()
une fonction :
fonction privée updateBlocks (e: Event): void
Comme cela est visible dans le paramètre de fonction, cela ressemble à un écouteur d’événement et oui, c’est vrai. Ceci est une fonction d'écoute que nous allons attacher à la ENTER_FRAME
événement de la scène. Pour attacher l’auditeur, ajoutez cette ligne à la fin du texte. Principale()
constructeur.
fonction publique Main (): void var camera: Camera = Camera.getCamera (); camera.setMode (camW, camH, 30); vidéo = nouvelle vidéo (camW, camH); video.attachCamera (caméra); initBlocks (); addEventListener (Event.ENTER_FRAME, updateBlocks);
C’est la première opération que nous effectuons dans notre boucle - la updateBlocks ()
fonction qui est appelée sur chaque image. Mettez le code suivant à l'intérieur updateBlocks ()
une fonction.
var srcBmpd: BitmapData = new BitmapData (camW, camH);
Toutes les données bitmap dans Actionscript 3.0 doivent être contenues dans un BitmapData
par exemple et nous en créons un. Nous allons peupler cette instance avec les données d'image vidéo actuelles.
srcBmpd.draw (vidéo);
Ici nous avons utilisé le dessiner()
fonction de la BitmapData
classe. Il nécessite un objet de la classe any qui implémente IBitmapDrawable
interface. Pour par exemple. Sprite, MovieClip, BitmapData, etc. Ce que cela fait est simplement prendre les données visuelles de l'objet passé et les stocke dans le BitmapData
exemple.
Alors maintenant, nous avons l'image vidéo actuelle (ou, vous pourriez dire, une capture d'écran) dans la variable srcBmpd
.
Comme nous devons mettre à jour chaque bloc, nous créons un double pour
-boucle, semblable à celle que nous avons écrite pour la création des blocs. Alors allez-y et ajoutez-le.
La fonction devrait ressembler à ceci maintenant:
fonction privée updateBlocks (e: Event): void var srcBmpd: BitmapData = new BitmapData (camW, camH); srcBmpd.draw (vidéo); pour (var r: int = 0; r < rows; r++) for (var c:int = 0; c < cols; c++) // update code here
N'oubliez pas que nous avons nommé les blocs d'une certaine manière lors de leur création afin de pouvoir référencer n'importe quel bloc en utilisant son numéro de ligne et de colonne. C'est ce que nous allons utiliser maintenant pour obtenir la référence de chaque bloc.
var b_mc: Sprite = this.getChildByName ("bloc" + r + c) en tant que Sprite;
Nous utilisons le getChildByName
fonction de la étape
(ce
) qui renvoient une référence à un objet dont le nom correspond à la chaîne transmise. Nous avons aussi transtypé à Lutin
classe juste pour être sûr que l'objet retourné est un Lutin
. Maintenant la référence du bloc est dans la variable b_mc
.
var bmp: Bitmap = b_mc.getChildByName ("myBmp") en tant que Bitmap;
De la même manière, nous récupérons la référence au bitmap ajouté en tant qu'enfant du sprite de bloc..
var p: Point = collectionCollection [b_mc.name];
Enfin, nous obtenons le bloc actuel (b_mc
) coordonnées du tableau dans lequel nous l'avons stocké précédemment en utilisant le nom du bloc.
Maintenant que nous avons toutes les informations requises sur quoi dessiner où, nous pouvons en fait dessiner. Notre motif ici est d’obtenir la région rectangulaire de la trame vidéo (i.e. srcBmpd
) avec le point en haut à gauche comme point récupéré p
, largeur comme bloc
et hauteur comme bloc
.
Pour cela, nous utilisons le copyPixels ()
méthode du BitmapData
classe. Il copie en fait la région d'une autre source BitmapData
spécifié en passant un Rectangle
objet.
bmp.bitmapData.copyPixels (srcBmpd, nouveau Rectangle (p.x, p.y, blockW, blockH), new Point ());
le dessiner()
la fonction est appelée bmp
de bitmapData
propriété. Les paramètres qui y sont passés sont:
BitmapData
obeject. La capture d'écran de la vidéo dans ce cas (srcBmpd
).Rectangle
objet qui spécifie le point en haut à gauche, la largeur et la colonne de la région dans la source à copier. Point
objet. Terminé! Il est maintenant temps de lancer votre projet et de voir l'effet impressionnant.
Pour ajouter la fonctionnalité glisser-déposer comme on le voit dans la démo, il suffit d’attacher deux écouteurs de souris à chaque bloc - un pour le SOURIS VERS LE BAS
événement et un autre pour la MOUSE_UP
un événement. Allez-y, définissez deux fonctions de gestionnaire de souris à la fin de la classe:
fonction privée onMouseDown (e: MouseEvent): void Sprite (e.currentTarget) .startDrag (); fonction privée onMouseUp (e: MouseEvent): void Sprite (e.currentTarget) .stopDrag ();
Tout ce que nous faisons à l’intérieur de ces fonctions d’écoute est d’obtenir la référence au bloc de répartition des événements à l’aide de la touche currentTarget
propriété du un événement
objet, le transtyper en un Lutin
(comme c’est ce que sont nos blocs) et appelez le startDrag ()
et stopDrag ()
gérer le glisser-déposer.
Ce n'est pas encore tout. Nous avons encore besoin d’attacher ces auditeurs aux événements correspondants. Alors ajoutez ces deux lignes à la initBlocks ()
une fonction.
fonction privée initBlocks (): void pour (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);
Une dernière chose juste pour que cela paraisse plus interactif. Vous avez peut-être remarqué comment les blocs entrent et sortent en fondu lorsque vous appuyez dessus, puis les relâchez. C'est une manipulation alpha que nous faisons chez les auditeurs. Modifiez vos auditeurs à quelque chose comme:
fonction privée onMouseDown (e: MouseEvent): void Sprite (e.currentTarget) .alpha = 0.4; Sprite (e.currentTarget) .startDrag (); fonction privée onMouseUp (e: MouseEvent): void Sprite (e.currentTarget) .alpha = 1; Sprite (e.currentTarget) .stopDrag ();
Et voilà l'effet de changement alpha.
L'effet a beaucoup de potentiel pour être utilisé dans diverses applications. J'ai récemment développé un jeu de puzzle.
En dehors de cela, il pourrait être utilisé pour créer des effets de transition pour les lecteurs vidéo, ou en conjonction avec la 3D pour texturer une surface avec une vidéo.
J'espère voir des trucs sympas que les gens trouveront avec cet effet!