drawTrianglesを使用して画像を自由変形する

画像を自由変形するエフェクトを作成しました。


Flash Player10の機能のdrawTrianglesを使いました。


実行結果はwonderflにアップしています。
wonderfl build flash online | 面白法人カヤック


今は10×10の点の位置を指定して、
画像を変形させています。
点の位置指定は適当な式を入れて変形しています。
もっと思いどおりに変形できればいいんだけど・・・。


ソースは一応載せておきます。

package {
	import __AS3__.vec.Vector;
	
	import flash.display.Bitmap;
	import flash.display.Graphics;
	import flash.display.Sprite;
	
	[SWF(width=800, height=600, backgroundColor=0xAADDFF)]

	public class Main03 extends Sprite {
		
		[Embed(source="images/school.jpg")] private var P1:Class;
		private var image:Bitmap = new P1();
		
		private var bendImage:Sprite = new Sprite();
		
		public function Main03() {
			bendImage.x = 50;
			bendImage.y = 50;
			addChild(bendImage);
			createBendImage();
		}
		
		private function createBendImage():void {
			var vertices:Vector.<Number> = new Vector.<Number>();
			var indices:Vector.<int> = new Vector.<int>();
			var uvtData:Vector.<Number> = new Vector.<Number>();
			
			for (var xx:int=0; xx<10; xx++) {
				for (var yy:int=0; yy<10; yy++) {
					vertices[vertices.length] = xx*50-(5-yy)*(5-yy)*5*(xx<5? 1 : -1);
					vertices[vertices.length] = yy*50;
					uvtData[uvtData.length] = xx/10;
					uvtData[uvtData.length] = yy/10;
				}
			}
			
			for (var i:int=0; i<10-1; i++) {
				for (var j:int=0; j<10-1; j++) {
					indices.push(i*10+j, i*10+j+1, (i+1)*10+j);
					indices.push(i*10+j+1, (i+1)*10+1+j, (i+1)*10+j);
				}
			}
			
			const g:Graphics = bendImage.graphics;
			g.beginBitmapFill(image.bitmapData);
			g.drawTriangles(vertices, indices, uvtData);
			g.endFill();
		}
		
	}
}

爆発エフェクト

爆発のエフェクトを作成しました。


爆発のエフェクトの作成手順は、

    1. 円が飛び散るだけのアニメーションを作成する。
    2. その円にBlurFilterをかける。
    3. 円のBlendModeをADDに設定する。

です。


実行結果は、wonderflに上げました。
wonderfl build flash online | 面白法人カヤック


ソースは以下に掲載します。

package {
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	
	[SWF(width=800, height=600, backgroundColor=0xAADDFF)]

	public class Main04 extends Sprite {
		
		public function Main04() {
			stage.addEventListener(MouseEvent.CLICK, onClick);
		}
		
		private function onClick(event:MouseEvent):void {
			var burst:Burst = new Burst();
			burst.x = event.stageX - burst.width/2;
			burst.y = event.stageY - burst.height/2;
			addChild(burst);
			
			burst.addEventListener(BurstEvent.COMPLETE, onFinishBurst);
		}
		
		private function onFinishBurst(event:BurstEvent):void {
			removeChild(event.currentTarget as DisplayObject);
		}
		
	}
}

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display.Graphics;
import flash.filters.BlurFilter;
import flash.events.Event;
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.display.BlendMode;

class Burst extends Bitmap {
	
	private var particleDesign:Sprite = new Sprite();
	private var particleList:Array = [];
	
	public function Burst() {
		var tempBmp:BitmapData = new BitmapData(200, 200, true, 0x00000000);
		super(tempBmp);
		
		// パーティクルのデザインを作成する
		createParticleDesign();
		
		// パーティクルを作成する
		createParticle();
		
		addEventListener(Event.ENTER_FRAME, onEnterFrame);
	}
	
	private function createParticleDesign():void {
		// 円を描く
		const g:Graphics = particleDesign.graphics;
		g.beginFill(0xFF8022, 0.5);
		g.drawCircle(0, 0, 10);
		g.endFill();
		
		// ぼかし効果を適用する
		particleDesign.filters = [new BlurFilter(10, 10, 1)];
	}
	
	private function createParticle():void {
		for (var i:int=0; i<50; i++) {
			var x:int = bitmapData.width/2;
			var y:int = bitmapData.height/2;
			var v:Number = Math.random()*5;
			var angle:uint = Math.random()*360;
			var ax:Number = 0;
			var ay:Number = 0;
			var enagy:Number = 1;
			var particle:Particle = new Particle(x, y, v, angle, ax, ay, enagy);
			particleList[particleList.length] = particle;
		}
		
		if (particleList.length <= 0) {
			removeEventListener(Event.ENTER_FRAME, onEnterFrame);
			dispatchEvent(new BurstEvent(BurstEvent.COMPLETE));
		}
	}
	
	private function onEnterFrame(event:Event):void {
		bitmapData.colorTransform(bitmapData.rect, new ColorTransform(1, 1, 1, 1, 0, 0, 0, -32));
		for (var i:int=particleList.length-1; i>-1; i--) {
			var particle:Particle = Particle(particleList[i]);
			particle.move();
			var mat:Matrix = new Matrix();
			mat.translate(particle.x, particle.y);
			bitmapData.draw(particleDesign, mat, new ColorTransform(1, 1, 1, particle.enagy), BlendMode.ADD);
			if (particle.enagy < 0.01) {
				particleList.splice(i, 1);
			}
		}
	}
	
}

