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

forked from: forked from: Saqoosha challenge for professionals(しんしん)

静かな降雪
/**
 * Copyright fatmonk ( http://wonderfl.net/user/fatmonk )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/kFPb
 */

// forked from Aquioux's forked from: Saqoosha challenge for professionals(しんしん)
// forked from checkmate's Saqoosha challenge for professionals
// 静かな降雪
package {
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.BlendMode;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	[SWF(width = "465", height = "465", frameRate = "60", backgroundColor = "#000000")]
	
	public class Main2 extends Sprite {
		// 定数
		private const NUM_OF_FALL:uint = 5;	// 同時に落ちる粒子の数

		private const GRAVITY:Number        =  0.9;		// 重力
		private const BOUNCE:Number         = -0.0;		// 跳ね返り
		private const BEND:Number           =  0.0;		// 跳ね返るときに曲がる率
		private const FRICTION:Number       =  0.45;	// 空気抵抗
		private const FLOOR_FRICTION:Number =  0.0;		// 摩擦抵抗
		private const LOCAL_FRICTION_BOOLEAN:Boolean = true;
		private const BOTTOM:uint = stage.stageHeight - 1;
		
		private const LETTER:String = "しんしん";	// 表示文字列
		
		// パーティクルの色の設定
		private function setParticleColor():uint {
			var c:uint = Math.random() * 0x33 + 0xCC;
			return rgbToHex(c, c, c);
		}

		
		// 変数
		private var particleArray:Array;		// パーティクル格納配列(繰り返し使うために待避)
		private var copyParticleArray:Array;	// パーティクル格納配列(実際に使用する)
		
		private var canvasBitmapData:BitmapData;	// 描画 BitmapData
		private var pixelizer:Pixelizer;			// ピクセル化クラス

		
		// コンストラクタ
		public function Main2() {
			// Particle クラスの初期化
			Particle.gravity       = GRAVITY;
			Particle.bounce        = BOUNCE
			Particle.bend          = BEND;
			Particle.friction      = FRICTION;
			Particle.floorFriction = FLOOR_FRICTION;
			Particle.localFrictionBoolrean = LOCAL_FRICTION_BOOLEAN;
			Particle.top    = 0;
			Particle.bottom = BOTTOM;
			Particle.left   = 0;
			Particle.right  = stage.stageWidth;
			
			// 描画 BitmapData 生成
			canvasBitmapData = new BitmapData(stage.stageWidth, stage.stageHeight, false, 0x000000);
			addChild(new Bitmap(canvasBitmapData));
			
			// 案内表示
			var signField:TextField   = new TextField();
			signField.text = "Stage を Click すると motion を再演します。";
			signField.autoSize   = TextFieldAutoSize.LEFT;
			signField.selectable = false;
			signField.blendMode  = BlendMode.INVERT;
			addChild(signField);

			// テキストピクセライズ
			var pTextField:PixelizerTextField = new PixelizerTextField();
			pTextField.text = LETTER;
			var textFormat:TextFormat = new TextFormat(null, 120);
			textFormat.letterSpacing = -5;
			pTextField.setTextFormat(textFormat);
			pixelizer = new Pixelizer();
			pixelizer.addEventListener(Event.COMPLETE, scanCompleteHandler);
			pixelizer.scan(pTextField.bitmapData);
		}
		
		// ピクセライズ完了後の処理
		// (ピクセル格納配列の生成)
		private function scanCompleteHandler(event:Event):void {
			// イテレータ生成
			var iter:PixelizerIterator = pixelizer.iterator;
			pixelizer = null;
			// 配置オフセット計算
			var offsetX:Number = (stage.stageWidth  - iter.width)  / 2;
			var offsetY:Number = 40;// (stage.stageHeight - iter.height) / 2;
			// イテレーション
			particleArray = [];
			while (iter.hasNext()) {
				var color:uint = iter.next();
				var alpha:uint = getAlpha(color);
				if (alpha > 0x7F) {
					particleArray.push(new Particle(iter.x + offsetX, iter.y + offsetY, setParticleColor()));
				}
			}
			
			// イベント登録
			stage.addEventListener(MouseEvent.CLICK, clickHandler);
			motion();
		}
		
		// 実処理(モーションタイポ)
		private function motion():void {
			// 待避配列から使用配列を生成
			copyParticleArray = [];
			for each (var original:Particle in particleArray) {
				copyParticleArray.push(original.clone());
			}
			// Particle 格納配列をシャッフル
			shuffle(copyParticleArray);
			// 各 particle に動作開始時限値
			var n:uint = copyParticleArray.length;
			for (var i:int = 0; i < n; i++) {
				copyParticleArray[i].counter = i / NUM_OF_FALL;
			}
			
			// イベント登録
			addEventListener(Event.ENTER_FRAME, enterFrameHandler);
		}
		// フレームイベント
		private function enterFrameHandler(event:Event):void {
			canvasBitmapData.lock();
			canvasBitmapData.fillRect(canvasBitmapData.rect, 0x000000);
			for each (var particle:Particle in copyParticleArray) {
				particle.update();
				canvasBitmapData.setPixel(particle.x, particle.y, particle.color);
			}
			canvasBitmapData.unlock();
		}
		// マウスイベント
		private function clickHandler(event:MouseEvent):void {
			removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
			motion();
		}

		// シャッフル
		private function shuffle(a:Array):void {
			var n:int;
			var t:*;
			var l:uint = a.length;
			while (l--) {
				n = Math.floor(Math.random() * (l+1));
				t = a[l];
				a[l] = a[n];
				a[n] = t;
			}
		}
		// RGB → 0xNNNNNN
		private function rgbToHex(r:uint, g:uint, b:uint):uint {
			r = adjust(r);
			g = adjust(g);
			b = adjust(b);

			return r << 16 | g << 8 | b;
		}
		// 255 を超えていた場合は 255 に切り捨てる
		private function adjust(val:uint):uint {
			return Math.min(val, 0xFF);
		}

		// 32 bit color のアルファ値を取得
		private function getAlpha(color:uint):uint {
			return (color >> 24) & 0xFF;
		}
		
	}
	
}

