勝手に添削:数学的な曲線を描画する
[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();
}
}
}
}