アクセシビリティ
デベロッパーリソース

目次

デベロッパー/デザイナー向けActionScript 3.0講座 パート1:プレローダー

タイムライン

まずはじめに、デベロッパーのみなさんにお知らせです。タイムラインは、デベロッパーさんの敵ではありません。むしろ、友達と言っていいくらいです。協力者です。ぜひとも、タイムラインを使いましょう。

<タイムラインって本当に役立つの?>

デベロッパーの方々は、「アートワークをステージに配置するときは、ダイナミックに配置した方がタイムラインも整理できるのでよい」と教わっているのではないでしょうか。もっともらしく聞こえますが、実際はというと、みなさんが思っているほど役立つ教えではありません。

この記事ではプレローダーを作りますが、私はプレローダーを直接ステージに配置しています。その理由は、ダイナミックに配置する場合はディスプレイ領域の中心を計算しなければなりませんが、その手間が省けるからです。「x = width * stageWidth/2 + someOffset」といったコードを書く必要はありません。私の代わりにFlashが計算をしてくれるので、その分、私はプレローダーを自分の思い通りの位置に配置することに集中できます

プレローダーをステージの中心に配置し、プレローダーのタイムラインを図1のように作成してフレームラベルを付けました。

Timeline of the preloader including frame labels for each section

図1. プレローダーのタイムライン。各セクションにはフレームラベルを付けています

タイムラインだけでなく、さらにフレームラベルも付けました。その理由は、フレームラベルを使えば、アニメーションの内容が一目瞭然となるからです。「フレーム2で登場してきて、フレーム37で消え始める」といった内容をいちいちメモしておかなくても、フレームラベルの「IN」と「OUT」という文字を見れば、そのアニメーション内容がわかります。

タイムラインを活用すれば、ステージ上でプレローダーを表示する際の位置が思い通りにならずに試行錯誤することはありません。しかも、デザイナーがプレローダーを修正したい場合でも、簡単に行うことができます。INのラベルを付けた部分のアニメーションに10フレーム分追加したくなったとしても、問題ありません。さらにプレローダーの色をグリーンからパープルにしたい? もちろん大丈夫です。見た目をワイングラスにして、ローディングが進むごとにグラスが満たされるようにしたい? どうぞ、できますよ。つまり、タイムラインを使えば、「コンテンツのプレローディング」というプレローダーの本質的な機能を損なわずに、ルック&フィールを自由に変更することができるのです。

<プレローダーのタイムライン>

この記事で作成するプレローダーは、いろいろな状況に対応でき簡単に使い回しができるようにするため、以下のように設計しました。

  1. ローディングを開始する準備ができたら、プレローダーのタイムラインにIN(登場)アニメーションを再生するように指示する。
  2. プレローダーのINアニメーションが完了したら、「progress_mc」と名付けたムビークリップをステージ上に配置する。
  3. ローディングが進行状況に応じて、ロード済の割合(%)を算出し、progress_mcムービークリップのタイムラインのロード済の割合に該当するフレームを再生する。
  4. progress_mcムービークリップのタイムラインが最後まで再生されたら、つまりロードが完了し100%になったら、プレローダーのタイムラインにOUT(消失)アニメーションを再生するように指示する。
  5. プレローダーのタイムラインのOUTアニメーションが完了したら、サイトあるいはアプリケーションにその旨を通知し、プレローダーを再利用するためにリセットする。

わりと分かりやすい設計です。ただ、いつINやOUTのアニメーションが完了したのかをどうやって調べるのか気になる人もいるでしょう。それについては、次の項目で解説します。

<イベント、リスナー、イベントディスパッチ、イベントフック>

ActionScript 3.0ではイベントディスパッチ(イベント送出)という概念があります。ActionScript 1.0や2.0の経験がある人ならば、十分に理解していなくても、なんとなく分かるのではいないでしょうか。たとえば、以下のようなコードがあります。

var mouseListener = new Object();
mouseListener.onMouseDown = function() {
  trace("The mouse button is down.");
};
Mouse.addListener(mouseListener);

mouseListenerオブジェクトは、Mouseクラスのイベント(onMouseDown)を監視しています。そのイベント、つまりユーザーがマウスボタンを押したときに、MouseクラスはonMouseDownイベントをディスパッチ(送出)します。そして、mouseListenerオブジェクトがonMouseDown関数を実行します。イベントディスパッチの特長は、複数のオブジェクトが同じ1つのイベントを監視しつつ、そのイベントが起きたときにオブジェクトごとに異なる処理を設定できるというところにあります。以下のコードは、その例です。

