前のページでは、1つのイベントに対して複数のリスナーが検知し、それぞれ異なる処理を実行できることを説明しました。また、カスタムイベントの作成例や、それを使ってどのようにタイムラインでのアニメーション完了をイベントとしてディスパッチするかを紹介しました。この手法を使えば、特定のタイミングで関数を呼び出すことができます。プレローダーでロード状況(%)を正確に表示するには、まさにこの手法が最適です。また、今回のサンプルでは、外部クラスを使用するためにimportステートメントを使用しています。それでは、ActionScriptのクラスについて詳しく解説して行きましょう。クラスを使ったモジュールコーディングは、役立つコーディング手法なのでぜひ覚えてください。
クラスにはコードの書き方があります。初心者は、シンプルなコードからクラスへと発展させていくといいでしょう。慣れてくれば、今のコードの書き方よりもクラスの書き方のほうが分かりやすく感じるようになると思います。以下は、簡単なクラスコードの例です。
package
{
public class MyClass
{
var myVar:String // クラスの変数(プロパティともいいます)
function MyClass() { } // コンストラクタ。新しくMyClass()を作成すると、この関数が自動で実行されます
function doSomething() {} // クラスの関数(メソッドともいいます)。クラスに何かをさせるためにこの関数を呼びます
}
}
クラスではimportステートメントを使って他のクラスを読み込んで利用することができます。先ほどのタイムラインのコードでは、「com.bigspaceship.events.AnimationEvent」を読み込んでいます。Flashのクラスやオブジェクト指向プログラミングに関する本はたくさんありますが、中でも私が役立つと思うのはColin Moockの『Essential ActionScript 3.0』です。彼の本は常に私の机の上に置いています。
プレローダークリップは特殊なムービークリップです。プレローダークリップは、基本的なムービークリップメソッド(startDragやstopDragなど)とプロパティ(x、y、alphaなど)を持っているほか、ローディング用のカスタム機能も持っています。
MovieClipクラスを利用するので、以下のように記述します。
package com.bigspaceship.frameworks.site
{
import flash.display.MovieClip
public class PreloaderClip extends MovieClip
{
function PreloaderClip() {};
};
};
ここで注目してほしいのは、4行目の「extends MovieClip」です。プレローダークリップはMovieClipクラスを拡張したものです。プレローダークリップの1フレーム目には「stop();」を記述しています。これは、指示があるまでプレローダーのアートワークが表示されないようにするためです。プレローダーを表示させたら、INフレームラベルのセクションを再生させるので、以下のようなメソッドを作ります。
public function animateIn():void
{
gotoAndPlay("IN");
addEventListener(AnimationEvent.ANIMATE_IN,
_onPreloaderIn,false,0,true);
};
このメソッドでは、タイムラインにINアニメーションを再生させるように指示しているとともに、私が作成したカスタムイベントAnimationEvent.ANIMATE_INを監視しています。そのイベントが検知した場合は、自動的に_onPreloaderIn関数を呼び出します。_onPreloaderIn関数は以下のようになっています。
private function _onPreloaderIn($evt:Event):void
{
progress_mc.addEventListener(Event.COMPLETE,_onProgressBarComplete,false,0,true);
progress_mc.addEventListener(Event.ENTER_FRAME,_onProgressEnterFrame,false,0,true);
progress_mc.stop();
dispatchEvent(new Event(Event.INIT));
};
プレローダークリップ内には、progress_mcという名前のムービークリップが入れ子で入っています。このprogress_mcムービークリップは、準備が整わないうちにロード状況を表示してしまわないように一旦ストップさせておき、さらに「Event.COMPLETE」と
「Event.ENTER_FRAME」の2つの新しいイベントを監視させています。
ENTER_FRAMEは、onEnterFrameイベントを扱うための新しい方法です。ここでは、毎フレームごとに_onProgressEnterFrame関数を呼び出しています(詳細はのちほど)。Event.COMPLETEは、progress_mcムービークリップのタイムラインの最後にあるイベントフックです。progress_mcムービークリップのタイムラインの最後まで再生したら、ローディング完了ということです。
dispatchEventの行はとても重要なコードです。プレローダークリップが、リスナーに何かが起きたことを知らせるためのものです。私が作成したイベントフックのように、addEventListener()をどこかに記述して、プレローダーの準備が整ってローディングを開始してもよいタイミングを知ることができます。
では、ENTER_FRAME時に呼び出す_onProgressEnterFrame関数のコードを見てみましょう。
private function _onProgressEnterFrame($evt:Event):void
{
(_targetFrame > progress_mc.currentFrame) ? progress_mc.play() : progress_mc.stop();
var totalPct:Number = Math.round((progress_mc.currentFrame/progress_mc.totalFrames) * 100);
try
{
pct_mc.tf.text = totalPct.toString();
}
catch($error:Error)
{
Out.debug(this,"% loaded: " + totalPct.toString());
}
};
これがプレローダーの秘密部分です。実は、プレローダークリップは何もロードしていません。ただ、進行状況を表示しているだけです。外部から必要なファイルをロードして、そのロード状況に応じて、以下の情報をプレローダークリップに渡しているのです。
つまり、アイテムを順々にロードして行きます。たとえば、XMLファイル、SWFファイル、JPEGファイルをロードするとしたら、最初にXMLファイルをロードします。この場合、itemsLoadedは2のうちの0となります(ご存知の通り、常に0からカウントするからです)。XMLファイルのロードが完了したら、次はSWFファイルをロードします。itemsLoadedは1となります。最後にJPEGファイルをロードします。itemsLoadedは2となります。JPEGファイルのロードが完了すると、progress_mcムービークリップのタイムラインは最後まで再生されます。コンテンツが100%ロードされ、プレローダークリップはEvent.COMPLETEイベントを検知して、自動的に_onProgressBarComplete関数を実行します。
private function _onProgressBarComplete($evt:Event = null):void
{
_isLoadComplete = true;
progress_mc.removeEventListener(Event.ENTER_FRAME,_onProgressEnterFrame); _animateOut();
};
private function _animateOut():void
{
gotoAndPlay("OUT");
addEventListener(AnimationEvent.ANIMATE_OUT, _onPreloaderOut,false,0,true);
};
この関数では、プレロードの完了を受けて、タイムラインのOUTアニメーションを開始します。そして、イベントフック「AnimationEvent.ANIMATE_OUT」に到達すると、_onPreloaderOut関数を実行します。
private function _onPreloaderOut($evt:Event):void
{
// プレローダーの再利用に備えて、リスナーをクリアします
// もしクリアを忘れると、_onPreloaderIn()を2度実行することになり、イベントフック「ANIMATE_IN」に到達した時点ですべてが台無しになってしまいます
removeEventListener(AnimationEvent.ANIMATE_IN,_onPreloaderIn);
removeEventListener(AnimationEvent.ANIMATE_OUT,_onPreloaderOut);
if(_isLoadComplete) dispatchEvent(new Event(Event.COMPLETE));
else animateIn();
};
この関数では、リスナーをクリアして、Event.COMPLETEイベントをディスパッチしています。こうしてリスナーに「プレローダークリップが完了して、ステージにロードしたコンテンツを表示できるようになった」ことを伝えます。
このプレローダーを使ってみましょう。本記事のサンプルにはもう1つMainというクラスを用意しています。この Mainクラスは、Document Rootクラスです。Document Rootはメインタイムラインのクラスです。SWFがロードされたとき、Document Rootは制御クラスになります。このMainクラスをセットするには、ステージのどこでもいいのでクリックして、使いたいクラスへのクラスパスを記述します。今回の場合、パッケージ内に入れ込むのではなく、単にMainと名付けて、Main.asファイルとして保存しています。以下は、Main.asの内容です。
public function Main()
{
Out.enableAllLevels();
Out.status(this,"Ready to go!");
// まずはじめに、プレローダークリップが完了した際にその旨を通知するように設定します。なお、Mainはメインタイムラインでpreloader_mcはプレローダークリップです。
preloader_mc.animateIn();
preloader_mc.addEventListener(Event.INIT,_onPreloaderIn,false,0,true);
preloader_mc.addEventListener(Event.COMPLETE,_onPreloaderOut,false,0,true);
};
private function _onPreloaderIn($evt:Event):void
{
_loadCount = 0;
// 以下は、ActionScript 3.0でSWFファイルやJPEGファイルを読み込む方法です。
_swfLoader = new Loader();
_swfLoader.contentLoaderInfo.addEventListener(Event.INIT,_onSWFLoaded,false,0,true);
_swfLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS,_onLoadProgress,false,0,true);
_swfLoader.load(new URLRequest("loadedContent.swf"));
};
コンストラクタが呼び出される(つまり、SWFがイニシャライズされる)と、すなわちメインタイムラインにプレローダークリップ(preloader_mc)があるということなので、preloader_mcムービクリップにINアニメーションを再生するように指示します。そして、Mainはそのアニメーションが完了する時を監視するようにしています。それから、実際のローディングを行うローダーをセットアップします。このローダーはロード状況に関わるProgressEvent.PROGRESSイベントを監視していて、このイベントが起きるとMainにある_onLoadProgress関数を実行します。
private function _onLoadProgress($evt:Event):void
{
Out.status(this,"_onLoadProgress");
// ロード状況を表示するために必要なもの
preloader_mc.updateProgress($evt.target.bytesLoaded,$evt.target.bytesTotal,_loadCount,_loadTotal);
};
SWFのローディング中は、_loadCountの値は0で、_loadTotalは1となります。ここでは2つのファイルをロードしているだけなので、プレローダークリップは半分までロード状況が進んでいることを示します。SWFファイルのローディングが完了すると、Mainは_onSWFLoaded関数とともに待機します。_onSWFLoaded関数は以下のようになっています。
private function _onSWFLoaded($evt:Event):void
{
Out.status(this,"_onSWFLoaded");
_loadCount = 1;
// XMLファイルをロードする準備ができました。ActionScript 3.0では、以下のようにしてXMLファイルをロードします。
// _onLoadProgress関数はSWFファイルでも、XMLファイルでも両方で使用できます。
_xmlLoader = new URLLoader();
_xmlLoader.addEventListener(Event.COMPLETE,_onXMLLoaded,false,0,true);
_xmlLoader.addEventListener(ProgressEvent.PROGRESS,_onLoadProgress,false,0,true);
_xmlLoader.load(new URLRequest("content.xml"));
};
content.xmlというXMLファイルをロードしていますが、XMLローダーではSWFのときと同じようにMainにある_onLoadProgress関数を実行しています。1つの関数内の1行のコードが、すべてのビジュアルアップデートを扱っているのです。違いと言えば、_loadCountの値が0から1に変わったくらいです。XMLファイルのロードが完了したら、_onXMLLoaded関数が実行されます。_onXMLLoaded関数は以下のようになっています。
private function _onXMLLoaded($evt:Event):void
{
preloader_mc.setComplete();
};
以上です。プレローダーは完了して消えて行きます
private function _onPreloaderOut($evt:Event):void
{
var loadedSWF:MovieClip = _swfLoader.contentLoaderInfo.content;
addChild(loadedSWF);
// SWFをステージに配置
loadedSWF.gotoAndPlay("IN");
// fロードされたSWFは、そのINアニメーションを再生します
loadedSWF.addEventListener(AnimationEvent.ANIMATE_IN,_onLoadedSWFAnimateIn,false,0,true);
};
ロードされたSWFをステージに配置して、そのINアニメーションを再生します。これで完成です。
では、作成したこれらのクラスをFlashがどのように見つけるかというと、初期状態ではFlashはFLAファイルがあるディレクトリを探します。個人的には、FLAファイルと同じディレクトリにクラスファイルを置くのは好きではありません。分かりやすいディレクトリを作成してその中でクラスファイルを管理する方がよいでしょう。どのように行うかというと、メニューから「ファイル/パブリッシュ設定」を選び、パブリッシュ設定ダイアログを開きます。Flashタブを選んで、「ActionScriptのバージョン」項目の右側にある「設定」ボタンをクリックします(図2)。ちなみに、「ActionScriptのバージョン」項目は、「ActionScript 3.0」を選んでおいてください。

