本連載ではActionScript 3.0の初心者の方を対象に、ActionScriptを使って表現を広げるためのテクニックを紹介していきます。ActionScript 3.0初心者向けに考え方や原理を解説するという目的のため、基本的には次のようなスタイルをとります。
第1回 スクリプトによるアニメーションの基本01
第2回 スクリプトによるアニメーションの基本02
第3回 複数のオブジェクトの制御方法
第1回目はアニメーションについて考えてみましょう。内容的には様々な書籍やセミナーでも扱われいるポピュラーなものですが、その分利用範囲が広く、次回以降のベースにもなるものです。知っているという方も改めて取り組んでみてください。
スクリプトでアニメーションを行うには、処理を繰り返す必要があります。例えば、「現在位置より5ピクセル右に移動する」という処理を繰り返すことで、右に移動するアニメーションになります。
ActionScript 3.0の場合、enterFrameイベントにイベントハンドラ(処理)を追加することでその処理を自動的に繰り返します。ムービークリップをはじめとする表示オブジェクトは、enterFrameイベントをサポートしています。また、メインタイムラインはデータとしてはムービークリップになるので、メインタイムラインもenterFrameイベントをサポートしています。enterFrameイベントにイベントハンドラを追加する書式は、以下のようになります。
【enterFrameイベントにイベントハンドラを追加する書式】
表示オブジェクト.addEventListener(Event.ENTER_FRAME, イベントハンドラ);
function イベントハンドラ(eventObj:Event):void {
処理
}
ムービークリップインスタンス_mcを5ピクセルずつ右に移動するアニメーションは、次にようになります。
_mc.addEventListener(Event.ENTER_FRAME, _mc_enterFrameHandler);
function _mc_enterFrameHandler(eventObj:Event):void {
_mc.x += 5;
}
移動のアニメーションには様々な方法があります。前項で例に挙げたアニメーションは、「終了位置を決めずにずっと移動する方法」でした。他にも「特定の移動終了位置まで移動する方法」などもあります。
特定の移動終了位置まで移動する方法の場合は、さらにフレーム数を決めて移動する「フレームベースの考え方」や、時間を決めて移動する「時間ベースの考え方」などがあります。フレームベースではアニメーションに使うフレーム数が固定され、フレームレートを変更するとアニメーションの時間が変化します。時間ベースではアニメーションの時間が固定され、フレームレートを変更するとフレーム数が変化します。
また、前の位置を基準に新たな位置を算出する「累積算出タイプの考え方」や、常に開始位置を基準に現在位置を算出する「個別算出タイプの考え方」などがあります。
それぞれ特徴について詳しい解説は省略しますが、色々な考え方があるのが理解できると思います。
さて、今回のサンプルで採用するアニメーションの方法は、上記の分類でいうと次のようなになります。
今回はアニメーションを制御するために「0~1」に変化する値を使います。移動開始位置から終了位置までの比率を考えると、0は開始位置、0.5は中間位置、1は終了位置になります。
つまり、「0~1の値」を「アニメーションの移動距離」に掛けることで、現在位置を算出することができます。この「0~1の値」が重要ポイントです。「0~1の値」を利用したアニメーションは応用範囲が広く、DisplayObject.alphaプロパティ(アルファ値)のような「0~1の値」で表されるプロパティとも相性がよく使えます。また、必ずしも「0~1」の範囲に限定する必要はなく、負の値や1より大きい値に範囲を広げて扱うこともあります。その場合はDisplayObject.scaleXプロパティDisplayObject.scaleYプロパティ(表示オブジェクトの拡大率)と相性がよくなります。
この「0~1の値」をどのように変化させるかで、アニメーションの表現が異なってきます。今回のサンプルは、1秒間の時間ベースのアニメーションです。まずは、「1秒間の時間経過」をもとに「0~1の値」を変化させてみましょう。なお、時間経過は等間隔で進むため、等速運動(アニメーション)となります。
「経過時間 / 1秒(=アニメーションの長さ)」から、アニメーションの進行度である「0~1の値」を求めることができます。例えば、0.1秒経過したら「0.1」の進行度。0.5秒経過したら「0.5」の進行度と考えられます。「終了位置までの距離(終了位置 - 開始位置)」にこの進行度を掛けると、開始位置からの移動距離を求めることができます。
【表示オブジェクトの水平位置の算出】
表示オブジェクト.x = 開始位置 + 距離 × 進行度
以下、アニメーション用ムービークリップ_mcが終了位置を表すムービークリップgoal_mcに1秒間で移動する処理を考えてみます。この例1ではスクリプトをシンプルにするために水平座標のみの移動としています。
//メインタイムライン:フレームアクション
//▼変数定義
var nDuration:Number = 1000;//アニメーションの長さ(ミリ秒)
var nStartX:Number = _mc.x;//_mcの移動開始位置
var nLengthX:Number = goal_mc.x - _mc.x;//距離(X方向)
var nStartTime:Number = getTimer();//開始時間
//▼処理実行
//アニメーション開始
_mc.addEventListener(Event.ENTER_FRAME, _mc_enterFrameHandler);
//▼関数定義
//enterFrameイベントハンドラ定義
function _mc_enterFrameHandler(eventObj:Event):void {
var nPastTime:Number = getTimer() - nStartTime;//経過時間を取得
var nTimeRate:Number = nPastTime / nDuration;//進行度(0~1)を取得
if (nTimeRate < 1) {//終了時間になっていなければ移動処理
_mc.x = nStartX + nLengthX * nTimeRate;//移動
}else{//終了時間になったら停止処理
_mc.x = goal_mc.x;//終了位置に合わせる
//アニメーション終了
_mc.removeEventListener(Event.ENTER_FRAME, _mc_enterFrameHandler);
}
}
だいたいはスクリプトコード中にコメントで説明しているので分かると思いますが、いくつか補足をしておきましょう。「▼変数定義」のブロックでは変数を用意しています。アニメーションの長さはミリ秒単位で変数nDurationに代入しています。この値を変更すると、アニメーションの移動時間が変わります。変数nStartTimeにはアニメーションの開始時間を代入しています。今回はSWF再生と共にアニメーションが始まるのですぐ開始時間を取得していますが、ボタンクリックでアニメーションを開始する場合にはクリック時に時間を取得することになります。
「▼関数定義」のブロックにあるenterFrameイベントハンドラ_mc_enterFrameHandler()の中では、経過時間から時間的な進行度(変数nTimeRate:0~1の値)を取得し、移動距離を算出して_mcの位置に反映しています。
「0~1の値」を扱う際に便利な道具となるのがsin値です。sin値は下図のように-1~1の範囲をとりますが、0~1の範囲を抜き出して使ったり、ある範囲を0~1になるように加工して使ったり、あるいはそのまま使ったりと色々な使い方ができます。
例えば、例1で時間的な進行度を使っていた部分をsin値に置き換えることで簡単なイージング(加速・減速効果)も表現できます。その場合、経過時間に応じたsin値を算出することになります。1秒間で、0°~90°までのsin値の変化を使う場合を考えてみます(図7:B~Cの範囲)
ActionScriptでsin値を求めるためには、角度をラジアンで扱う必要があります。ActionScriptで「0°~90°」をラジアンに置き換えると「0~Math.PI * 0.5」となります。このをsin値の範囲で考えると「0~1」になります。つまり、「1秒間で0~1に変化する値をsin値を使うことで求めよう」ということです。
経過時間に応じたsin値を算出するには、経過時間に応じた角度をラジアンで算出する必要があります。例えば、0.2秒経過したら時間的な進行度は0.2です。「0~Math.PI * 0.5」までの変化の0.2の時点の値なので「0.2 * Math.PI * 0.5」でその時点の角度(ラジアン)を求めることができます。sin値はMath.sin(0.2 * Math.PI * 0.5)で求めることができます。この例えでは開始角度が0なので分かりやすいですが、開始角度が0でない場合を考慮すると進行度に応じたsin値は次のようして求めることができます。
【進行度に応じたsin値の算出】
変化の範囲 = 終了角度 - 開始角度
sin値 = Math.sin(変化の範囲 × 進行度(0~1) + 開始角度)
次の例2では、1秒間で-90°~90°(ラジアンでは「-Math.PI * 0.5~Math.PI * 0.5」)までのsin値の変化を使ってアニメーションさせます(図6:A~Cの範囲)。ただし、この場合のsin値は「-1~1」の範囲になってしまいます。「-1~1」の範囲を「0~1」に調整するには「(sin値 + 1) * 0.5」のように加工します。以下、例1を元にsin値を使った移動に変更したサンプルスクリプトです。
//メインタイムライン:フレームアクション
//▼変数定義
var nDuration:Number = 1000;//アニメーションの長さ(ミリ秒)
var nStartX:Number = _mc.x;//_mcの移動開始位置
var nLengthX:Number = goal_mc.x - _mc.x;//距離(X方向)
var nStartTime:Number = getTimer();//開始時間
var nOffsetRadian:Number = -Math.PI * 0.5;//角度(ラジアン)
//▼処理実行
//アニメーション開始
_mc.addEventListener(Event.ENTER_FRAME, _mc_enterFrameHandler);
//▼関数定義
//enterFrameイベントハンドラ定義
function _mc_enterFrameHandler(eventObj:Event):void {
var nPastTime:Number = getTimer() - nStartTime;//経過時間を取得
var nTimeRate:Number = nPastTime / nDuration;//進行度(0~1)を取得
if (nTimeRate < 1) {//終了時間になっていなければ移動処理
//sin値により-1~1の範囲の値を算出
var nSinRate:Number = Math.sin(Math.PI * nTimeRate + nOffsetRadian);
//0~1に加工
nSinRate = (nSinRate + 1) * 0.5;
_mc.x = nStartX + nLengthX * nSinRate;//移動
}else{//終了時間になったら停止処理
_mc.x = goal_mc.x;//終了位置に合わせる
//アニメーション終了
_mc.removeEventListener(Event.ENTER_FRAME, _mc_enterFrameHandler);
}
}
sin値そのままのイージングは少々効果が緩めですが、お手軽に使えるのでオススメです。
今回はsinを扱いました。せっかくなので次回はcos(コサイン)も扱います。簡単な3D表現にも挑戦します。お楽しみに。