var mouseListener1 = new Object();
var mouseListener2 = new Object();
mouseListener1.onMouseDown = function() {
  trace("the mouse button is down.");
};
mouseListener2.onMouseDown = function() {
  trace("1+1=" + (1+1));
};
Mouse.addListener(mouseListener1);
Mouse.addListener(mouseListener2);

2 つのリスナーがあります。2つのリスナーとも同じイベントを監視していますが、そのイベントが起きた際は異なる処理を行うようになっています。上記の例では、両方のリスナーとも出力パネルに違うメッセージをトレース出力しています。もちろんまったく異なる処理を実行させることも可能です。

オブジェクト指向プログラミングを習得したい、特にクラス作成に興味があるという人は、このイベントディスパッチ概念は非常に重要なものなので、ぜひ押さえておいてください。クラスの内容に関係なく、複数のクラスが同じイベントを扱うことができるのです。

<オブジェクト指向プログラミングの補足説明>

先ほどオブジェクト指向プログミラングについて触れましたが、少し実際のコードから離れて、現実の世界に置き換えて考えてみましょう。あなたのコードはファーストフードレストラン「ActionScriptカフェ」だとします。そして、ユーザーは、そこに来るお客さんでお腹がすいています。お客さんが何かを注文したい。そのとき、あなたのレストラン(ActionScriptコード)での対応は、以下の2つが考えられます。

  • シナリオ1: お客さんがウェイターに欲しいものを伝える。それから、ウェイターかお客さんのどちらかが、クックにそれを伝えることになっている。そしてウェイターか、お客さんか、クックの誰かが料理を作ることになっている…このように誰が何をすべきなのかが明確でないと混乱が起きてしまい、非常に効率が悪くなってしまいます。
  • シナリオ2: お客さんはタッチスクリーンを使って注文する(残念ながら、ウェイター職をタッチスクリーンに奪い取られたのです)。注文内容がクックとレジ係に伝わり、料理が出され、支払いが行われる。クックは食材の調理方法を知っていますし、レジ係はレジの扱い方を知っています。クックは、お客さんの支払いのことは気にする必要はありません。ちゃんと払ってくれるだろうと思っておけばいいのです。一方で、レジ係は料理のことを気にする必要はありません。料理に問題があれば、それはレジ係の責任ではなく、クックの責任となるからです。

これをプログラミングに置き換えると、シナリオ1は古いスタイルのプログラミング方法です。どの時点で何が起きているのかが把握しづらく、バグがあっても解決するのが困難です。シナリオ2は理想的なプログラミング方法です。料理に問題があればクッククラスを調べればよく、レジに問題があればレジ係クラスを調べればいいのです。もし両方に問題があれば、タッチスクリーンクラスを調べるのです。とにかく、このように役割分担を明確にすることで、コードは整理され管理しやすくなります。

<ActionScript 3.0でのイベントハンドリング>

それでは、プレローダーを例に、ActionScript 3.0でイベントがどのように作用するかを説明しましょう。ActionScript 3.0では、独自のイベントを定義できます(ActionScript 2.0でも同様に行えます)。さらに、ムービークリップはEvent Dispatcherを拡張します。つまり、先ほどのコード例と同じ方法でムービークリップはイベントをディスパッチすることができます。この特徴がいかに役立つことなのかを、プレローダーを例にお見せしましょう。再度図1を見てください。タイムラインのIN_IDLEフレームラベルのところにコードがあります。

import com.bigspaceship.events.AnimationEvent;
dispatchEvent(new AnimationEvent(AnimationEvent.ANIMATE_IN));
stop();

importステートメントは、外部クラス(後述します)をこのタイムラインで使用するために読み込むためのコードです。AnimationEventは私が作ったカスタムイベントで、ここではAnimationEvent.ANIMATE_INイベントをディスパッチします。このイベントの内容はシンプルです。 ActionScript 1.0でonMouseDown イベントが起きることによって「マウスが押された」ことが検知できるのと同じように、リスナーは、AnimationEvent.ANIMATE_INを監視し、「タイムラインのINフレームラベルのアニメーションが完了した」こと検知します。タイムラインのOUT_IDLEフレームラベルにも似たようなコードを記述しています。

import com.bigspaceship.events.AnimationEvent;
dispatchEvent(new AnimationEvent(AnimationEvent.ANIMATE_OUT));
stop();

同じようにdispatchEventを使って、「タイムラインのOUTフレームラベルのアニメーションが完了した」ことをディスパッチしています。私は、これらのイベントを「イベントフック」と呼んでいます。INやOUTのアニメーションが再生されているとき、コードでは待機して監視しているのです。そしてイベントフックに到達すると、プレローディングを進めるようにロジックを作っています。イベントハンドリングの詳細については、Introduction to event handling in ActionScript 3.0を見てください。