ActionScript 3.0で始めるオブジェクト指向スクリプティング

第16回三角関数を使った楕円軌道のアニメーション

三角関数のcosとsin関数は、角度の変化に対して値がバネや波の動きのように増減する。これらの関数を使うと、円や楕円軌道を描くアニメーションがつくれる。

バネのように振動するアニメーション - cosとsin関数

楕円軌道の前に、一方向にバネのように揺れるアニメーションを作成してみよう。cosもsin関数も、0を中心に±1の間を値が振動のように増減する図1⁠。

図1 角度の変化に対するcosとsin関数の値
図1 角度の変化に対するcosとsin関数の値

まずは、cos関数を使って、インスタンスを水平に揺らしてみる。使うメソッドはMath.cos()で、引数には角度となる数値を渡す。中心座標をステージ中央、揺れ幅を左右にそれぞれ100ピクセルとしよう。振幅はcos関数に掛け合わせ、中心座標はその値を加算すればよい。

  • 振動する水平座標=中心座標+cosθ×振幅

アニメーションさせるには、もちろんリスナー関数をインスタンスのDisplayObject.enterFrameイベント(定数Event.ENTER_FRAMEに登録する。振動させるインスタンスに記述するフレームアクションは、つぎのスクリプト1のとおりだ。

スクリプト1 インスタンスを水平に振動させるフレームアクション
// MovieClip: 振動させるインスタンス
var nRadian:Number = 0;
var nCenterX:Number = stage.stageWidth/2;
var nRadiusX:Number = 100;
addEventListener(Event.ENTER_FRAME, xMoveX);

function xMoveX(eventObject:Event):void {
  x = nCenterX+Math.cos(nRadian)*nRadiusX;
  nRadian += 0.1;
}

[ムービープレビュー]で確かめると、上記フレームアクションスクリプト1を記述したインスタンスが、バネの振動のように水平に揺れ動く図2⁠。

図2 インスタンスが水平方向に揺れ動く
図2 インスタンスが水平方向に揺れ動く

つぎに、sin関数を使って、垂直方向に振動するアニメーションをつくってみる。用いるメソッドはMath.sin()で、考え方は水平方向の場合と同じだ[1]⁠。

  • 振動する垂直座標=中心座標+sinθ×振幅

インスタンスに記述するフレームアクションは、以下のスクリプト2のとおりだ。三角関数のメソッドをMath.sin()に変えたほか、参照するプロパティ、変数名や関数名などを修正した。ただし、角度の変数(nRadian)は同じである。

スクリプト2 インスタンスを垂直に振動させるフレームアクション
// MovieClip: 振動させるインスタンス
var nRadian:Number = 0;

var nCenterY:Number = stage.stageHeight/2;
var nRadiusY:Number = 100;
addEventListener(Event.ENTER_FRAME, xMoveY);
function xMoveY(eventObject:Event):void {
  y = nCenterY+Math.sin(nRadian)*nRadiusY;
  nRadian += 0.1;
}

円や楕円軌道のアニメーション

前掲スクリプト1と2を合わせて、水平・垂直両方向のアニメーションにしてみよう。ただし、角度の変数値(nRadian)は2度加算する必要はないので、別のリスナー関数xUpdate()として定義するスクリプト3※2⁠。

スクリプト3 水平・垂直両方向の振動を合わせたフレームアクション
// MovieClip: 振動させるインスタンス
var nRadian:Number = 0;
var nCenterX:Number = stage.stageWidth/2;
var nCenterY:Number = stage.stageHeight/2;

var nRadiusX:Number = 100;
var nRadiusY:Number = 100;
addEventListener(Event.ENTER_FRAME, xMoveX);
addEventListener(Event.ENTER_FRAME, xMoveY);
addEventListener(Event.ENTER_FRAME, xUpdate);
function xMoveX(eventObject:Event):void {
  x = nCenterX+Math.cos(nRadian)*nRadiusX;
}
function xMoveY(eventObject:Event):void {

  y = nCenterY+Math.sin(nRadian)*nRadiusY;
}
function xUpdate(eventObject:Event):void {
  nRadian += 0.1;
}
図3 インスタンスが円軌道を描いて回る
図3 インスタンスが円軌道を描いて回る

[ムービープレビュー]を見ると、インスタンスのアニメーションは円軌道を描く。このように、与える角度を同じにして、x座標とy座標に対しそれぞれcos値とsin値に半径を乗じて設定すると、⁠x, y)座標は円軌道上を動くことになる。

  • 円軌道の水平座標=水平中心座標+cosθ×半径
  • 円軌道の垂直座標=垂直中心座標+sinθ×半径

