// ----- Xm.as --- octech 2008 ----- // package { import caurina.transitions.Tweener; import flash.display.*; import flash.filters.GlowFilter; import flash.geom.*; import flash.text.*; import flash.events.*; [SWF(frameRate = "24", backgroundColor = "#333333")] public class Xm extends Sprite { static private const MODE_EDIT:int = 0; static private const MODE_VIEW:int = 1; static private const NUM_MODE:int = 2; static private const P_SIZE:int = 12; // パーティクルの一辺の長さ(pixel) static private const GRAVITY_Y:Number = 1.4; // パーティクルの基本速度. private var _mode:int = 0; // MODE_EDIT, MODE_VIEW private var _scenes:Vector.<Sprite> = null; // _modeに対応 private var _bitmapdata:BitmapData = null; private var _editRects:Array = []; private var _particles:Array = []; private var _pauseView:Boolean = false; // コンストラクタ. public function Xm() { addEventListener(Event.ADDED_TO_STAGE, init); } // 初期化. private function init(e:Event) :void { stage.align = "TL"; stage.scaleMode = "noScale"; _scenes = new Vector.<Sprite>( NUM_MODE ); // draw SKY. var g:Graphics = this.graphics; var gm:Matrix = new Matrix(); gm.createGradientBox( stage.stageWidth, stage.stageHeight, Math.PI / 2, 0, 0 ); g.beginGradientFill( GradientType.LINEAR, [ 0x000011, 0x333344 ], [1, 1], [0, 255], gm ); g.drawRect( 0, 0, stage.stageWidth, stage.stageHeight ); g.endFill(); // シーン作成. _scenes[MODE_VIEW] = new Sprite(); addChild( _scenes[MODE_VIEW] ); setupView( _scenes[MODE_VIEW], stage.stageWidth, stage.stageHeight ); _scenes[MODE_EDIT] = new Sprite(); addChild( _scenes[MODE_EDIT] ); setupEdit( _scenes[MODE_EDIT], stage.stageWidth, stage.stageHeight ); stage.addEventListener( MouseEvent.MOUSE_MOVE, checkModeToEdit ); stage.addEventListener( Event.MOUSE_LEAVE, checkModeToView ); // パーティクル基本データ作成. _bitmapdata = new BitmapData( P_SIZE, P_SIZE, true, 0x00FFFFFF ); } private function checkModeToEdit(e:MouseEvent):void { setMode( MODE_EDIT ); } private function checkModeToView(e:Event):void { setMode( MODE_VIEW ); } // エディットモードを作成. private function setupEdit( s:Sprite, w:int, h:int ) :void { var g:Graphics = s.graphics; g.beginFill( 0x663333, 1.0 ); g.drawRect( 0, 0, w, h ); const EDITAREA_SIZE:Number = 200; const EDITAREA_X0:Number = stage.stageWidth/2 - EDITAREA_SIZE/2; const EDITAREA_Y0:Number = 10; const EDITBOX_SIZE:Number = EDITAREA_SIZE / P_SIZE; // 一つの矩形のサイズ. var py:int, px:int; for ( py = 0; py < P_SIZE; py++) { for ( px = 0; px < P_SIZE; px++) { s.addChild( addEditRect( EDITAREA_X0 + px * EDITBOX_SIZE, EDITAREA_Y0 + py * EDITBOX_SIZE, EDITBOX_SIZE, EDITBOX_SIZE ) ); } } // 初期化X if ( P_SIZE == 12 ) { for ( py = 0; py < P_SIZE; py++) { for ( px = 0; px < P_SIZE; px++) { var er:EditRect = _editRects[py * P_SIZE + px] as EditRect; if ( (px == py || px == P_SIZE-py-1) && (px >= 2 && px < 10) ) { er.onoff = true; } else { er.onoff = false; } } } } // text var t:TextField = new TextField(); s.addChild(t); t.text = "You can draw the snow flake.\n\n" +"After drawing,\nmove cursor out from flash area.\n\n" + "Xm.as --- octech 2008.\nMerry Christmas !"; t.selectable = false; t.autoSize = TextFieldAutoSize.LEFT; t.setTextFormat(new TextFormat(null, 12, 0xcccccc)); t.x = EDITAREA_X0; t.y = EDITAREA_Y0 + EDITBOX_SIZE * P_SIZE + 15; } // エディットモードの一つの箱を配置. private function addEditRect( ex:Number, ey:Number, ew:Number, eh:Number ) :EditRect { var newEditRect:EditRect = new EditRect( ew, eh ); _editRects.push( newEditRect ); newEditRect.x = ex; newEditRect.y = ey; return newEditRect; } // ビューモードを作成. private function setupView( s:Sprite, w:int, h:int ) :void { s.addEventListener( Event.ENTER_FRAME, processView ); var g:Graphics = s.graphics; // draw RAND-TOWN. const MAX_X:Number = stage.stageWidth; const MIN_HEIGHT:Number = 10, RAND_HEIGHT:Number = 20; const MIN_WIDTH:Number = 10, RAND_WIDTH:Number = 40; var accX:Number = 0; var curW:Number = 0, curH:Number = 0; const BOTTOM:Number = stage.stageHeight; g.beginFill( 0xFFFFFF, 1.0 ); while ( accX < MAX_X ) { curH = Math.random() * RAND_HEIGHT + MIN_HEIGHT; curW = Math.random() * RAND_WIDTH + MIN_WIDTH; g.drawRect( accX, BOTTOM - curH, curW, curH ); accX += curW; } g.endFill(); // draw TREE. const TX:Number = stage.stageWidth - 100; const TW:Number = 40, TH:Number = 15; const TB:Number = BOTTOM - MIN_HEIGHT; const TE:Number = 10; const TNUM:int = 4; for (var i:int = 0; i < TNUM; i++) { g.beginFill( 0xFFFFFF, 1.0 ); g.moveTo( TX, TB - i * TH ); g.lineTo( TX + TW, TB - i * TH ); g.lineTo( TX + TW/2, TB - ((i+1) * TH) - TE ); g.lineTo( TX, TB - i * TH ); g.endFill(); } const StarR:Number = 15; var StartX:Number = TX + TW / 2, StartY:Number = TB - TNUM * TH - TE; var VTheta:Vector.<Number> = Vector.<Number>([ 0.1 * Math.PI, 0.5 * Math.PI, 0.9 * Math.PI, 1.3 * Math.PI, 1.7 * Math.PI ]); const VVtx:Vector.<Number> = Vector.<Number>( [ StartX + StarR*Math.cos(VTheta[0]), StartY - StarR*Math.sin(VTheta[0]), StartX + StarR*Math.cos(VTheta[2]), StartY - StarR*Math.sin(VTheta[2]), StartX + StarR*Math.cos(VTheta[4]), StartY - StarR*Math.sin(VTheta[4]), StartX + StarR*Math.cos(VTheta[1]), StartY - StarR*Math.sin(VTheta[1]), StartX + StarR*Math.cos(VTheta[3]), StartY - StarR*Math.sin(VTheta[3]), StartX + StarR*Math.cos(VTheta[0]), StartY - StarR*Math.sin(VTheta[0]) ] ); g.beginFill( 0xFFFF66, 1.0 ); g.drawPath( Vector.<int>([1,2,2,2,2,2]), VVtx, "nonZero" ); g.endFill(); // グロー. s.filters = [ new GlowFilter( 0xFFFFFF, 2.0, 16.0, 16.0, 1.0, 2 ) ]; } // モード切替. private function setMode( mode:int ) :void { if( _mode != mode ){ _mode = mode; switch ( _mode ) { case MODE_EDIT: _pauseView = true; Tweener.addTween( _scenes[MODE_EDIT], { alpha:0.9, time:0.6 } ); break; case MODE_VIEW: applyParticle(); _pauseView = false; Tweener.addTween( _scenes[MODE_EDIT], { alpha:0.0, time:1.2 } ); break; } } } // 編集情報を、ビットマップデータに適用. private function applyParticle() :void { for (var py:int = 0; py < P_SIZE; py++) { for (var px:int = 0; px < P_SIZE; px++) { var er:EditRect = _editRects[py * P_SIZE + px] as EditRect; _bitmapdata.setPixel32( px, py, (er.onoff ? 0xFFFFFFFF : 0x00FFFFFF) ); } } } // ビューモードの毎フレームの処理. private function processView( e:Event ) :void { if ( _pauseView ) return; // ポーズ中. // 新規作成. var sView:Sprite = _scenes[MODE_VIEW]; var newP:Sprite = createNewParticle(); if( sView != null && newP != null ){ sView.addChild( newP ); newP.x = Math.random() * sView.width; newP.y = -newP.height; } // 落下. for (var i:int = 0; i < _particles.length; i++) { var p:Sprite = _particles[i]; if ( p == null ) { continue; } p.x += (Math.random()-0.5) * 0.8; p.y += GRAVITY_Y + 0.2*Math.random(); p.rotation += 2.0 + (Math.random() * 3.0); if ( p.y > stage.stageHeight + p.height ) { // dead. sView.removeChild( _particles[i] ); _particles[i] = null; } } } // 新しくパーティクルを作成します. private function createNewParticle() :Sprite { const P_SIZE_HALF:Number = P_SIZE / 2; var newP:Sprite = new Sprite(); var pm:Matrix = new Matrix(); pm.translate( -P_SIZE_HALF, -P_SIZE_HALF ); newP.graphics.beginBitmapFill( _bitmapdata, pm ); newP.graphics.drawRect( -P_SIZE_HALF, -P_SIZE_HALF, P_SIZE, P_SIZE ); newP.graphics.endFill(); for (var i:int = 0; i < _particles.length; i++) { if ( _particles[i] == null ) { _particles[i] = newP; // 空きがあればそこに追加. return newP; } } _particles.push( newP ); // 空きがなければ末尾に追加. return newP; } } } import flash.display.Graphics; import flash.display.Sprite; import flash.events.MouseEvent; class EditRect extends Sprite { static private const MARGIN:Number = 1; private var _w:Number, _h:Number; private var _onoff:Boolean = true; public function EditRect( w:Number, h:Number ) { _w = w; _h = h; onoff = true; addEventListener( MouseEvent.ROLL_OVER, checkChange ); addEventListener( MouseEvent.MOUSE_DOWN, checkChange ); } private function checkChange(e:MouseEvent):void { switch ( e.type ) { case MouseEvent.MOUSE_DOWN: toggleOnoff(); break; case MouseEvent.ROLL_OVER: if ( e.buttonDown ) toggleOnoff(); break; } } private function toggleOnoff() :void { onoff = !onoff; } public function set onoff( value:Boolean ) :void { var g:Graphics = this.graphics; g.clear(); _onoff = value; if ( _onoff ) g.beginFill( 0x999999, 1.0 ); else g.beginFill( 0x333333, 0.5 ); g.drawRect( MARGIN, MARGIN, _w - MARGIN * 2, _h - MARGIN * 2 ); } public function get onoff() :Boolean { return _onoff; } } Xm.as