2010年01月15日
続・パーフェクトシャッフルは何回で元に戻るか (AS3版)
前回の続きで最初と最後がつながるところをアニメーションさせてみることにした。
アニメーションの雛形作成
四角から円をどのように作るか悩んだのだけど、扇形を徐々に広げていく形で変換してやった。バームクーヘンの1人前から始まり、徐々にバームクーヘンの1ホールになっていく、と言ってもいいだろう。こんな感じ。
この実験は Square to Donut として Wonderfl に投稿してある。
(はてなダイアリーに wonderfl の作品を iframe で貼り付けても失敗する。title="" を取り除いてもダメだけど何でだろ...)
線の当てはめ
アニメーションの大枠ができたら、扇上に前回のシミュレーション結果を貼り付けて、変形に応じて座標を変えていけばよい。sin とか cos を駆使して座標変換を行えば終わり。
ソースは以下に(80行)。wonderfl にも投稿済み。
package { import flash.display.*; import flash.events.Event; import flash.geom.Point; import flash.filters.BlurFilter; import flash.text.TextField; import org.libspark.betweenas3.BetweenAS3; import org.libspark.betweenas3.tweens.ITween; import org.libspark.betweenas3.easing.*; import frocessing.color.ColorHSV; [SWF(backgroundColor="0x000000")] public class PerfectShuffleVisualization2 extends Sprite { public var r:Number = 800; public var d:Number = 80; public var angle:Number = 6; private const NUM:int = 5; private const SIZE:int = 30; private var msk:Sprite; public function PerfectShuffleVisualization2() { stage.scaleMode = "noScale"; stage.align = "TL"; var t:TextField = new TextField(); t.text = "Click to play!!"; t.textColor = 0xffffff; addChild(t); x = 240; y = 240; draw(); var tween:ITween = BetweenAS3.parallel( BetweenAS3.tween(this, { r: 30 }, null, 5, Quint.easeOut), BetweenAS3.tween(this, { angle: 360, d: 160 }, null, 5) ); tween.onUpdate = draw; stage.addEventListener("click", function(event:Event):void { if (t.parent) t.parent.removeChild(t); tween.play(); }); filters = [new BlurFilter(2, 2)]; } private function draw():void { var p:Point = new Point(); var g:Graphics = graphics; g.clear(); // draw lines for (var yy:int = 0; yy < SIZE; yy++) { var num:int = yy; g.lineStyle(2, new ColorHSV(yy * 270 / SIZE, .7).value, .7); p.x = 0; p.y = num; getXY(p); g.moveTo(p.x, p.y); for (var xx:int = 1; xx <= NUM; xx++) { num = getNext(num); p.x = xx; p.y = num; getXY(p); g.lineTo(p.x, p.y); } } } // get next position after perfect shuffle private function getNext(num:int):int { if (num < SIZE / 2) { return num * 2 + 1; } else { return (num - SIZE / 2) * 2; } } private function getXY(pt:Point):Point { var rad:Number = (-angle / 2.0 + angle * pt.x / NUM) / 180.0 * Math.PI; pt.x = (r + d / (SIZE - 1) * pt.y) * Math.sin(rad); pt.y = -(r + d / (SIZE - 1) * pt.y) * Math.cos(rad) + r * Math.cos(angle / 2 / 180 * Math.PI); return pt; } } }