In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

パーティクルの応用で弾幕3 - 超最適化

コードのリファクタリング & 最適化
* Nicolasが最適化してくれました。
* http://wonderfl.net/code/63f88f2189846bdc7275a01d5d228b1607344e51
* BitmapData#draw() を BitmapData#coloyPixces() に変えるだけ!
* めっちゃ早いよ!これ!
* by coppieee

さらに最適化!
* http://wonderfl.net/code/9dcd5e428a43c4b20f69f86873f2831fa9ec32f3
* に触発されて、私も最適化してみた。Linked listは使いたくなかったので別の方法で。
* これでもか!ってぐらいがんばった。
* 
* Particleのプール用意して、
* 削除のところ工夫して、
* 回転の計算のアルゴリズム変更して、
* とかもろもろ。
* 
* 弾の大きさを変更したのはオマケ。(オマケなんだけど、小さければ小さいほど速くなるよ。)
* きっとこれ以上の最適化は無理だと思うよ!
* 
* 
* _canvas.copyPixels()のところを別の描画のアルゴリズムで置き換えたら、あるいはもっと速く・・・。
* by coppieee
/**
 * Copyright coppieee ( http://wonderfl.net/user/coppieee )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/vCgt
 */

// forked from coppieee's forked from: パーティクルの応用で弾幕2 - 早くなったよ~
// forked from coppieeee's パーティクルの応用で弾幕2 - 早くなったよ~
// forked from coppieeee's 弾幕 - パーティクルの応用で弾幕

/*
 * コードのリファクタリング & 最適化
 * Nicolasが最適化してくれました。
 * http://wonderfl.net/code/63f88f2189846bdc7275a01d5d228b1607344e51
 * BitmapData#draw() を BitmapData#coloyPixces() に変えるだけ!
 * めっちゃ早いよ!これ!
 * by coppieee
 */
/*
 * さらに最適化!
 * http://wonderfl.net/code/9dcd5e428a43c4b20f69f86873f2831fa9ec32f3
 * に触発されて、私も最適化してみた。Linked listは使いたくなかったので別の方法で。
 * これでもか!ってぐらいがんばった。
 * 
 * Particleのプール用意して、
 * 削除のところ工夫して、
 * 回転の計算のアルゴリズム変更して、
 * とかもろもろ。
 * 
 * 弾の大きさを変更したのはオマケ。(オマケなんだけど、小さければ小さいほど速くなるよ。)
 * きっとこれ以上の最適化は無理だと思うよ!
 * 
 * 
 * _canvas.copyPixels()のところを別の描画のアルゴリズムで置き換えたら、あるいはもっと速く・・・。
 * by coppieee
 */

