// forked from uwi's ふよふよ // 元ネタはコレ http://www.whatisfailwhale.info/ package { import com.flashdynamix.utils.SWFProfiler; import flash.display.BitmapData; import flash.display.Bitmap; import flash.display.Shape; import flash.display.Sprite; import flash.display.Graphics; import flash.events.Event; import flash.events.TimerEvent; import flash.filters.BitmapFilter; import flash.filters.GradientBevelFilter; import flash.filters.BlurFilter; import flash.utils.Timer; import flash.utils.getTimer; import flash.geom.Point; import flash.geom.Matrix; import flash.geom.Rectangle; import flash.text.TextField; import flash.text.TextFormat; import flash.display.BlendMode; import org.libspark.betweenas3.BetweenAS3; import org.libspark.betweenas3.tweens.ITween; import org.libspark.betweenas3.easing.Cubic; import frocessing.shape.FShapeSVG; [SWF(width=465, height=465, backgroundColor=0x000000, frameRate=60)] public class TwitterBird extends Sprite { private var _bullets : Array; private var _myx : Point; private var _myv : Point; private const R_BULLET : Number = 20.0; private var _tf : TextField; private var _space : BitmapData; private var _avs : Array; // <Avoider> private const P0 : Point = new Point(0, 0); public function TwitterBird() { Wonderfl.capture_delay(5); SWFProfiler.init(this); // 宇宙 _space = new BitmapData(465, 465, false, 0x6CC5C3); var bmpspace : Bitmap = new Bitmap(_space); addChild(bmpspace); var svg:XML = <svg><g> <path fill="#FFFFFF" d="M495.498,20.332c-13.752,0-28.352-9.762-33.87-19.307c-5.693,9.545-20.712,19.307-34.463,19.307 s-28.353-9.762-33.87-19.307c-5.693,9.545-20.711,19.307-34.463,19.307s-28.352-9.762-33.87-19.307 c-5.693,9.545-20.712,19.307-34.463,19.307s-28.353-9.762-33.87-19.307c-5.693,9.545-20.711,19.307-34.463,19.307 s-28.352-9.762-33.87-19.307c-5.693,9.545-20.712,19.307-34.463,19.307c-14.178,0-29.264-10.375-34.362-20.193 C114.207,9.957,98.678,20.332,84.5,20.332C70.255,20.332,55.097,9.859,50.069,0h-0.196c-5.189,9.859-20.795,20.332-35.04,20.332 c-4.99,0-10.092-1.289-14.833-3.383V56h531V0h-0.462C525.349,9.859,509.743,20.332,495.498,20.332z"/></g></svg> var fshape:FShapeSVG = new FShapeSVG(svg); var whitewave:Sprite = addChild(fshape.toSprite()) as Sprite; whitewave.x = -34 whitewave.y = 410 var t:ITween = BetweenAS3.serial( BetweenAS3.tween(whitewave, { y: 420 }, null, 3.0 , Cubic.easeInOut), BetweenAS3.tween(whitewave, { y: 400 }, null, 3.0 , Cubic.easeInOut), BetweenAS3.tween(whitewave, { y: 410 }, null, 3.0 , Cubic.easeInOut) ); t.stopOnComplete = false; t.play(); svg = <svg><g> <path fill="#F15A22" d="M495.498,20.332c-13.752,0-28.352-9.762-33.87-19.307c-5.693,9.545-20.712,19.307-34.463,19.307 s-28.353-9.762-33.87-19.307c-5.693,9.545-20.711,19.307-34.463,19.307s-28.352-9.762-33.87-19.307 c-5.693,9.545-20.712,19.307-34.463,19.307s-28.353-9.762-33.87-19.307c-5.693,9.545-20.711,19.307-34.463,19.307 s-28.352-9.762-33.87-19.307c-5.693,9.545-20.712,19.307-34.463,19.307c-14.178,0-29.264-10.375-34.362-20.193 C114.207,9.957,98.678,20.332,84.5,20.332C70.255,20.332,55.097,9.859,50.069,0h-0.196c-5.189,9.859-20.795,20.332-35.04,20.332 c-4.99,0-10.092-1.289-14.833-3.383V56h531V0h-0.462C525.349,9.859,509.743,20.332,495.498,20.332z"/></g></svg> fshape = new FShapeSVG(svg); var wave:Sprite = addChild(fshape.toSprite()) as Sprite; wave.y = 410 t = BetweenAS3.serial( BetweenAS3.tween(wave, { y: 420 }, null, 5.0 , Cubic.easeInOut), BetweenAS3.tween(wave, { y: 435 }, null, 5.0 , Cubic.easeInOut), BetweenAS3.tween(wave, { y: 410 }, null, 5.0 , Cubic.easeInOut) ); t.stopOnComplete = false; t.play(); _myx = new Point(465 / 2, 465 / 2); _myv = new Point(0, 0); _bullets = []; addEventListener(Event.ENTER_FRAME, onEnterFrame); _avs = []; for (var i : int = 0; i < 8; i++) { addBullet(); _avs.push(new Avoider(_bullets, 465, 0, 465, 0, R_BULLET, 0.4, 0.4, 0.2, 0.2, _bullets[i])); } } private function onEnterFrame(e : Event) : void { var i : int = 0; for each(var b : Bullet in _bullets) { var a : Array = _avs[i].algo(b.x, b.y, b.v.x, b.v.y, 1); b.v.x += a[0]; b.v.y += a[1]; b.x += b.v.x; b.y += b.v.y; if (Math.ceil(Math.random() * 30) == 1) { if (b.scaleX == -1) { BetweenAS3.tween(b, { scaleX:1 }, null, 1.0+Math.random(), Cubic.easeOut).play(); } else if(b.scaleX == 1) { BetweenAS3.tween(b, { scaleX: -1 }, null, 1.0+Math.random(), Cubic.easeOut).play(); } } i++; } } // 弾追加 private function addBullet() : void { var x : Point = new Point(65+Math.random() * 400, 65+Math.random() * 350); // var v : Point = new Point(Math.random() * 5 + 2, Math.random() * 4 - 2); var v : Point = new Point(Math.random() * 0.2 - 0.1, Math.random() * 0.2 - 0.1); var b : Bullet = new Bullet(); b.x = x.x; b.y = x.y; b.v = v; b.r = R_BULLET; _bullets.push(b); addChild(b); } } } import flash.display.Sprite; import flash.geom.Point; import frocessing.shape.FShapeSVG; import org.libspark.betweenas3.BetweenAS3; import org.libspark.betweenas3.tweens.ITween; import org.libspark.betweenas3.easing.Cubic; class Bullet extends Sprite { public var p : Point; public var v : Point; public var r : Number; public function Bullet():void { super(); var svg:XML = <svg><path fill="#F15A22" d="M0,16.609c0,0,2.959-2.25,3.084-2.791c0.125-0.543,2.459-4.709,6.375-4.709s7.916,6.25,9.833,6.25 s-1.5-2.833,2.25-7.25c5.493-6.469,13-4,14.083-8c0.263-0.972,2.584,4.75,2.584,9.083c0,4.333-3.417,9.917-3.417,9.917 s0.417,0.666,2.5,0.666s5.75-3.5,5.75-3.5s2.834,19.417-19.584,19.417c-6.481,0-14.372-5.372-16.811-11.433 c-0.988-2.455-0.428-4.499-2.781-6.188C3.394,17.732,0.621,16.137,0,16.609z"/><path fill="#FFFFFF" d="M24.542,16.359c2.931,3.35,13-1.75,8-11C32.542,5.359,19.292,10.359,24.542,16.359z"/><circle fill="#FFFFFF" cx="8.126" cy="13.86" r="1.777"/></svg> var fshape:FShapeSVG = new FShapeSVG(svg); var sprite:Sprite = addChild(fshape.toSprite()) as Sprite; sprite.x = -21.5; var t:ITween = BetweenAS3.serial( BetweenAS3.tween(sprite, { rotation: 20 }, null, 1.0+Math.random()*2 , Cubic.easeInOut), BetweenAS3.tween(sprite, { rotation: 0 }, null, 1.0+Math.random()*2 , Cubic.easeInOut), BetweenAS3.tween(sprite, { rotation: -30 }, null, 1.0+Math.random()*2 , Cubic.easeInOut), BetweenAS3.tween(sprite, { rotation: 0 }, null, 1.0+Math.random()*2 , Cubic.easeInOut) ); t.stopOnComplete = false; t.play(); } } class Avoider { private var _bullets : Array; private var MAXXX : Number; private var MINXX : Number; private var MAXXY : Number; private var MINXY : Number; private var MYR : Number; private var LIMAX : Number; private var LIMAY : Number; private var STEPAX : Number; private var STEPAY : Number; public var _val : Number; private var _self : Bullet; public function Avoider( bullets : Array, maxxx : Number, minxx : Number, maxxy : Number, minxy : Number, myr : Number, limax : Number, limay : Number, stepax : Number, stepay : Number, self : Bullet ) : void { _bullets = bullets; MAXXX = maxxx; MINXX = minxx; MAXXY = maxxy; MINXY = minxy; MYR = myr; LIMAX = limax; LIMAY = limay; STEPAX = stepax; STEPAY = stepay; _self = self; } // もっとも長い時間生き残れる加速度の組を返す public function algo(xx : Number, xy : Number, vx : Number, vy : Number, depth : int) : Array { var ret : Array = [0.0, 0.0]; var maxval : Number = 0; for(var ax : Number = -LIMAX;ax <= LIMAX;ax += STEPAX){ for(var ay : Number = -LIMAY;ay <= LIMAY;ay += STEPAY){ // 最低速度を設ける if((vx + ax) * (vx + ax) + (vy + ay) * (vy + ay) < 0.3)continue; var val : Number = algoCore(xx, xy, vx, vy, ax, ay, 0, depth); if(maxval < val){ maxval = val; ret[0] = ax; ret[1] = ay; } } } _val = maxval; return ret; } private function algoCore(xx : Number, xy : Number, vx : Number, vy : Number, ax : Number, ay : Number, dt : int, depth : int) : Number { var mint : Number = 50; // wall var t : Number; t = solveQPositive(ax, vx, xx - (MAXXX - MYR)); if(!isNaN(t) && t < mint)mint = t; t = solveQPositive(ax, vx, xx - (MINXX + MYR)); if(!isNaN(t) && t < mint)mint = t; t = solveQPositive(ay, vy, xy - (MAXXY - MYR)); if(!isNaN(t) && t < mint)mint = t; t = solveQPositive(ay, vy, xy - (MINXY + MYR)); if(!isNaN(t) && t < mint)mint = t; // bullet for each(var b : Bullet in _bullets){ if(b == _self)continue; var mybr2 : Number = (MYR + b.r) * (MYR + b.r); var rxx : Number = xx - (b.x + b.v.x * dt); var rxy : Number = xy - (b.y + b.v.y * dt); var rvx : Number = vx - b.v.x; var rvy : Number = vy - b.v.y; for(t = 0;t < mint;t++){ if(rxx * rxx + rxy * rxy <= mybr2)break; rvx += ax; rvy += ay; rxx += rvx; rxy += rvy; } mint = t; } if(mint >= 1 && depth >= 1){ // recursion var maxval : Number = 0; var tt : int = mint - 1; var newxx : Number = (ax * (tt + 1) / 2 + vx) * tt + xx; var newxy : Number = (ay * (tt + 1) / 2 + vy) * tt + xy; var newvx : Number = ax * tt + vx; var newvy : Number = ay * tt + vy; for(var newax : Number = -LIMAX;newax <= LIMAX;newax += STEPAX){ for(var neway : Number = -LIMAY;neway <= LIMAY;neway += STEPAY){ var val : Number = algoCore(newxx, newxy, newvx, newvy, newax, neway, dt + tt, depth - 1); if(maxval < val){ maxval = val; } } } mint += maxval; } return mint; } // 0以上の最小解を求める private static function solveQPositive(a : Number, b : Number, c : Number) : Number { if(a > -0.0001 && a < 0.0001){ return -c / b; }else{ var D : Number = b * b - 4 * a * c; if(D < 0)return Number.NaN; var sqd : Number = Math.sqrt(D); var a1 : Number = (-b - sqd) / (2 * a); var a2 : Number = (-b + sqd) / (2 * a); if(a < 0){ var d : Number = a1; a1 = a2; a2 = d; } if(a1 >= 0)return a1; if(a2 >= 0)return a2; return Number.NaN; } } } TwitterBird