Xm.as
----- Xm.as --- octech 2008 ----- //
// ----- 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; }
}