Forked from: Aquioux's Clifford Attractor (A) diff:1 forked from: Clifford Attractor (A) harema forked:0favorite:0lines:304license : MIT License modified : 2011-03-16 04:57:28 Embed Tweet // forked from Aquioux's Clifford Attractor (A) package { import caurina.transitions.Tweener; import flash.display.Sprite; import flash.events.Event; [SWF(width = "465", height = "465", frameRate = "30", backgroundColor = "#000000")] /** * Clifford Attractor Pattern A * @see http://aquioux.net/blog/?p=1322 * @author Aquioux(YOSHIDA, Akio) */ public class Main extends Sprite { private var viewer:Viewer; // ビューア private var buttons:Buttons; // ボタン private var sliders:Sliders; // スライダー public function Main():void { setup(); addEventListener(Event.ENTER_FRAME, update); } // セットアップ private function setup():void { // ステージサイズ var w:int = stage.stageWidth; var h:int = stage.stageHeight; // アトラクターエンジン初期化 Attractor.setup(); // Attractor.paramRandom(); // ビューアの作成 viewer = new Viewer(); viewer.setup(w, h); addChild(viewer); // ボタンの作成 buttons = new Buttons(); buttons.setup(); buttons.action = drawByButton; buttons.y = h - 40; addChild(buttons); // スライダーの作成 sliders = new Sliders(); sliders.setup(); sliders.action = drawBySlider; sliders.reset(); addChild(sliders); } // アップデート private function update(e:Event):void { viewer.update(Attractor.update()); } // ボタンに起因する描画の実行 // アトラクタの変数の値をトゥイーン private function drawByButton(values:Vector.<Number>):void { Tweener.addTween(Attractor, { "a":values[0], "b":values[1], "c":values[2], "d":values[3], time:1.5, transition:"easeOutCubic", onStart:viewer.reset, onUpdate:sliders.reset }); } // スライダーに起因する描画の実行 private function drawBySlider():void { buttons.reset(); } } } //package { /** * アトラクターエンジン(Clifford Attractor) * @author Aquioux(YOSHIDA, Akio) */ /*public*/ class Attractor { /** * アトラクター計算に使用するパラメータ a */ static public function get a():Number { return _a; } static public function set a(value:Number):void { _a = value; } static private var _a:Number; /** * アトラクター計算に使用するパラメータ b */ static public function get b():Number { return _b; } static public function set b(value:Number):void { _b = value; } static private var _b:Number; /** * アトラクター計算に使用するパラメータ c */ static public function get c():Number { return _c; } static public function set c(value:Number):void { _c = value; } static private var _c:Number; /** * アトラクター計算に使用するパラメータ d */ static public function get d():Number { return _d; } static public function set d(value:Number):void { _d = value; } static private var _d:Number; /** * アトラクター計算に使用する各パラメータの最小値、最大値、既定値 */ static public function get A_MIN():Number { return PARAMS[0]; } static public function get A_MAX():Number { return PARAMS[1]; } static public function get A_DEFAULT():Number { return PARAMS[2]; } static public function get B_MIN():Number { return PARAMS[3]; } static public function get B_MAX():Number { return PARAMS[4]; } static public function get B_DEFAULT():Number { return PARAMS[5]; } static public function get C_MIN():Number { return PARAMS[6]; } static public function get C_MAX():Number { return PARAMS[7]; } static public function get C_DEFAULT():Number { return PARAMS[8]; } static public function get D_MIN():Number { return PARAMS[9]; } static public function get D_MAX():Number { return PARAMS[10]; } static public function get D_DEFAULT():Number { return PARAMS[11]; } static private const PARAMS:Vector.<Number> = Vector.<Number>([ -3.0, 3.0, -1.4, // a -3.0, 3.0, 1.6, // b -2.0, 2.0, -2.0, // c -2.0, 2.0, 0.7, // d ]); /** * パーティクル数 */ static public function get numOfParticle():int { return numOfParticle_; } static private var numOfParticle_:int = 25000; // update() の返り値となる Vector static private var data_:Vector.<Number>; // 漸化式用変数 static private var x_:Number; // X座標値 static private var y_:Number; // Y座標値 /** * セットアップ */ static public function setup():void { // update() の返り値となる Vector data_ = new Vector.<Number>(numOfParticle_ * 2, true); // 各パラメータの値を初期化 paramDefault(); } /** * パラメータ a, b, c, d を既定値に戻す */ static public function paramDefault():void { _a = A_DEFAULT; _b = B_DEFAULT; _c = C_DEFAULT; _d = D_DEFAULT; } /** * パラメータ a, b, c, d をランダムな値にする */ static public function paramRandom():void { _a = Math.random() * (A_MAX - A_MIN) + A_MIN; _b = Math.random() * (B_MAX - B_MIN) + B_MIN; _c = Math.random() * (C_MAX - C_MIN) + C_MIN; _d = Math.random() * (D_MAX - D_MIN) + D_MIN; } /** * アトラクター計算 * @return 結果の座標を一次元配列で格納した Vector */ static public function update():Vector.<Number> { x_ = Math.random() * 10 - 5; y_ = Math.random() * 10 - 5; if (Math.random() < 0.5 ) x_ = -x_; if (Math.random() < 0.5 ) y_ = -y_; var len:int = numOfParticle_ * 2; for (var i:int = 0; i < len; i += 2) { var xn:Number = Math.sin(_a * y_) + _c * Math.cos(_a * x_); var yn:Number = Math.sin(_b * x_) + _d * Math.cos(_b * y_); data_[i] = xn; data_[i + 1] = yn; x_ = xn; y_ = yn; } return data_; } } //} //package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.filters.BitmapFilterQuality; import flash.filters.BlurFilter; import flash.geom.ColorTransform; import flash.geom.Point; import flash.geom.Rectangle; /** * ビューア * @author Aquioux(YOSHIDA, Akio) */ /*public*/ class Viewer extends Bitmap { /** * ColorTransform によるフェードアウトのための定義 */ public function set fade(value:ColorTransform):void { _fade = value; } private var _fade:ColorTransform = new ColorTransform(0.95, 0.95, 0.95); /** * Blur filter によるフェードアウトのための定義 */ public function set blur(value:BlurFilter):void { _blur = value; } private var _blur:BlurFilter = new BlurFilter(8, 8, BitmapFilterQuality.HIGH); // 描画色用の変数 private var start_:Number = 0.0; // 開始位置 private var add_:Number = 0.5; // start_ への増分 private var renge_:Number = 150 / 360; // 循環色相の範囲(角度) private var dir_:int = 1; // グラデーションの方向 // BitmapData 関連 private var bufferBmd_:BitmapData; // バッファ private var rect_:Rectangle; // ColorTransform, Blur 共用 private const ZERO_POINT:Point = new Point(0, 0); // 表示オフセット private var offsetX_:Number; // X座標オフセット private var offsetY_:Number; // Y座標オフセット private const OFFSET_SCALE:int = 50; // スケールオフセット /** * コンストラクタ */ public function Viewer() { } /** * セットアップ * @param sw ステージ幅 * @param sh ステージ高 */ public function setup(sw:Number, sh:Number):void { // BitmapData 関連 bufferBmd_ = new BitmapData(sw, sh, true, 0xFF000000); bitmapData = bufferBmd_.clone(); rect_ = new Rectangle(0, 0, sw, sh); // 各オフセット offsetX_ = sw / 2; offsetY_ = sh / 2; // 描画色関連 reset(); // 描画色のアルファ値を設定 CycleRGB.alpha = 0xCC; } /** * アップデート * @param data 描画座標データ */ public function update(data:Vector.<Number>):void { // bufferBmd_ の更新 bufferBmd_.lock(); bufferBmd_.fillRect(bufferBmd_.rect, 0x00000000); var len:uint = data.length; start_ += add_; for (var i:int = 0; i < len; i += 2) { var px:Number = (data[i] * OFFSET_SCALE + offsetX_) >> 0; var py:Number = (data[i + 1] * OFFSET_SCALE + offsetY_) >> 0; var offsetColor:Number = (px + py * dir_) * renge_; //var offsetColor:Number = (px * height / width - py * width / height) * renge_; bufferBmd_.setPixel32(px, py, CycleRGB.getColor32(offsetColor + start_)); } bufferBmd_.unlock(); // bitmapData の更新 bitmapData.lock(); bitmapData.colorTransform(rect_, _fade); bitmapData.applyFilter(bitmapData, rect_, ZERO_POINT, _blur); bitmapData.draw(bufferBmd_); bitmapData.unlock(); } /** * 描画色用変数の再設定 */ public function reset():void { start_ = (Math.random() * 360) >> 0; add_ = ((Math.random() * 100 + 10) >> 0) / 100; renge_ = ((Math.random() * 180 + 30) >> 00) / 360; dir_ = (Math.random() < 0.5) ? -1 : 1; dir_ = (Math.random() < 0.3) ? dir_ : 0; } } //} //package { import com.bit101.components.HUISlider; import flash.display.Sprite; import flash.events.Event; /** * コントロール用スライダー * @author Aquioux(YOSHIDA, Akio) */ /*public*/ class Sliders extends Sprite { /** * スライダーアクション(外部で定義した処理) */ public function set action(value:Function):void { _action = value; } private var _action:Function; // スライダーの値を小数第何位まで有効にするか private const PRECISION:int = 3; private const TICK:Number = 1 / Math.pow(10, PRECISION); // スライダーのラベル private const VALUES:Array = ["a:", "b:", "c:", "d:"]; // スライダー格納配列 private var sliders:Array = []; /** * コンストラクタ */ public function Sliders() { } /** * セットアップ */ public function setup():void { var params:Vector.<Number> = Vector.<Number>([ Attractor.A_MIN, Attractor.A_MAX, Attractor.a, Attractor.B_MIN, Attractor.B_MAX, Attractor.b, Attractor.C_MIN, Attractor.C_MAX, Attractor.c, Attractor.D_MIN, Attractor.D_MAX, Attractor.d ]); var idx:int = 0; for (var y:int = 0; y < VALUES.length; y++) { var slider:HUISlider = new HUISlider(this, 25, y * 15, VALUES[idx], handler); slider.width = 430; slider.labelPrecision = PRECISION; slider.tick = TICK; slider.setSliderParams(params[idx * 3], params[idx * 3 + 1], params[idx * 3 + 2]); sliders[idx] = slider; idx++; } } /** * リセット(Attractor 内の数値に伴ったスライダー値にリセット) */ public function reset():void { sliders[0].value = Attractor.a; sliders[1].value = Attractor.b; sliders[2].value = Attractor.c; sliders[3].value = Attractor.d; } // ハンドラ private function handler(e:Event):void { var target:HUISlider = HUISlider(e.target); var label:String = target.label; var value:Number = target.value; if (label == VALUES[0]) Attractor.a = value; if (label == VALUES[1]) Attractor.b = value; if (label == VALUES[2]) Attractor.c = value; if (label == VALUES[3]) Attractor.d = value; _action(); } } //} //package { import com.bit101.components.PushButton; import flash.display.Sprite; import flash.events.Event; /** * コントロール用ボタン * @author Aquioux(YOSHIDA, Akio) */ /*public*/ class Buttons extends Sprite { /** * ボタンアクション(外部で定義した処理) */ public function set action(value:Function):void { _action = value; } private var _action:Function; // 写像の名称と複素数の値 private const VALUES:Array = [ ["No.1", Vector.<Number>([-2.167, -1.583, -0.609, -1.774]) ], ["No.2", Vector.<Number>([-1.03, -1.743, 1.844, 0.469]) ], ["No.3", Vector.<Number>([-1.5, -3.0, 1.5, 1.5]) ], ["No.4", Vector.<Number>([-1.4, 1.6, 1.0, 0.7]) ], ["No.5", Vector.<Number>([1.7, 1.7, 0.06, 1.2]) ], ["No.6", Vector.<Number>([1.3, 1.7, 0.5, 1.4]) ], ["No.7", Vector.<Number>([0.87, 1.29, -1.07, 1.55]) ], ["No.8", Vector.<Number>([1.7, 1.7, -1.2, 1.2]) ], ["No.9", Vector.<Number>([1.6, -0.6, -1.2, 1.6]) ], ["No.10", Vector.<Number>([1.1, -1.1, 1.0, 1.4]) ], ["No.11", Vector.<Number>([1.4, -1.4, 0.5, 0.8]) ], ["No.12", Vector.<Number>([0.7, -2.0, 1.6, 0.9]) ], ["No.13", Vector.<Number>([0.7, -2.879, 1.6, 0.9]) ], ["No.14", Vector.<Number>([3.0, -3.0, 2.0, -2.0]) ], ["No.15", Vector.<Number>([3.0, -3.0, 2.0, -0.793]) ], ["No.16", Vector.<Number>([3.0, -3.0, 2.0, 0.0]) ], ["No.17", Vector.<Number>([2.0, -2.0, 2.0, -0.135]) ], ["No.18", Vector.<Number>([2.828, -1.461, -0.444, -1.104]) ] //["No.1", Vector.<Number>([-1.835, -1.743, 1.844, 0.469]) ], //["No.5", Vector.<Number>([-1.96, 1.73, 1.21, -0.208]) ], ]; // 前回押したボタン private var prevButton_:PushButton; /** * インストラクタ */ public function Buttons() { } /** * セットアップ */ public function setup():void { // ボタンの作成 var buttonWidth:int = 52; var buttonHeight:int = 20; var idx:int = 0; for (var y:int = 0; y < 2; y++) { for (var x:int = 0; x < 9; x++) { var b:PushButton = new PushButton(this, buttonWidth * x, buttonHeight * y, VALUES[idx][0], handler); b.name = String(idx); idx++; b.width = buttonWidth; b.height = buttonHeight; } } } /** * リセット(前回押したため無効になっているボタンを有効にする) */ public function reset():void { if (prevButton_) prevButton_.enabled = true; } // ハンドラ private function handler(e:Event):void { var target:PushButton = PushButton(e.target); var idx:int = int(target.name); handlerAction(target); _action(VALUES[idx][1]); } /** * ボタンアクション(内部で完了する処理) * 押されたボタンを押せなくし、前回押したボタンを押せるようにする * @param target 押されたボタン * @private */ private function handlerAction(target:PushButton):void { reset(); target.enabled = false; prevButton_ = target; } } //} //package aquioux.display.colorUtil { /** * コサインカーブで色相環的な RGB を計算 * @author Aquioux(Yoshida, Akio) */ /*public*/ class CycleRGB { /** * 32bit カラーのためのアルファ値 */ static public function get alpha():uint { return _alpha; } static public function set alpha(value:uint):void { _alpha = (value > 0xFF) ? 0xFF : value; } private static var _alpha:uint = 0xFF; private static const PI:Number = Math.PI; // 円周率 private static const DEGREE90:Number = PI / 2; // 90度(弧度法形式) private static const DEGREE180:Number = PI; // 180度(弧度法形式) /** * 角度に応じた RGB を得る * @param angle HSV のように角度(度数法)を指定 * @return 色(0xNNNNNN) */ public static function getColor(angle:Number):uint { var radian:Number = angle * PI / 180; var valR:uint = (Math.cos(radian) + 1) * 0xFF >> 1; var valG:uint = (Math.cos(radian + DEGREE90) + 1) * 0xFF >> 1; var valB:uint = (Math.cos(radian + DEGREE180) + 1) * 0xFF >> 1; return valR << 16 | valG << 8 | valB; } /** * 角度に応じた RGB を得る(32bit カラー) * @param angle HSV のように角度(度数法)を指定 * @return 色(0xNNNNNNNN) */ public static function getColor32(angle:Number):uint { return _alpha << 24 | getColor(angle); } } //} Code Fullscreen Preview Fullscreen