// パーティクルクラス
	class Particle {
		// static 変数
		// 物理変数
		public static var gravity:Number       =  0.98;	// 重力
		public static var bounce:Number        = -0.45;	// 跳ね返り
		public static var bend:Number          =  4.5;	// 跳ね返るときに曲がる率
		public static var friction:Number      =  0.98;	// 空気抵抗
		public static var floorFriction:Number =  0.9;	// 摩擦抵抗
		
		public static var localFrictionBoolrean:Boolean = false;
		
		// ステージ領域
		public static var top:uint;
		public static var bottom:uint;
		public static var left:uint;
		public static var right:uint;


		// 現在座標
		public function get x():Number { return _x; }
		private var _x:Number;
		public function get y():Number { return _y; }
		private var _y:Number;
		// 色
		public function get color():uint { return _color; }
		private var _color:uint;
		
		// 動作開始時限値
		public function set counter(value:uint):void {
			_counter = value;
		}
		private var _counter:uint = 0;
		

		// ローカルな物理変数
		private var localBounce:Number;		// 跳ね返り
		private var localBend:Number;		// 跳ね返るときに曲がる率
		private var localFriction:Number;	// 空気抵抗
		
		// 速度
		private var vx:Number = 0;
		private var vy:Number = 0;


		public function Particle(x:Number, y:Number, color:uint) {
			_x = x;
			_y = y;
			_color = color;
			
			// bounce、bend、friction のローカル補正
			localBounce = bounce + (Math.random() * 2 - 1) / 4;
			localBend = (Math.random() < 0.5) ? bend : -bend;
			localBend += (Math.random() * 2 - 1);
			localFriction = (localFrictionBoolrean) ? friction - Math.random() : friction - Math.random() / 20;
		}
		
		public function clone():Particle {
			return new Particle(_x, _y, _color);
		}
		
		public function update():void {
			if (_counter > 0) {
				_counter--;
			} else {
				// 壁処理
				if (_x > right) {
					_x = right;
					vx *= localBounce;
					vx *= floorFriction;
					localBend *= floorFriction;
					vy = localBend;
				} else if (_x < left) {
					_x = left;
					vx *= localBounce;
					vx *= floorFriction;
					localBend *= floorFriction;
					vy = localBend;
				}
				if (_y > bottom) {
					_y = bottom;
					vy *= localBounce;
					vy *= floorFriction;
					localBend *= floorFriction;
					vx = localBend;
				} else if (_y < top) {
					_y = top;
					vy *= localBounce;
					vy *= floorFriction;
					localBend *= floorFriction;
					vx = localBend;
				}
				// 座標更新
				vx *= localFriction;
				vy *= localFriction;
				vy += gravity;
				_x += vx;
				_y += vy;
			}
		}
	}