class BurstEvent extends Event {
	
	public static const COMPLETE:String = "complete";
	
	public function BurstEvent(type:String) {
		super(type);
	}
}

class Particle {
	
	public var x:Number;
	public var y:Number;
	private var vx:Number;
	private var vy:Number;
	private var ax:Number;
	private var ay:Number
	public var enagy:Number;
	
	public function Particle(x:int, y:int, v:Number, angle:uint, ax:Number, ay:Number, enagy:Number) {
		this.x = x;
		this.y = y;
		this.vx = Math.cos(angle*Math.PI/180) * v;
		this.vy = Math.sin(angle*Math.PI/180) * v;
		this.ax = ax;
		this.ay = ay;
		this.enagy = enagy;
	}
	
	public function move():void {
		x += vx;
		y += vy;
		
		vx += ax;
		vy += ay;
		
		enagy *= 0.9;
	}
	
}

右クリックのメニューを作成するContextMenuクラス

こんなクラスがあったんですね。
右クリックのメニューは変更できないと思っていました。


しかも、Spriteごとに設定できるようで使い勝手もよさそうです。
問題点は、Flashの右クリックのメニューは表示されるところかな?


右クリックのメニューを変更したソースを載せておきます。
右クリックすると、テスト1・テスト2・テスト3という項目が増えています。

package {
	import flash.display.Sprite;
	import flash.ui.ContextMenu;
	import flash.ui.ContextMenuItem;
	
	[SWF(width=800, height=600, backgroundColor=0xAADDFF)]

	public class Main04 extends Sprite {
		
		public function Main04() {
			var menu:ContextMenu = new ContextMenu();
			menu.customItems.push(new ContextMenuItem("テスト1"));
			menu.customItems.push(new ContextMenuItem("テスト2"));
			menu.customItems.push(new ContextMenuItem("テスト3"));
			menu.hideBuiltInItems();
			contextMenu = menu;
		}
		
	}
}

気になったサイト

wonderfl build flash online | 面白法人カヤック
オンラインでSWFを生成できるサイト。
ソースもWeb上で編集できます。


コミュニティー的なもので、
他人が作成したSWFやソースを見ることができ、
それを改良したものを作ったりとかして、
コミュニケーションをとれるらしい。
大変いいサイトだよwww


登録していても、損はないと思いましたw

BitmapDataで残像エフェクト

BitmapDataを使って残像エフェクトを作成しました。


やり方は簡単。
残像エフェクトを適用したいオブジェクトを
BitmapDataにdrawしていくだけ。


それだけだと、
残像が消えないので、1つ処理を加えます。


BitmapDataクラスのcolorTransformメソッドを使って、
現在drawされているものを半透明にする。

afterBitmapData.colorTransform(afterBitmapData.rect, 
	new ColorTransform(1, 1, 1, 1, 0, 0, 0, -16));
			
var mat:Matrix = new Matrix();
mat.translate(character.x, character.y);
afterBitmapData.draw(character, mat);



こんな感じですね^^
次にdrawするものは、半透明にならないので、
残像を作るにはぴったりのメソッドだと思いました。


一応、ソースコード載せておきます。

package {
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.PixelSnapping;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
	
	[SWF(width=800, height=600, backgroundColor=0xAADDFF)]

	public class Main17 extends Sprite {
		
		private var afterBitmapData:BitmapData = new BitmapData(800, 600, true, 0x00FFFFFF);
		private var afterImage:Bitmap = new Bitmap(afterBitmapData, PixelSnapping.AUTO, true);
		private var character:Character = new Character();
		
		public function Main17() {
			addChild(afterImage);
			
			character.x = 200;
			character.y = 200;
			addChild(character);
			
			addEventListener(Event.ENTER_FRAME, onEnterFrame);
		}
		
		private function onEnterFrame(event:Event):void {
			character.move();
			
			afterBitmapData.colorTransform(afterBitmapData.rect, 
						new ColorTransform(1, 1, 1, 1, 0, 0, 0, -16));
			
			var mat:Matrix = new Matrix();
			mat.translate(character.x, character.y);
			afterBitmapData.draw(character, mat);
		}
		
	}
}

import flash.display.Sprite;
import flash.events.Event;

class Character extends Sprite {
	
	private var isStage:Boolean = false;
	private var vx:Number = 5;
	private var vy:Number = 5;
	
	public function Character() {
		graphics.beginFill(0x0000FF);
		graphics.drawCircle(0, 0, 50);
		graphics.endFill();
		
		graphics.beginFill(0x00FF00);
		graphics.drawCircle(0, 0, 20);
		graphics.endFill();
		
		addEventListener(Event.ADDED_TO_STAGE, onAddedStage);
	}
	
	public function move():void {
		x += vx;
		y += vy;
		
		if (isStage) {
			if (x < 0+width/2 || x > stage.stageWidth-width/2) {
				vx *= -1;
			}
			if (y < 0+height/2 || y > stage.stageHeight-height/2) {
				vy *= -1;
			}
		}
	}
	
	private function onAddedStage(event:Event):void {
		isStage = true;
	}
	
}

気になった記事

かなり前の記事だけど・・・。


パーリンノイズを使った焼けるエフェクト - PHP,MySQL,Flex,JSな日々+イラストとか
パーリンノイズを使用して、
画面が焼けおちていくのを実装しているようです。
閾値を上げていくことで、画面を透明化するアルゴリズムは、
すごいと思いました。
これを使えば、いろいろなエフェクト作成できるかもしれません。
画面遷移のエフェクトにかなり有効的だと思いました。