図2. パブリッシュ設定ダイアログの「ActionScriptのバージョン」項目の右側にある「設定」ボタンをクリックします
ActionScript 3.0設定ダイアログが表示されるので、「+」ボタンをクリックして新しいクラスパスを追加します。今回の場合、すべてのクラスファイルはFLAファイルと同じディレクトに作成した「_classes」ディレクトリ内で管理することにしているので、「./classes/」というパスを追加しました(図3)。

図3. ActionScript 3.0設定ダイアログで、新しいクラスパス「./classes/」を追加します
図4 は、FLAファイルの保存場所を示したものです。クラスファイルのディレクトリとの関係が分かるかと思います。ここでは、すべてのクラスファイルをクラスパッケージ名と関連したディレクトリで保存しています。たとえば、「foo.bar.MyClass」という名前のクラスなら、そのクラスファイルは「_classes/foo/bar/MyClass.as」ディレクトリにあります。

図4. FLAファイルとクラスファイルを保存したディレクトリ
通常、クラス名を付ける際は一般的なパッケージ名から始めて、徐々に固有のディレクトリ名になるようするのが良いとされています。私の場合、最も一般的なクラス名として「com」を使っています。comディレクトリ内にあるbigspaceshipディレクトリには、私が所属する会社「Big Spaceship」のために作ったクラスやパッケージを置くようにしています。bigspaceshipディレクトリ内にあるframeworksディレクトリには、会社のプロジェクトで使う基本構造設計のため必要なすべてのクラスやパッケージを置くようにしています。frameworksディレクトリ内にあるsiteディレクトリには、Webサイトのプロジェクトで使うクラスを置いています(Adobe AIRアプリケーションやゲームに使うクラスと区別するためです)。この記事のサンプルの場合、すべてのコードは「_classes/com/bigspaceship/frameworks/site/PreloaderClip.as」ディレクトリに置いています。
なお、クラスパケージ名は自由に付けることができます。あなた次第です。ただ、チームで作業する場合は、私たちのように何か基準を設けて名前をつけた方が、ファイルを探しやすくなるでしょう。ファイルが見つからなくて作り直したという失敗を避けることができます。
ActionScript 2.0では、リンケージというと、ユニークIDを識別することでした。ActionScript 3.0ではというと、似ていますが違う部分もあります。ActionScript 3.0では、これまでの通り各ムービークリップは固有のリンケージIDを持っています。ただ、それだけでなくもう1つ「基本クラス」というパラメータを持っています。基本クラスとはリンケージのタイプを示すものです。今回の場合、MovieClipクラスを拡張したものなので、「flash.display.MovieClip」とします。拡張クラスについての解説は、この記事の範疇外なので詳しくは「 ActionScript 3.0 Language and Components Reference 」を見てください。このサンプルでは、リンケージの設定をリンク項目は「com.bigspaceship.frameworks.utils.PreloaderClip」とし、基本クラス項目は「flash.display.MovieClip」としています。プレローダーをステージにダイナミックに配置したい場合は、以下のようなコードを記述します。
import com.bigspaceship.frameworks.utils.PreloaderClip; var p:PreloaderClip = new PreloaderClip(); addChild(p);
上記のコードでは、新しいプレローダークリップを作成しており、このクリップは変数Pを使って参照できます。次にaddChild.を使ってそれをdisplay listに追加します。display listとは、Flash Playerがオブジェクトを扱う新しい方法のことです。かなり複雑な内容なので、ここでは解説を省きます。
これでFlashはステージ上に配置されたムビークリップを、MovieClipクラスを拡張したカスタムクラス「プレローダークリップ」として扱うようになります。Document Rootクラスには、ロード状況を表示する際に、プレローダークリップを活用するように設定しています。あとは、SWFファイルをコンパイルしてリラックスするだけです。