紙ふぶき
------------------------------------------------------------------------
2010年4月9日
なんちゃって紙ふぶき
実はそれぞれの紙切れは, 一定の回転軸のまわりを, 一定の速さで回転しながら,
一定の移動速度で落下しているのだけど, 移動方向がフラフラ変わることと,
数多く同時に散らしていることで, なんとなく紙吹雪らしく見えている.
... しかし、これまた重くなった (^^;
------------------------------------------------------------------------
/**
* Copyright tenasaku ( http://wonderfl.net/user/tenasaku )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/tVmM
*/
/* ------------------------------------------------------------------------
2010年4月9日
なんちゃって紙ふぶき
実はそれぞれの紙切れは, 一定の回転軸のまわりを, 一定の速さで回転しながら,
一定の移動速度で落下しているのだけど, 移動方向がフラフラ変わることと,
数多く同時に散らしていることで, なんとなく紙吹雪らしく見えている.
... しかし、これまた重くなった (^^;
------------------------------------------------------------------------
*/
package {
import flash.display.*;
import flash.events.*;
import flash.geom.*;
// import flash.text.*;
public class Main extends Sprite {
private const NUM_KAMIKIRE:int = 400;
private var kamiFubuki:Array;
private var frameCount:uint;
private function drawBackGround():void {
var mat:Matrix = new Matrix();
mat.createGradientBox(stage.stageWidth,stage.stageHeight,Math.PI/2,0,0);
this.graphics.clear();
this.graphics.beginGradientFill(
GradientType.LINEAR,
[0x00ccff,0x0000ff,0x000099],[1,1,1],[0,200,255],
mat,
SpreadMethod.PAD);
this.graphics.drawRect(0,0,stage.stageWidth, stage.stageHeight);
this.graphics.endFill();
}
private function atEveryFrame(e:Event):void {
var i:int;
// 最初の一秒ほどで撒き散らす
if ( (frameCount+1)*25 < kamiFubuki.length ) {
for ( i = frameCount*25 ; i < (frameCount+1)*25 ; ++i ) {
if ( i >= kamiFubuki.length ) break;
kamiFubuki[i].x
= Kamikire.SIZE/Math.SQRT2
+ (stage.stageWidth-Kamikire.SIZE*Math.SQRT2)*(i/kamiFubuki.length);
kamiFubuki[i].y = 30;
kamiFubuki[i].visible = true;
}
frameCount++;
}
// 紙切れを落とす. 画面の外に出たら反対側から入ってくる(トーラス空間)
for ( i = 0 ; i < kamiFubuki.length ; ++i ) {
kamiFubuki[i].fall();
if (kamiFubuki[i].x - Kamikire.SIZE/Math.SQRT2 > stage.stageWidth) {
kamiFubuki[i].x -= stage.stageWidth;
}
if (kamiFubuki[i].x + Kamikire.SIZE/Math.SQRT2 < 0 ) {
kamiFubuki[i].x += stage.stageWidth;
}
if (kamiFubuki[i].y - Kamikire.SIZE/Math.SQRT2 > stage.stageHeight) {
kamiFubuki[i].y -= stage.stageHeight;
}
}
}
private function onResize(e:Event):void {
drawBackGround();
var i:int;
for ( i = 0 ; i < kamiFubuki.length ; ++i ) {
kamiFubuki[i].visible = false;
}
frameCount = 0;
}
private function initialize(e:Event):void {
this.removeEventListener(Event.ADDED_TO_STAGE, initialize);
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
drawBackGround();
kamiFubuki = new Array();
while ( kamiFubuki.length < NUM_KAMIKIRE ) {
kamiFubuki.unshift(new Kamikire());
kamiFubuki[0].visible = false; // 出し方をヒネったので最初は見えなくする
this.addChild(kamiFubuki[0]);
}
stage.frameRate = 24;
frameCount = 0;
stage.addEventListener(Event.RESIZE, onResize);
stage.addEventListener(Event.ENTER_FRAME, atEveryFrame);
}
// The Main constructor simply calles initialize() function.
public function Main():void {
if ( stage != null ) {
initialize(null);
} else {
this.addEventListener(Event.ADDED_TO_STAGE, initialize);
}
}
} // end of class Main
} // end of package
// 固有の軸のまわりを固有の角速度で3D回転しながらフラフラと落下する正方形の紙切れ
import flash.display.*;
class Kamikire extends Shape {
public static const SIZE:Number = 10;
private var _faceColor:uint;
private var _backColor:uint;
private var _theta:Number; // amount of rotation along the axis
private var _omega:Number; // angular velocity
private var _fallTheta:Number;
private var _fallSpeed:Number;
private var _Ax:Number,_Ay:Number,_Az:Number; // axis of rotation
private var _Bx:Number,_By:Number,_Bz:Number; // a unit vector perp to A
private var _Cx:Number,_Cy:Number,_Cz:Number; // a unit vector perp to A and B
public function Kamikire() {
var t:Number = Math.random()*Math.PI*2;
var r:int = Math.floor((1+Math.cos(t))*127.9999);
var g:int = Math.floor((1+Math.cos(t+Math.PI*2/3))*127.9999);
var b:int = Math.floor((1+Math.cos(t-Math.PI*2/3))*127.9999);
_faceColor = (r<<16)|(g<<8)|b;
_backColor = 0x010101*Math.floor(127+Math.random()*64);
_omega = (Math.random()*2-1)*Math.PI/4;
_fallTheta = 0;
_fallSpeed = 3+Math.random()*2;
_theta = Math.random()*Math.PI*2;
_Ax = 1;
_Ay = Math.random();
_Az = Math.random()*2-1;
var _l:Number = Math.sqrt(_Ax*_Ax+_Ay*_Ay+_Az*_Az);
_Ax /= _l;
_Ay /= _l;
_Az /= _l;
var _s:Number = Math.sqrt(_Ax*_Ax+_Ay*_Ay);
if ( _s == 0 ) { // then A == ( 0, 0, -1 );
_Bx = 1.0; _By = 0.0; _Bz = 0.0;
_Cx = 0.0; _Cy = 1.0; _Cz = 0.0;
} else {
_Bx = _Ay; _By = -_Ax; _Bz = 0;
_Cx = _Ax*_Az; _Cy = _Ay*_Az; _Cz = -(_s*_s);
_Bx /= _s; _By /= _s;
_Cx /= _s*_l; _Cy /= _s*_l; _Cz /= _s*_l;
}
this.graphics.beginFill(_faceColor);
this.graphics.drawRect(-SIZE/2,-SIZE/2,SIZE,SIZE);
this.graphics.endFill();
}
// rotate along the axis (_Ax,_Ay,_Az)...
public function set rotation3D(theta:Number):void {
_theta = theta - (Math.PI*2)*Math.floor(theta/(Math.PI*2));
var _cos:Number = Math.cos(_theta);
var _sin:Number = Math.sin(_theta);
// vector F is the rotated image of (1,0,0);
var _Fx:Number = _Ax*_Ax+(_Bx*_Bx+_Cx*_Cx)*_cos;
var _Fy:Number = _Ax*_Ay+(_Bx*_By+_Cx*_Cy)*_cos+(_Bx*_Cy-_Cx*_By)*_sin;
var _Fz:Number = _Ax*_Az+(_Bx*_Bz+_Cx*_Cz)*_cos-(_Bx*_Cz-_Cx*_Bz)*_sin;
// vector G is the rotated image of (0,1,0);
var _Gx:Number = _Ax*_Ay+(_By*_Bx+_Cy*_Cz)*_cos+(_By*_Cx-_Cy*_Bx)*_sin;
var _Gy:Number = _Ay*_Ay+(_By*_By+_Cy*_Cy)*_cos;
var _Gz:Number = _Ay*_Az+(_By*_Bz+_Cy*_Cz)*_cos+(_By*_Cz-_Cy*_Bz)*_sin;
// let's see whether the piece shows its face or its back...
var cc:uint = ( (_Az*_Az+(_Bz*_Bz+_Cz*_Cz)*_cos) >= 0 )?_faceColor:_backColor;
// We can draw the image now...
this.graphics.clear();
this.graphics.beginFill(cc);
this.graphics.moveTo(_Fx*SIZE/2+_Gx*SIZE/2,_Fy*SIZE/2+_Gy*SIZE/2);
this.graphics.lineTo(-_Fx*SIZE/2+_Gx*SIZE/2,-_Fy*SIZE/2+_Gy*SIZE/2);
this.graphics.lineTo(-_Fx*SIZE/2-_Gx*SIZE/2,-_Fy*SIZE/2-_Gy*SIZE/2);
this.graphics.lineTo(_Fx*SIZE/2-_Gx*SIZE/2,_Fy*SIZE/2-_Gy*SIZE/2);
this.graphics.lineTo(_Fx*SIZE/2+_Gx*SIZE/2,_Fy*SIZE/2+_Gy*SIZE/2);
this.graphics.endFill();
}
public function get rotation3D():Number {
return _theta - (Math.PI*2)*Math.floor(_theta/(Math.PI*2));
}
public function fall():void {
this.rotation3D += this._omega;
this.x += _fallSpeed*Math.sin(_fallTheta);
this.y += _fallSpeed*Math.cos(_fallTheta);
_fallTheta += (Math.random()*2-1)*Math.PI/12;
if ( _fallTheta < -Math.PI/2 ) {
_fallTheta = -Math.PI - _fallTheta;
}
if ( _fallTheta > Math.PI/2 ) {
_fallTheta = Math.PI - _fallTheta;
}
}
} // end of class Kamikire