// ピクセル化クラス
	import flash.display.BitmapData;
	import flash.events.Event;
	import flash.events.EventDispatcher;

	class Pixelizer extends EventDispatcher {
		private var width:uint  = 0;
		private var height:uint = 0;
		private var data:Vector.<uint>;
		
		// イテレータ
		public function get iterator():PixelizerIterator {
			return new PixelizerIterator(width, height, data);
		}
		
		// コンストラクタ
		public function Pixelizer() {}

		// スキャン
		public function scan(bmd:BitmapData):void {
			width  = bmd.width;
			height = bmd.height;
			data   = bmd.getVector(bmd.rect);

			// イベント発行
			dispatchEvent(new Event(Event.COMPLETE));
		}
	}

// ピクセル化したデータのイテレータ
	class PixelizerIterator {
		// モードフラグ
		public static const NEXT:String = "next";	// 正順
		public static const PREV:String = "prev";	// 逆順

		// next()、nextCol() で取得したデータのX座標
		public function get x():int { return positionX; }
		private var positionX:int = 0;
		// next()、nextRow() で取得したデータのY座標
		public function get y():int { return positionY; }
		private var positionY:int = 0;

		// スキャンサイズ(幅)
		public function get width():uint { return _width; }
		private var _width:uint;
		// スキャンサイズ(高)
		public function get height():uint { return _height; }
		private var _height:uint;

		// データ格納 Vector
		private var data:Vector.<uint>;

		// 現在のイテレートモード
		private var mode:String = "next";
		// イテレーションカウンター
		private var position:int = 0;
		
		
		public function PixelizerIterator(width:uint, height:uint, data:Vector.<uint>) {
			_width  = width;
			_height = height;
			this.data = data;
		}
		
		// データの操作(1個ずつデータを呼び出す)
		// 外部から呼び出せる hasNext
		public function hasNext():Boolean {
			return (mode == "prev") ? _hasPrev() : _hasNext();
		}
		// 外部から呼び出せる next
		public function next():uint {
			return (mode == "prev") ? _prev() : _next();
		}

		// データの同一列(横)の操作(同一列の全てのデータを呼び出す)
		// 外部から呼び出せる hasNext
		public function hasNextRow():Boolean {
			return (mode == "prev") ? _hasPrevRow() : _hasNextRow();
		}
		// 外部から呼び出せる next
		public function nextRow():Vector.<uint> {
			return (mode == "prev") ? _prevRow() : _nextRow();
		}

		// データの同一行(縦)の操作(同一行のすべてのデータを呼び出す)
		// 外部から呼び出せる hasNext
		public function hasNextCol():Boolean {
			return (mode == "next") ? _hasNextCol() : _hasPrevCol();
		}
		// 外部から呼び出せる next
		public function nextCol():Vector.<uint> {
			return (mode == "next") ? _nextCol() : _prevCol();
		}

		// リセット
		public function reset(mode:String = "next"):void {
			this.mode = mode;
			var offset:uint = (mode == "next") ? 0 : 1;
			position  = (data.length - 1) * offset;
			positionX = (_width  - 1) * offset;
			positionY = (_height - 1) * offset;
		}


		// データの操作(1個ずつデータを呼び出す)
		// mode = "next" 時の hasNext
		private function _hasNext():Boolean {
			return position < data.length;
		}
		// mode = "prev" 時の hasNext
		private function _hasPrev():Boolean {
			return position > 0;
		}
		// mode = "next" 時の next
		private function _next():uint {
			positionX = position % _width;
			positionY = position / _width;
			return getData(position++);
		}
		// mode = "prev" 時の next
		private function _prev():uint {
			positionX = position % _width;
			positionY = position / _width;
			return getData(position--);
		}
		private function getData(idx:uint):uint {
			if (idx >= data.length) {
				throw new Error("getData#配列範囲外:" + idx + " length:" + data.length);
			}
			return data[idx];
		}
		
		// データの同一列(横)の操作(同一列の全てのデータを呼び出す)
		// mode = "next" 時の hasNext
		private function _hasNextRow():Boolean {
			return positionY < _height;
		}
		// mode = "prev" 時の hasNext
		private function _hasPrevRow():Boolean {
			return positionY > -1;
		}
		// mode = "next" 時の next
		private function _nextRow():Vector.<uint> {
			return getRow(positionY++);
		}
		// mode = "prev" 時の next
		private function _prevRow():Vector.<uint> {
			return getRow(positionY--);
		}
		// next の実体
		private function getRow(val:uint):Vector.<uint> {
			if (val >= _height) {
				throw new Error("getRow#配列範囲外:" + val + " _height:" + _height);
			}
			return data.slice(val * _width, (val + 1) * _width);
		}
		
		// データの同一行(縦)の操作(同一行のすべてのデータを呼び出す)
		// mode = "next" 時の hasNext
		private function _hasNextCol():Boolean {
			return positionX < _width;
		}
		// mode = "prev" 時の hasNext
		private function _hasPrevCol():Boolean {
			return positionX > -1;
		}
		// mode = "next" 時の next
		private function _nextCol():Vector.<uint> {
			return getCol(positionX++);
		}
		// mode = "prev" 時の next
		private function _prevCol():Vector.<uint> {
			return getCol(positionX--);
		}
		// next の実体
		private function getCol(idx:uint):Vector.<uint> {
			if (idx >= _width) {
				throw new Error("getCol#配列範囲外:" + idx + " _width:" + _width);
			}
			var vector:Vector.<uint> = new Vector.<uint>(_height, true);
			for (var i:uint = 0; i < _height; i++) {
				vector[i] = data[_width * i + idx];
			}
			return vector;
		}
	}

// 文字列をピクセル化クラスへ投げ込むためのテキストフィールド
	import flash.display.BitmapData;
	import flash.geom.Matrix;
	import flash.geom.Rectangle;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;

	class PixelizerTextField extends TextField {
		// 透明
		private const TRANSPARENT:uint = 0x00000000;


		public function PixelizerTextField() {
			autoSize = TextFieldAutoSize.LEFT;
		}

		public function get bitmapData():BitmapData {
			// 普通に TextField を BitmapData に draw
			var bmd1:BitmapData = new BitmapData(textWidth, textHeight, true, TRANSPARENT);
			bmd1.draw(this, new Matrix(1, 0, 0, 1, -2, -2));
			// 上記 BitmapData のうち、文字である範囲を Rectangle として取得
			var rect:Rectangle = bmd1.getColorBoundsRect(0xFF000000, TRANSPARENT, false);
			// 上記 Rectangle 部分のみの BitmapData を生成
			var bmd2:BitmapData = new BitmapData(rect.width, rect.height, true, TRANSPARENT);
			bmd2.draw(bmd1, new Matrix(1, 0, 0, 1, -rect.x, -rect.y));
			bmd1.dispose();

			return bmd2;
		}
	}