图片粒子动画

二维粒子 everyinch 7709℃ 0评论

40000个BitmapData粒子的喷射动画很好地体现了BitmapData粒子在性能方面的优势,但视觉效果并不十分理想,能否使用BitmapData粒子实现更炫更复杂的视觉效果呢?下面就让我们模拟图片粒子化的动画效果。完成的效果是首先加载一张位图,单击鼠标后该位图粒子化并上升飞起,再次单击鼠标则向上飞起的粒子又重新生成初始的图片。类文件名为ParticleImage.as,源代码如下:

package{
	import com.particles.Particle2D;

	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.ColorTransform;
	import flash.geom.Point;

	[SWF(width="800", height="600", frameRate="31")]
	public class ParticleImage extends Sprite{
		[Embed(source="assets/portrait.jpg")]
		private var image:Class;

		private var pixels:Array=new Array();
		private var particles:Array=new Array();

		private var portrait:Bitmap;

		private var colorTransform:ColorTransform=new ColorTransform(0.8, 0.8, 0.8, 0.8);
		private var status:Array=new Array();

		private var sw:int=800;
		private var sh:int=600;
		private var bmpd:BitmapData;
		private var bmp:Bitmap;
		private var centerY:Number;
		private var centerX:Number;
		private var rows:int=0;

		public function ParticleImage(){
			stage.addEventListener(MouseEvent.CLICK, onBreakClick);
			initBitmap();
		}

		private function initBitmap():void{
			var x:int=0;
			var y:int=0;
			portrait=new image();
			bmpd=new BitmapData(sw, sh, false, 0);
			centerX=(bmpd.width - portrait.width) / 2;
			centerY=(bmpd.height - portrait.height) / 2;
			bmpd.copyPixels(portrait.bitmapData, portrait.bitmapData.rect, new Point(centerX, centerY), null, new Point(), true);
			bmp=new Bitmap(bmpd);
			addChild(bmp);
			y=0;
			while (y < portrait.height){
				pixels[y]=[];
				particles[y]=[];
				x=0;
				while (x < portrait.width){
					pixels[y].push(portrait.bitmapData.getPixel32(x, y));
					particles[y].push(new Particle2D(centerX + x, centerY + y, 0, 0, 1 + Math.random() * 5));
					x++;
				}
				y++;
			}
		}

		private function onBreakClick(event:MouseEvent):void{
			var xmouse:Number=mouseX;
			var ymouse:Number=mouseY;
			event.currentTarget.removeEventListener(MouseEvent.CLICK, onBreakClick);
			event.currentTarget.addEventListener(MouseEvent.CLICK, onRecoverClick);
			var y:int=0;
			while (y < portrait.height){
				var x:int=0;
				while (x < portrait.width){
					var p:Particle2D=particles[y][x] as Particle2D;
					var dx:Number=p.x - xmouse;
					var dy:Number=p.y - ymouse;
					var square:Number=Math.sqrt(dx * dx + dy * dy);
					var radian:Number=Math.atan2(dy, dx);
					var radius:Number=(10 + Math.random() * 90) * 20 / (20 + square);
					p.vx=p.vx + radius * Math.cos(radian) / p.mass;
					p.vy=p.vy + radius * Math.sin(radian) / p.mass;
					x++;
				}
				y++;
			}
			removeEventListener(Event.ENTER_FRAME, onRecoverEnterFrame);
			addEventListener(Event.ENTER_FRAME, onBreakEnterFrame);
		}

		private function onBreakEnterFrame(e:Event):void{
			bmpd.lock();
			bmpd.colorTransform(bmpd.rect, colorTransform);
			var y:int=0;
			while (y < portrait.height){
				var x:int=0;
				while (x < portrait.width){ 					var p:Particle2D=particles[y][x] as Particle2D; 					if (p.y > -1){
						p.vx=p.vx * 0.98;
						p.vy=p.vy - 1 / p.mass;
						p.update();
					}
					bmpd.setPixel32(p.x, p.y, pixels[y][x]);
					x++;
				}
				y++;
			}
			bmpd.unlock();
		}

		private function onRecoverClick(event:MouseEvent):void{
			event.currentTarget.removeEventListener(MouseEvent.CLICK, onRecoverClick);
			event.currentTarget.addEventListener(MouseEvent.CLICK, onBreakClick);
			rows=0;
			var y:int=0;
			while (y < portrait.height){
				var x:int=0;
				status[y]=[];
				while (x < portrait.width){
					status[y][x]=false;
					x++;
				}
				y++;
			}
			removeEventListener(Event.ENTER_FRAME, onBreakEnterFrame);
			addEventListener(Event.ENTER_FRAME, onRecoverEnterFrame);
		}

		private function onRecoverEnterFrame(event:Event):void{
			bmpd.lock();
			bmpd.colorTransform(bmpd.rect, colorTransform);
			if (rows < portrait.height){
				rows=rows + 2;
			}
			var y:int=0;
			while (y < portrait.height){
				var x:int=0;
				while (x < portrait.width){
					var p:Particle2D=particles[y][x] as Particle2D;
					if (!status[y][x]){
						var px:Number=centerX + x;
						var py:Number=centerY + y;
						if (y < rows){
							p.vx=(px - p.x) / (p.mass * 4);
							p.vy=(py - p.y) / (p.mass * 3);
						}
						p.update();
						if (Math.abs(p.x - px) < 1 && Math.abs(p.y - py) < 1){
							p.x=px;
							p.y=py;
							status[y][x]=true;
						}
					}
					bmpd.setPixel32(p.x, p.y, pixels[y][x]);
					x++;
				}
				y++;
			}
			bmpd.unlock();
		}
	}
}

initBitmap函数用来将嵌入的位图的BitmapData复制到指定的BitmapData中,并将指定的BitmapData添加到显示对象列表。使用双重while循环将位图的每一个像素的颜色存入pixels数组,将每一个像素的位置存入particles数组。
鼠标在舞台上首次单击则触发onBreakClick函数,该函数首先移除onBreakClick事件处理函数并重新添加onRecoverClick事件处理函数,用来响应还原图像的鼠标单击。再移除onRecoverEnterFrame事件处理函数并重新添加onBreakEnterFrame事件处理函数,用来逐帧更新显示,实现图片粒子化的效果。在双重while循环中指定particles数组中每一个粒子的速度。
在onBreakEnterFrame事件处理函数中,重复了实现BitmapData粒子的5个步骤。实现了粒子向上飞起的效果。
当再次在舞台上单击鼠标则执行onRecoverClick事件处理函数,同样切换必要的事件处理函数。即移除onRecoverClick事件处理函数并重新添加onBreakClick事件处理函数,用来响应图像粒子化的鼠标单击。再移除onBreakEnterFrame事件处理函数并重新添加onRecoverEnterFrame事件处理函数,用来逐帧更新显示,实现粒子还原成图片的效果。
在onRecoverEnterFrame事件处理函数中,除了使用实现BitmapData粒子动画的5个步骤之外,还定义了rows变量。每次递增该变量,使粒子逐渐还原成原始的图像,防止出现粒子在中途已经还原好图像的问题。

分享&收藏

转载请注明:陈童的博客 » 图片粒子动画

喜欢 (0)
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
'; } if( dopt('d_footcode_b') ) echo dopt('d_footcode'); ?>