まわる炎

by hankuro
papervision3dの存在を知り、Sphereを練習がてら使ってみました。
 ちなみのメインの処理は、相変わらず「Actionscript3.0による数学・物理学表現」(ソフトバンク)のCase10を借用
♥0 | Line 190 | Modified 2009-09-23 05:42:03 | 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/vBPW
 */

package{
 
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Loader;
	import flash.display.Sprite;
	import flash.events.*;
	import flash.net.URLRequest;
	import flash.system.LoaderContext;
	import org.papervision3d.view.BasicView;
	import flash.filters.DropShadowFilter;
	import flash.filters.BevelFilter;
	import flash.filters.BitmapFilterQuality;
	import flash.filters.BitmapFilterType;
	import flash.geom.Point;
	
	[SWF(width = 400, height = 400, backgroundColor = 0x000000)]
	
	//
	// papervision3dの存在を知り、Sphereを練習がてら使ってみました。
	// ちなみのメインの処理は、相変わらず「Actionscript3.0による数学・物理学表現」(ソフトバンク)のCase10を借用
	//
	
	public class Main extends Sprite {	
	
		
		public var ppt:PhysicalPoint;
		public var moonShadow:DropShadowFilter;
		public var moonBevel:BevelFilter;
		public var b:BasicView;
		public var fire:TeraFire;
		
		public var image_l:Loader = new Loader();
		public var image_url:URLRequest = new URLRequest("http://farm3.static.flickr.com/2533/3938035691_7c3ddbc3c1.jpg");
		public var bmp:Bitmap = new Bitmap();
		
		public function Main() {
			var context : LoaderContext = new LoaderContext(true);
			image_l.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded);
			image_l.load(image_url, context);
		}
		public function onImageLoaded(event:Event):void {
			
			bmp = Bitmap(image_l.content);
			ppt = new PhysicalPoint(this.stage.stageWidth/2, this.stage.stageHeight/2);
			moonShadow = new DropShadowFilter(0, 0, 0xFFFFFF, 0.4, 10, 10, 1, BitmapFilterQuality.MEDIUM, false, false, false);
			moonBevel = new BevelFilter(20, 0, 0x000000, 0, 0x333300, 0.5, 10, 10, 1, BitmapFilterQuality.MEDIUM, BitmapFilterType.INNER, false);
			b = new Ball(bmp);
			b.filters = [moonShadow, moonBevel];
			addChild(b);
			fire= new TeraFire(100,100);
			addChild(fire);			
			addEventListener( Event.ENTER_FRAME, onLoop );	
		}
		public function onLoop(evt:Event):void {
			    ppt.setKasokudo((this.mouseX - ppt.x)*10, (this.mouseY - ppt.y)*10);      
				fire.x = ppt.x;
				fire.y = ppt.y;      
				var angle: Number = Math.atan2(this.stage.stageHeight/2 - fire.y,  stage.stageWidth/2 - fire.x)/Math.PI*180;
				var distance: Number = Math.sqrt(Math.pow( stage.stageWidth/2 - fire.x, 2)+Math.pow( this.stage.stageHeight/2- fire.y, 2));
				moonShadow.angle = angle;
				moonShadow.distance = distance/3;
				moonBevel.angle = angle;
				b.filters = [moonBevel, moonShadow];
			
		}
	}
 
}
  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;
    }
  }
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.*;
	import org.papervision3d.objects.DisplayObject3D;

	import org.papervision3d.materials.*;
	import org.papervision3d.materials.utils.MaterialsList;
	import org.papervision3d.objects.parsers.Collada;
	import org.papervision3d.objects.primitives.*;
	import org.papervision3d.view.*;
	import org.papervision3d.scenes.Scene3D;
	import org.papervision3d.cameras.Camera3D;
	import org.papervision3d.render.BasicRenderEngine;
	
	
 
	class Ball extends BasicView {
				

		private var bmp_data:BitmapData;
		public var material:BitmapMaterial ;
		public var sphere:Sphere ;
		
		public function Ball(b:Bitmap):void {
			
			bmp_data = new BitmapData(b.width, b.height);
			bmp_data.draw(b);
			material = new BitmapMaterial( bmp_data );
			material.doubleSided = true;
			sphere = new Sphere(material, 200, 40, 40);
			scene.addChild( sphere );
			startRendering();
			addEventListener( Event.ENTER_FRAME, onLoop );			
		}
		public function onLoop(evt:Event):void {
			sphere.rotationY += 2;
		}
 
	}
	import flash.display.BitmapData;
	import flash.display.GradientType;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.filters.DisplacementMapFilter;
	import flash.filters.DisplacementMapFilterMode;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	//
	// 炎は以下のサイトから借用
	//   http://www.trick7.com/blog/2008/07/27-205806.php
	//
	
	class TeraFire extends Sprite{
		//横方向ゆらぎ速度
		public var phaseRateX:Number;
		//縦方向ゆらぎ速度
		public var phaseRateY:Number;
		private var offsets:Array= [new Point(),new Point()];
		private var seed:Number = Math.random();
		private var fireW:Number;
		private var fireH:Number;
		//火の色
		//private var fireColorIn:uint;
		//private var fireColorOut:uint;

		private var ball:Sprite;
		private var gradientImage:BitmapData;
		private var displaceImage:BitmapData;
		//火の玉の中心の上下位置偏差(-1で上端、1で下端)
		private var focalPointRatio:Number = 0.6;
		//炎の揺らぎのせいで描画エリアをはみ出してしまうのを防ぐための余白幅
		private const margin:int = 10;
		private var rdm:Number;
		
		//コンストラクタ
		public function TeraFire(xPos:Number=0, yPos:Number=0, fireWidth:Number=30, fireHeight:Number=90, fireColorIn:uint = 0xFFCC00,fireColorOut:uint = 0xE22D09){
			fireW = fireWidth;
			fireH = fireHeight;
			phaseRateX = 0;
			phaseRateY = 5;
			var matrix:Matrix = new Matrix();
			matrix.createGradientBox(fireW,fireH,Math.PI/2,-fireW/2,-fireH*(focalPointRatio+1)/2);
			var colors:Array = [fireColorIn, fireColorOut, fireColorOut];
			var alphas:Array = [1,1,0];
			var ratios:Array = [30, 100, 220];
			
			var home:Sprite = new Sprite();
			ball = new Sprite();
			//炎本体
			ball.graphics.beginGradientFill(GradientType.RADIAL,colors, alphas, ratios, matrix,"pad","rgb",focalPointRatio);
			ball.graphics.drawEllipse(-fireW/2,-fireH*(focalPointRatio+1)/2,fireW,fireH);
			ball.graphics.endFill();
			//余白確保用透明矩形
			ball.graphics.beginFill(0x000000,0);
			ball.graphics.drawRect(-fireW/2,0,fireW+margin,1);
			ball.graphics.endFill();
			addChild(home);
			home.addChild(ball);
			this.x = xPos;
			this.y = yPos;
			addEventListener(Event.ENTER_FRAME,loop);
			
			//ゆらぎ用のBitmap(ステージに貼付ける必要はないのでBitmapに貼る必要はない)
			displaceImage = new BitmapData(fireW+margin,fireH,false,0xFFFFFFFF);
			//火の芯付近の揺らぎを抑える用のグラデーション
			var matrix2:Matrix = new Matrix();
			matrix2.createGradientBox(fireW+margin,fireH,Math.PI/2,0,0);
			var gradient_mc:Sprite = new Sprite;
			gradient_mc.graphics.beginGradientFill(GradientType.LINEAR,[0x666666,0x666666], [0,1], [120,220], matrix2);
			gradient_mc.graphics.drawRect(0,0,fireW+margin,fireH);//drawのターゲットなので生成位置にこだわる必要はない。
			gradient_mc.graphics.endFill();
			gradientImage = new BitmapData(fireW+margin,fireH,true,0x00FFFFFF);
			gradientImage.draw(gradient_mc);//gradient_mcを消す必要は?
			//同サイズの炎の揺らぎをランダム化
			rdm = Math.floor(Math.random()*10);
			
			//確認検証用コード
			/*this.startDrag(true);//検証用マウス吸着
			import flash.display.Bitmap; 
			var bmp:Bitmap = new flash.display.Bitmap(displaceImage);
			bmp.x = -fireW/2;
			bmp.y = -fireH*(focalPointRatio+1)/2;
			home.addChild(bmp);
			bmp.alpha = 0.4;//揺らぎマップのコピーを半透明表示(擬似コピーなので揺らぎマップ本体ではない!)
			home.addChild(gradient_mc);//根元の揺らぎ抑えるグラデーションを表示。場所は適当
			*/
		}
		private function loop(e:Event):void{
			//もやもや画像を上スクロール移動させる
			for(var i:int = 0; i < 2; ++i){
				offsets[i].x += phaseRateX;
				offsets[i].y += phaseRateY;
			}
			//もやもやした白黒画像を生成
			displaceImage.perlinNoise(30+rdm, 60+rdm, 2, seed, false, false, 7, true, offsets);
			//芯付近の揺らぎを抑える
			displaceImage.copyPixels(gradientImage,gradientImage.rect,new Point(),null, null, true);
			var dMap:DisplacementMapFilter = new DisplacementMapFilter(displaceImage, new Point(), 1, 1, 20, 10, DisplacementMapFilterMode.CLAMP);
			ball.filters = [dMap];
		}
	}