ところで、Math.cos()Math.sin()メソッドに引数として渡す角度は度数ではない。変数名(nRadian)からも推測できるとおり「ラジアン」だ。ラジアンは角度を、半径1の円の弧の長さで表す図4⁠。度数とラジアンは、以下の式で変換される[3]⁠。

  • 度数=ラジアン×(180/π)
  • ラジアン=度数×(π/180)
図4 ラジアンは角度を半径1の円弧の長さで示す
図4 ラジアンは角度を半径1の円弧の長さで示す

角度の変数(nRadian)に毎フレーム加算していた0.1というのは、度数では約5.73度(= 0.1×180/3.14)になる。スクリプトの処理は、ラジアンをベースにしてもとくに問題はない。しかし、インスタンスの開始位置を決めたり、角度の計算をしようという場合、度数がわかると便利なことも少なくない。そこで、度数をベースとした処理に書替える。また、半径としてcosおよびsin値に掛合わせている値を、水平方向(nRadiusX)と垂直方向(nRadiusY)とで変えてみよう。

以下のフレームアクションスクリプト4では、度数の変数(nDegree)を宣言し、毎フレーム5度(nSpeed)回転させることにした。度数からラジアンへの変換係数は、変数(nDegreeToRadian)に代入しておく。cos値やsin値も、あとでスクリプトを拡張するため、変数(nCosおよびnSin)として宣言しておく。変数値の更新は、基本的に関数xUpdate()にまとめている。

スクリプト4 インスタンスを楕円軌道で回転させるフレームアクション
// MovieClip: 振動させるインスタンス
var nDegree:Number = 0;
var nRadian:Number = 0;
var nSpeed:Number = 5;

var nDegreeToRadian:Number = Math.PI/180;
var nCenterX:Number = stage.stageWidth/2;
var nCenterY:Number = stage.stageHeight/2;
var nRadiusX:Number = 100;
var nRadiusY:Number = 50;
var nCos:Number = Math.cos(nRadian);

var nSin:Number = Math.sin(nRadian);
addEventListener(Event.ENTER_FRAME, xMoveX);
addEventListener(Event.ENTER_FRAME, xMoveY);
addEventListener(Event.ENTER_FRAME, xUpdate);
function xMoveX(eventObject:Event):void {
  x = nCenterX+nCos*nRadiusX;
}
function xMoveY(eventObject:Event):void {

  y = nCenterY+nSin*nRadiusY;
}
function xUpdate(eventObject:Event):void {
  nDegree += nSpeed;
  nDegree = (nDegree%360+360)%360;
  trace(nDegree);  // 確認用

  nRadian = nDegree*nDegreeToRadian;
  nCos = Math.cos(nRadian);
  nSin = Math.sin(nRadian);
}

上記スクリプト4で説明が必要なのは、関数xUpdate()で度数値(nDegree)を加算したあとに行っている演算の内容だ。これは、度数値を0から360までの間の数値に変換する処理になる。

  • nDegree=(nDegree%360+360)%360

ActionScriptのNumber型変数で扱える数値には、もちろん上限がある[4]⁠。だから、際限なく値を加算し続けるという処理は危うい。そして、度数は360度周期なので、90度も450度も同じ角度だ。したがって、度数値(nDegree)を0から360度の範囲に限定しようというのが上記ステートメントである。

%は剰余、つまり割った余りを求める演算子だ。450の360に対する剰余(= 450%360)は90となる。よって、正数であれば、以下のステートメントで0以上360未満の値に変換できる。

  • nDegree=nDegree%360

しかし、今後のスクリプトの拡張で、負の角度を扱うかもしれない。負の値の場合の剰余は、-360から0までの値になる。したがって、それを正の値の0から360までに変換するには、上記スクリプト4のようなステートメントにする必要がある。

[ムービープレビュー]を確かめると、インスタンスは楕円軌道を描いて回転する。cos値およびsin値に掛合わせる半径を、水平方向(nRadiusX)と垂直方向(nRadiusY)で変えると、楕円軌道の座標を導く式になるのだ図5⁠。

  • 楕円軌道の水平座標=水平中心座標+cosθ×水平方向の半径
  • 楕円軌道の垂直座標=垂直中心座標+sinθ×垂直方向の半径
図5 水平方向と垂直方向の半径を変えると楕円軌道のアニメーションになる
図5 水平方向と垂直方向の半径を変えると楕円軌道のアニメーションになる

前掲スクリプト4には、変数に設定された度数値を[出力]するステートメントを加えた。[出力]パネルに表示される値が、0以上360未満であることを確認しよう。

次回は、このインスタンスのアニメーションに遠近感を加えてみたい。

今回解説した次のサンプルファイルがダウンロードできます。

おすすめ記事

記事・ニュース一覧