くすだま
2010年4月11日
明日は娘の9歳の誕生日なので, ひとつこんなものを...
----------------------------------------------------------------
先日の「紙ふぶき」
(see: http://wonderfl.net/code/d1bb28bd17493ad8e9e997e5c3ca4e8b7cc35eda)
は実はこのために試作したものです
----------------------------------------------------------------
流用歓迎. (Taremaku クラスの MESSAGE プロパティを変更してください)
----------------------------------------------------------------
/**
* Copyright tenasaku ( http://wonderfl.net/user/tenasaku )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/g719
*/
// 2010年4月11日
// 明日は娘の9歳の誕生日なので, ひとつこんなものを...
// ----------------------------------------------------------------
// 先日の「紙ふぶき」
// (see: http://wonderfl.net/code/d1bb28bd17493ad8e9e997e5c3ca4e8b7cc35eda)
// は実はこのために試作したものです
// ----------------------------------------------------------------
// 流用歓迎. (Taremaku クラスの MESSAGE プロパティを変更してください)
// ----------------------------------------------------------------
package {
import flash.display.*;
import flash.events.*;
import flash.text.*;
import flash.utils.*;
public class Main extends Sprite {
private const NUM_KAMIKIRE:int = 320;
private const TEXT1:String = "たま を クリック してください";
private const TEXT2:String = "もういちど みるには\nリロード してください";
private var maku:Taremaku;
private var kamiFubuki:Array;
private var tama:Kusudama;
private var tf:TextField;
private function atEveryFrame(e:Event):void {
if ( tama.scaleX > 1.0 ) {
tama.scaleX = Math.max(1.0, tama.scaleX - 0.1);
tama.scaleY = tama.scaleX;
return;
}
if ( tama.tipOpen < Math.PI/3 ) {
tama.tipOpen += Math.PI/30;
}
if ( ( tama.tipOpen >= Math.PI/4 ) && ( maku.scaleY < 1.0 ) ) {
maku.scaleY += 0.1;
}
var i:int = 0;
while ( i < kamiFubuki.length ) {
kamiFubuki[i].rotation3D += kamiFubuki[i].omega;
kamiFubuki[i].fall();
if ( kamiFubuki[i].x < 0 ) {
kamiFubuki[i].x += stage.stageWidth;
}
if ( kamiFubuki[i].x >= stage.stageWidth ) {
kamiFubuki[i].x -= stage.stageWidth;
}
if ( kamiFubuki[i].y - Kamikire.SIZE/Math.SQRT2 >= stage.stageHeight ) {
this.removeChild(kamiFubuki[i]);
kamiFubuki.splice(i,1);
} else {
++i;
}
}
if ( kamiFubuki.length == 0 ) {
tf.text = TEXT2;
tf.visible = true;
tf.x = (stage.stageWidth - tf.width)/2;
tf.y = stage.stageHeight - tf.height - 10;
this.removeEventListener(Event.ENTER_FRAME, atEveryFrame);
}
}
private function onClick(e:MouseEvent):void {
tf.visible = false;
tama.removeEventListener(MouseEvent.CLICK, onClick);
this.addEventListener(Event.ENTER_FRAME, atEveryFrame);
}
private function initialize(e:Event):void {
this.removeEventListener(Event.ADDED_TO_STAGE, initialize);
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
this.graphics.beginFill(0xff9966);
this.graphics.drawRect(0,0,stage.stageWidth,stage.stageHeight);
this.graphics.endFill();
tama = new Kusudama();
tama.x = stage.stageWidth/2;
tama.y = 20;
kamiFubuki = new Array();
maku = new Taremaku();
maku.x = stage.stageWidth/2;
maku.y = tama.y + Kusudama.SIZE/2*Math.sqrt(3);
addChild(maku);
while ( kamiFubuki.length < NUM_KAMIKIRE ) {
kamiFubuki.unshift(new Kamikire());
kamiFubuki[0].x = stage.stageWidth/2;
kamiFubuki[0].y = tama.y+Kusudama.SIZE/2;
this.addChild(kamiFubuki[0]);
}
tama.scaleX = Math.min(stage.stageWidth-40,stage.stageHeight-40)/Kusudama.SIZE;
tama.scaleY = tama.scaleX;
this.addChild(tama);
stage.frameRate = 20;
var fmt:TextFormat = new TextFormat();
var fontList:Array = Font.enumerateFonts(true);
var i:int;
for each ( var ft:Font in fontList ) {
if ( ft.fontName == "ヒラギノ角ゴ Pro W6" ) {
fmt.font = "ヒラギノ角ゴ Pro W6";
break;
} if ( ft.fontName == "MS ゴシック" ) {
fmt.font = "MS ゴシック";
break;
}
}
fmt.size = 24;
fmt.leftMargin = 4;
fmt.rightMargin = 4;
fmt.align = TextFormatAlign.CENTER;
tf = new TextField();
tf.autoSize = TextFieldAutoSize.CENTER;
tf.defaultTextFormat = fmt;
tf.background = true;
tf.backgroundColor = 0x0000ff;
tf.textColor = 0xffff00;
tf.text = TEXT1;
tf.visible = true;
tf.x = (stage.stageWidth - tf.width)/2;
tf.y = stage.stageHeight - tf.height - 10;
this.addChild(tf);
tama.addEventListener(MouseEvent.CLICK, onClick);
}
// 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
import flash.display.*;
import flash.geom.*;
import flash.text.*;
// 固有の軸のまわりで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();
}
public function get omega():Number {
return _omega;
}
// 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.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
class Kusudama extends Sprite {
public static const SIZE:Number = 100;
private var migi:Shape;
private var hidari:Shape;
public function set tipOpen(t:Number):void {
if (t < 0) { t = 0; }
if (t > Math.PI/2) { t = Math.PI/2; }
hidari.rotation = t/Math.PI*90;
migi.rotation = -hidari.rotation;
}
public function get tipOpen():Number {
return hidari.rotation/90*Math.PI;
}
public function Kusudama() {
var mat:Matrix = new Matrix;
mat.createGradientBox(SIZE,SIZE,Math.PI/2,0,0);
migi = new Shape();
hidari = new Shape();
migi.graphics.clear();
migi.graphics.beginGradientFill(
GradientType.LINEAR,
[0xffffff,0xffcccc,0xcc3333],[1,1,1],[0,64,127],
mat,
SpreadMethod.PAD
);
migi.graphics.moveTo(0,0);
migi.graphics.curveTo(SIZE/2,0,SIZE/2,SIZE/2);
migi.graphics.curveTo(SIZE/2,SIZE,0,SIZE);
migi.graphics.lineTo(0,0);
migi.graphics.endFill()
hidari.graphics.clear();
hidari.graphics.beginGradientFill(
GradientType.LINEAR,
[0xffffff,0xffcccc,0xcc3333],[1,1,1],[0,64,127],
mat,
SpreadMethod.PAD
);
hidari.graphics.moveTo(0,0);
hidari.graphics.curveTo(-SIZE/2,0,-SIZE/2,SIZE/2);
hidari.graphics.curveTo(-SIZE/2,SIZE,0,SIZE);
hidari.graphics.lineTo(0,0);
hidari.graphics.endFill();
this.addChild(migi);
this.addChild(hidari);
}
}
class Taremaku extends Sprite {
private const MAKUHABA:Number = Kusudama.SIZE - 4;
private const MESSAGE:String = "ゆきかちゃん\nおたんじょうび\nおめでとう!";
private const MARGIN_TOP:Number = 12;
private var fmt:TextFormat;
private var letterList:Array; // List of TextFields associated to each letter...
// constructor method...
public function Taremaku() {
letterList = new Array();
fmt = new TextFormat();
var fontList:Array = Font.enumerateFonts(true);
var i:int;
for each ( var ft:Font in fontList ) {
if ( ft.fontName == "ヒラギノ明朝 Pro W6" ) {
fmt.font = "ヒラギノ明朝 Pro W6";
break;
} if ( ft.fontName == "MS 明朝" ) {
fmt.font = "MS 明朝";
break;
}
}
fmt.size = 18;
fmt.bold = true;
fmt.align = TextFormatAlign.CENTER;
var p:int = 0;
var horiz:int = MAKUHABA/3;
var vert:int = MARGIN_TOP;
for ( i = 0 ; i < MESSAGE.length ; ++i ) {
var s:String = MESSAGE.charAt(i);
if ( s == "\n" ) {
horiz -= MAKUHABA/3;
vert = MARGIN_TOP;
} else {
p++;
letterList[p] = new TextField();
letterList[p].defaultTextFormat = fmt;
letterList[p].text = s;
letterList[p].autoSize = TextFieldAutoSize.CENTER;
letterList[p].x = horiz - letterList[p].width/2;
letterList[p].y = vert;
vert += letterList[p].height+3;
this.addChild(letterList[p]);
}
}
this.height += letterList[p].height+MARGIN_TOP/2;
var h:Number = this.height;
this.graphics.clear();
this.graphics.beginFill(0xffffff);
this.graphics.drawRect(-MAKUHABA/2,0,MAKUHABA,h);
this.graphics.endFill();
this.graphics.lineStyle(3,0xff0000);
this.graphics.moveTo(-MAKUHABA/2,0);
this.graphics.lineTo(-MAKUHABA/2,h);
this.graphics.moveTo(+MAKUHABA/2,0);
this.graphics.lineTo(+MAKUHABA/2,h);
this.scaleY = 0;
}
}