package 
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Graphics;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import net.hires.debug.Stats;
	
	[SWF(width="512",height="512", frameRate="60" )]
	public class PShooting extends Sprite 
	{
		//1fpsあたりの弾の生成数
		public static const BULLET_COUNT:int = 20;
		
		public static const WIDTH:Number = 512;
		public static const HEIGHT:Number = 512;
		
		//弾のビットマップキャッシュ
		private var _bulletImg:BitmapData;
		//キャンバス
		private var _canvas:BitmapData;
		//パーティクルリスト(Vector#unshift()がバグってて使えないので、しょうがないからArray使う。)
		private var _particles:/*Particle*/Array;
		//敵。というか弾の再生位置。
		private var _enemy:Particle;
		//パーティクルプール(いらなくなったパーティクルを溜めとくとこ)
		private var _particlesPool:Vector.<Particle>;
		
		public function PShooting()
		{
			Wonderfl.capture_delay( 7 );
			
			//キャンバスの生成
			_canvas = new BitmapData(WIDTH, HEIGHT,false,0x000000);
			var cb:Bitmap = new Bitmap(_canvas);
			addChild(cb);
			
			_particles = [];
			_enemy = new Particle();
			_particlesPool = new Vector.<Particle>();
			
			//弾のBitmapの生成
			//Shapeに円を書く。
			var shape:Shape = new Shape();
			var g:Graphics = shape.graphics;
			g.beginFill(0x00AAAA, 0.5);
			g.drawCircle(8, 8, 8);
			g.beginFill(0x55EEFF);
			g.drawCircle(8, 8, 4);
			g.endFill();
			
			//BitmapDataにdraw()
			_bulletImg = new BitmapData(shape.width, shape.height, true, 0xFFFFFF);
			_bulletImg.draw(shape);
			
			//Statsの生成
			addChild(new Stats());
			
			addEventListener(Event.ENTER_FRAME, onEnterFrame);
			
			//particlsの個数表示用のTextField生成
			var tf:TextField = new TextField();
			tf.y = 100;
			tf.textColor = 0xFFFFFF;
			tf.background = true;
			tf.backgroundColor = 0x000000;
			tf.autoSize = TextFieldAutoSize.LEFT;
			tf.multiline = true;
			addChild(tf);
			addEventListener(Event.ENTER_FRAME, function(e:Event):void {
				tf.text = "bullets:" + _particles.length +"\n pool:"+_particlesPool.length ;
			});
		}
		private var _radian:Number = 0;
		
		private function onEnterFrame(e:Event):void
		{
			_canvas.lock();
			
            var ct:ColorTransform = new ColorTransform (0.9, 0.9, 0.95);
            _canvas.colorTransform(_canvas.rect, ct);
			//下の方が軽いけど、見た目が悪くなる。
			//_canvas.fillRect(_canvas.rect, 0x000000);
			
			//弾の生成場所をマウスのところへ移動
			_enemy.vx = (stage.mouseX - _enemy.x) * 0.05;
			_enemy.vy = (stage.mouseY - _enemy.y) * 0.05;
			_enemy.x += _enemy.vx;
			_enemy.y += _enemy.vy;
			
			//回転
			_radian += (Math.PI / 180) *62.1;
			var bRadian:Number = _radian;
			//弾の生成
			for (var i:int = 0; i <BULLET_COUNT; i++ )
			{
				var vx:Number = Math.cos(bRadian) * 3;
				var vy:Number = Math.sin(bRadian) * 3;
				var newP:Particle;
				if (_particlesPool.length != 0)
				{
					newP = _particlesPool.pop();
				}else{
					newP = new Particle();
				}
				newP.x = _enemy.x;
				newP.y = _enemy.y;
				newP.vx = vx;
				newP.vy = vy;
				_particles.unshift(newP);
				
				bRadian += Math.PI *2 / BULLET_COUNT;
			}
			
			//必要な計算はforループの前にしておく。
			var bulletRect:Rectangle = _bulletImg.rect;
			var bulletPoint:Point = new Point();
			
			var phi:Number = Math.PI / 180 * 80;
			var cosPhi:Number = Math.cos(phi) * 0.02; //0.02はオマケ
			var sinPhi:Number = Math.sin(phi) * 0.02;
			
			var bWidth_2:int = _bulletImg.width / 2;
			var bHeight_2:int = _bulletImg.height / 2;
			var xMin:int = - bWidth_2 / 2;
			var yMin:int = - bHeight_2 / 2;
			var xMax:int = bWidth_2 + WIDTH;
			var yMax:int = bHeight_2 + HEIGHT;
			
			//弾の移動
			for (var j:int = _particles.length - 1; j != -1 ;j--)
			{
				var p:Particle = _particles[j];
				
				//ベクトルうめぇww
				p.ax = p.vx * cosPhi - p.vy * sinPhi;
				p.ay = p.vy * cosPhi + p.vx * sinPhi;
				p.x += p.vx;
				p.y += p.vy;
				p.vx += p.ax;
				p.vy += p.ay;
				
				//画面外に出たら削除
				if (p.x < xMin || p.x > xMax || p.y < yMin || p.y > yMax)
				{
					_particlesPool.push(p);
					_particles.splice(j, 1);
					continue;
				}
				
				bulletPoint.x = p.x - bWidth_2;
				bulletPoint.y = p.y - bHeight_2;
				_canvas.copyPixels(_bulletImg, bulletRect, bulletPoint);
			}
			_canvas.unlock();
		}
	}
}

class Particle
{
	public var x:Number = 0;
	public var y:Number = 0;
	public var vx:Number = 0;
	public var vy:Number = 0;
	public var ax:Number = 0;
	public var ay:Number = 0;
}