揺らめく画像

by hankuro
drawTrianglesにて旗が揺らめくロジックを考察中に、既存ロックの組み合わせで、マウスの動きで画像が淀み元に戻る、ロジックができた。
 *  マウス早く動かすと変化量が少なくゆっくり動かすと変化量が大きくなります。
♥0 | Line 191 | Modified 2009-09-18 18:01:33 | MIT License
play

ActionScript3 source code

/**
 * Copyright hankuro ( http://wonderfl.net/user/hankuro )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/gSMB
 */

package 
{
import flash.display.Bitmap;
	import flash.display.* ;
	import flash.events.*;
	import flash.geom.Point;
	import flash.net.URLRequest;
	import flash.system.LoaderContext;
	import flash.system.Security;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.utils.Timer;
	
	[SWF(width=340, height=240, backgroundColor=0xFFFFFF)]
	
	/**
	 *  drawTrianglesにて旗が揺らめくロジックを考察中に、既存ロックの組み合わせで、マウスの動きで画像が淀み元に戻る、ロジックができた。
         *  マウス早く動かすと変化量が少なくゆっくり動かすと変化量が大きくなります。
	 */
	public class Main extends Sprite 
	{
		public var vertices:Vector.<Number>;
		public var indices:Vector.<int>;
		public var uvtData:Vector.<Number>;
		
		public var vertices_init:Array;
		public var vertices_kasokudo:Array;
	
		public var bmp:Bitmap = new Bitmap();
		public var sh:Shape = new Shape();
		public var sp:Sprite = new Sprite();
		public var bm_data:BitmapData;
		
		private const DIV_w:int = 30;
		private const DIV_h:int = 20;
		
		public var m_obj:Main;
		
		public var i:Number,
				   j:Number,
				   stepW:Number, // 幅
				   stepH:Number; // 高さ
				   
		public var imgLoader:Loader;
        public var urlReq:URLRequest;
		
		public var m_x:Number = 0;
		public var m_y:Number = 0;
		
		public var timer:Timer;
		
		public var maxDist:Number
		public var out_sw:Boolean = false;
			
		public function Main():void 
		{
			var context : LoaderContext = new LoaderContext(true);
			imgLoader = new Loader();
         	urlReq = new URLRequest("http://farm3.static.flickr.com/2627/3922415094_35afc00424.jpg");
         	imgLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded);
         	imgLoader.load(urlReq,context);
		}
		public function onImageLoaded(event:Event):void {
			imgLoader.width = 300;
			imgLoader.height = 200;
			bmp = Bitmap(imgLoader.content);
			var c_bmp:Bitmap = new Bitmap(bmp.bitmapData.clone());
			bm_data = new BitmapData(imgLoader.width, imgLoader.height);
			bm_data.draw(c_bmp);
			stepW = imgLoader.width / DIV_w, // 
			stepH = imgLoader.height / DIV_h;// 高さ
			sh.x = sh.y = 20;
			addChild(sh);
			var scr:Sprite = new Sprite();
			scr.graphics.beginFill(0x0000FF, 0.1);
			scr.graphics.drawRect(0, 0, imgLoader.width + 40, imgLoader.height + 40);
			scr.graphics.endFill();
			addChild(scr);
			scr.addEventListener(MouseEvent.MOUSE_OVER,onOver);
			scr.addEventListener(MouseEvent.MOUSE_OUT,onOut);
			addEventListener(Event.ENTER_FRAME, onLoop);
			vertices_init = new Array(DIV_h);
			vertices_kasokudo = new Array(DIV_h);
			for (i = 0; i < DIV_h; i++ ) {
				vertices_init[i] = new Array(DIV_w);
				vertices_kasokudo[i] = new Array(DIV_w);
				for (j = 0; j < DIV_w; j++ ) {
					//  vertices,indices,uvtDataの値設定ロジックは
					//  「drawTrianglesとUVマッピング #3」さんから借用
					//  http://www.scratchbrain.net/blog/ver2/entries/000900.html
					
					vertices_init[i][j] = new Array(4);
					vertices_kasokudo[i][j] = new Array(4);
					vertices_init[i][j][0] = new Point(	j * stepW, i * stepH);                  			// 頂点 0(左上) 
					vertices_init[i][j][1] = new Point(	(j + 1) * stepW, i * stepH);	        			// 頂点 1(右上)
					vertices_init[i][j][2] = new Point(	(j + 1) * stepW, (i + 1) * stepH);					// 頂点 2(右下)
					vertices_init[i][j][3] = new Point(	j * stepW,	(i + 1) * stepH);  	        			// 頂点 3(左下)
					vertices_kasokudo[i][j][0] = new PhysicalPoint(	j * stepW, i * stepH);                  // 頂点 0(左上) 
					vertices_kasokudo[i][j][1] = new PhysicalPoint(	(j + 1) * stepW, i * stepH);	        // 頂点 1(右上)
					vertices_kasokudo[i][j][2] = new PhysicalPoint(	(j + 1) * stepW, (i + 1) * stepH);		// 頂点 2(右下)
					vertices_kasokudo[i][j][3] = new PhysicalPoint(	j * stepW,	(i + 1) * stepH);  	        // 頂点 3(左下)			
				}
			}
		}
		public function onLoop(evt:Event):void {
			var stepInd:Number = 0;
			vertices = new Vector.<Number>();
			indices = new Vector.<int>();
			uvtData = new Vector.<Number>();
			sh.graphics.clear();
			var n:Number = 0;
			for(i = 0; i<DIV_h; i++ ){
				// 横方向のループ
				for (j = 0; j < DIV_w; j++ ) {
					for (var h:Number = 0; h < 4; h++) {
						// 画像をマウスで動作させるロジックは
						// 「ActionScript3.0 による数学・物理学表現[入門編] 古堅真彦 著(ソフトバンク)
						// 「Case12 大量のオブジェクトを物理法則で動かす」を借用
						// 	maxDistの値は元々は50だったが、変化量がおおきかった為30に変更
						
						vertices_kasokudo[i][j][h].setKasokudo(
						((vertices_init[i][j][h].x - vertices_kasokudo[i][j][h].x) * 10 ) ,
						((vertices_init[i][j][h].y - vertices_kasokudo[i][j][h].y) * 10 ));
						maxDist = 30;
						if (out_sw) {
							m_x = this.mouseX;
							m_y = this.mouseY;
						}else {
							m_x = imgLoader.width + maxDist * 2 ;
							m_y = imgLoader.height + maxDist * 2;
						}						
						if (m_x < 0 ) m_x = 0;
						if (m_y < 0 ) m_y = 0;
						var dist:Number = Point.distance(new Point(m_x, m_y), vertices_kasokudo[i][j][h]);
						if (dist < maxDist) {
							var par:Number = (maxDist - dist) / maxDist;
							vertices_kasokudo[i][j][h].setKasokudo(((vertices_kasokudo[i][j][h].x - m_x) * par * 50),
															((vertices_kasokudo[i][j][h].y - m_y) * par * 50));
						}
					}
				}
			}
			for(i = 0; i<DIV_h; i++ ){
				// 横方向のループ
				for(j = 0; j<DIV_w; j++ ){
				// 頂点の座標データセット

				vertices.push(
								vertices_kasokudo[i][j][0].x,
								vertices_kasokudo[i][j][0].y,
								vertices_kasokudo[i][j][1].x,
								vertices_kasokudo[i][j][1].y,
								vertices_kasokudo[i][j][2].x,
								vertices_kasokudo[i][j][2].y,
								vertices_kasokudo[i][j][3].x,
								vertices_kasokudo[i][j][3].y	
				);
				// 描画の順序データセット
				indices.push(stepInd,stepInd+1,stepInd+3,stepInd+1,stepInd+2,stepInd+3);
				stepInd += 4;
				// UVマッピングデータセット
				uvtData.push(
								j / DIV_w,	     //頂点 0(左上)U
								i / DIV_h,	     // V
								(j+1) / DIV_w,	 //頂点 1(右上)U
								i / DIV_h,	     // V
								(j+1) / DIV_w,	 //頂点 2(右下)U
								(i+1) / DIV_h,	 // V
								j/DIV_w,		 //頂点 3(左下)U
								(i+1) / DIV_h);	 // V
				}
			}
			sh.graphics.beginBitmapFill(bm_data);
			sh.graphics.drawTriangles(vertices,indices,uvtData);
			sh.graphics.endFill();
		}
		public function onOut(evt:MouseEvent):void {
			out_sw = false;
		}
		public function onOver(evt:MouseEvent):void {
			out_sw = true;
		}
	}
	
	
}

  import flash.utils.Timer;
  import flash.events.TimerEvent;
  import flash.geom.Point;

  class PhysicalPoint extends Point{
    public var vx:Number, vy:Number;
    private var ax:Number, ay:Number;
    public var b:Number;
    public var sakkiTime:Number;
    public var timer:Timer;
    
    public function PhysicalPoint(xx: Number=0, yy: Number=0){
      x = xx;      y = yy;
      b = 0.9;
      vx = 0;      vy = 0;
      ax = 0;      ay = 0;
      sakkiTime = new Date().getTime();
      
      timer = new Timer(33);
      timer.addEventListener(TimerEvent.TIMER, loop);
      timer.start();
    }

    public function loop(event:TimerEvent):void{
      var nowTime:Number = new Date().getTime();
	  var t:Number = (nowTime - sakkiTime) / 1000;
	  // 経過秒tが0.1以上になると画像にひび割れが発生するためtのmax値を0.1にした。
	  // ちなみにこの0.1の根拠はどこにもない。実験から導き出した。
	  
	  if (t > 0.1) t = 0.1;

      
      x += vx*t + 0.5*ax*t*t;
      y += vy*t + 0.5*ay*t*t;
      
      vx += ax*t;
      vy += ay*t;
      
      vx *= b;
      vy *= b;
      
      ax = 0;
      ay = 0;
      
      sakkiTime = nowTime;
    }
    
    public function setKasokudo(aax:Number=0, aay:Number=0):void{
      ax += aax;
      ay += aay;
    }
  }