勝手に添削:数学的な曲線を描画する
[ActionScript3.0] 数学的な曲線を描画する サイクロイド、三葉線、螺旋等[AS3] | moriBlog - ActionScriptとか、気になるニュースのメモ が面白かったのだけど、ソースが気になったので勝手に添削してみた。
気になったところ
こんな調子で draw01~draw07まで並んでる。
//円を描く(中心点座標を引数に) function draw01(xp:Number,yp:Number):void{ canvas = new MovieClip(); addChild(canvas) canvasArray.push(canvas) var shape01:DrawCircle = new DrawCircle(canvas,Math.random()*180,xp,yp); } //三葉線を描く(中心点座標を引数に) function draw02(xp:Number,yp:Number):void{ canvas = new MovieClip(); addChild(canvas) canvasArray.push(canvas) var shape02:DrawThreeLeaves = new DrawThreeLeaves(canvas,Math.random()*180,xp,yp); } //(アルキメデスの)螺旋を描く(中心点座標を引数に) function draw03(xp:Number,yp:Number):void{ canvas = new MovieClip(); // 以下略...
draw01~draw07 を呼ぶところも悲しいぐらいの列挙。
if(curveMode == "circle")draw01(mouseX,mouseY); else if(curveMode == "ThreeLeaves") draw02(mouseX,mouseY); else if(curveMode == "Archimedes") draw03(mouseX,mouseY); // 以下略...
ほとんど同じ内容なのに、ベタッと勢いで書き下されているのは気持ち悪い。まとめて1箇所で処理したくなるのがプログラマ魂。
どうするか
共通部分を見極めて、くくりだしていく。違うところは変数なりオブジェクトなりで表現する。
drawXX 関数をみてみると、new するクラスが違うぐらい。なので、クラス一覧を shapes という配列に入れちゃう。
private var shapes:Array = [DrawCircle, DrawThreeLeaves, DrawArchimedes, DrawAsteroid, DrawHypocycloid, DrawLissajous, DrawFourLeaves];
こうしてしまえば、あとは1つの関数を呼び出すだけで、7個の関数を代用できる。
function draw(xp:Number, yp:Number):void{ var Drawer:Class = shapes[curveMode] as Class; if(!Drawer){ return; } canvas = new MovieClip(); addChild(canvas) canvasArray.push(canvas) new Drawer(canvas,Math.random()*180, xp, yp); }
curveMode は 0~7 の数字。キーボード入力イベントハンドラで次のようにして設定している。
private function KeyDownHandle(e:KeyboardEvent):void{ if(49 <= e.keyCode && e.keyCode < 49 + shapes.length){ curveMode = e.keyCode - 49; // ← ココ! dtext.text = names[curveMode]; } else if(e.keyCode == 49 + shapes.length){ eraser(); } }
1~8までのキーコードが1ずつ増えていってるのを利用している。49 というマジックナンバーが気持ち悪い場合は、"0".charCodeAt(0) などと書けばいいと思う。
呼び出す関数が1つになったので、draw01~draw07 を呼んでいたところはこう書ける。条件分岐いらないよ!
function clickHandle(e:MouseEvent):void{ draw(mouseX, mouseY); }
こうなったよ
全体として、ソースはこんな感じになった。mxmlc でビルドできるように、一部に手は入れたが、可能な限り元々の設計は残しておいた。
元のソースに比べて、随分とすっきりした。ただ、元のものにはあった半径のパラメータが消えていたり、内サイクロイド(DrawHypocycloid)でコンストラクタの引数の数が違って例外が出たりする。
まだまだ、不十分なので、もう少しいじっていくことにする。(続く)
package{ import flash.display.*; import flash.events.*; import flash.text.*; public class Test extends Sprite{ private var dtext:TextField; private var canvasArray:Array = []; private var curveMode:int = 0; private var shapes:Array = [DrawCircle, DrawThreeLeaves, DrawArchimedes, DrawAsteroid, DrawHypocycloid, DrawLissajous, DrawFourLeaves]; private var names:Array = ["円", "三葉線", "螺旋", "アステロイド曲線", "内サイクロイド", "リサジュー曲線", "四葉線"]; public function Test(){ addChild(dtext = new TextField()); dtext.text = names[curveMode]; stage.addEventListener(MouseEvent.CLICK,clickHandle); stage.addEventListener(KeyboardEvent.KEY_DOWN,KeyDownHandle); } private function draw(xp:Number, yp:Number):void{ var Drawer:Class = shapes[curveMode] as Class; if(!Drawer){ return; } canvas = new MovieClip(); addChild(canvas) canvasArray.push(canvas) new Drawer(canvas,Math.random()*180, xp, yp); } private function clickHandle(e:MouseEvent):void{ draw(mouseX, mouseY); } private function eraser():void{ for(var i:int = 0; i < canvasArray.length; i++){ removeChild(canvasArray[i]); } canvasArray = []; } private function KeyDownHandle(e:KeyboardEvent):void{ if(49 <= e.keyCode && e.keyCode < 49 + shapes.length){ curveMode = e.keyCode - 49; dtext.text = names[curveMode]; } else if(e.keyCode == 49 + shapes.length){ eraser(); } } } }