JAVAC.JP
HOSHI TETSUYA 星鉄矢
2005/07/25
hossy@javac.jp
http://www.javac.jp
Google
WWW を検索 WWW.JAVAC.JP を検索

2-1 画像をロードする

SWFに対してアニメーションのファイルという印象を持つ方は多いと思われますが、アプリケーションプログラミングにおけるFlashでは、画像はロード、またはリンケージからのロード(後述)を用いることが多々あります。その場合、SWFファイルは主にソースコードを格納したものとして存在します。
Javaアプリケーション(Frame, Applet, iアプリ)やVisual C++をお使いになられる方にとっては、画像のロードは当然のことと思われますが、主にアニメーション目的でFlashを使われる方にとっては、あまり縁の薄い方法かもしれません。ただし、アニメーション目的でFlashを作成する場合でも、ファイルサイズの大きすぎるSWFを分割する、その際、初期ローディング時間を短縮する場合には、これらのロードは常套手段として用いられることが多いです。

Flash MXからロードできる対象に、SWFファイルの他、JPGファイルやMP3ファイルが加わりました。GIFファイルやPNGファイルのロードはサポートしていません。その場合、一度、Flashアプリケーションを用いて、それらのファイルをSWFファイルに読み込み、コンパイル(パブリッシュ)したものをロードします。

具体的には、SWFファイル・JPGファイルのロードにはMovieClip.loadMovieメソッド、MP3ファイルのロードにはMovieClip.loadSoundメソッドを用います。loadSoundメソッドに関しては、今回のテーマとは趣旨がずれるため割愛します。

一般的には、MovieClip.createEmptyMovieClipメソッドで画像読み込み用のムービークリップを作成し、そこにロードします。これにより、上位ムービークリップにロード監視用スクリプト等を保持したまま、画像のロードを行うことができます。
この点は非常に間違えやすいところなのですが、ロードされると、そのパスに存在していたムービークリップはロードしたものに書き換えられるので、用意していたコードなどは全て無効になります。
図示すると、以下のようになります。
movieclip-+-method ------ このムービークリップに持たせる機能
          |
          +-movieclip --- ここにロード
例えば、どのようなソースコードになるでしょうか。
例によって、タイムラインに #include "main.as" の記述がなされているものとします。
また、SWFファイルと同階層にtest.jpgを用意してください。
main.as
---
this.createEmptyMovieClip("test_movieclip",1);
var mc:MovieClip=this.test_movieclip;
mc.createEmptyMovieClip("seed",1);
var seed:MovieClip=mc.seed;
seed.loadMovie("test.jpg");
mc.onEnterFrame=function(){
    trace("Now Loading.");
    var l:Number=seed.getBytesLoaded();
    var t:Number=seed.getBytesTotal();
    var wi:Number=seed._width;
    var he:Number=seed._height;
    if(l>=t && t>2 && wi>0 && he>0){
        trace("Load Complete.");
        delete(this.onEnterFrame);
    }
};
stop();
このソースにはいくつかのポイントがあります。
まず、onEnterFrameメソッドは匿名メソッドとして記述しています。ActionScriptでは、dynamicな性質を持つオブジェクトに対し、メソッドを動的に付加することができ、このonEnterFrameメソッドもそのようなものとして存在しています。その場合、Object.method=function(){}; の形で記述をすることになります。
ここで気をつけなければならないことは、匿名メソッド内でのスコープの変化です。delete(this.onEnterFrame); 文において、thisが指すのはmcムービークリップです。ですから、匿名メソッド外で用いているメンバは、匿名メソッド内ではthisの対象ではありません。
では、onEnterFrameメソッド内のseedは、なぜonEnterFrameメソッド外メンバのムービークリップseedにアクセスできているのでしょうか。FlashPlayerは、メソッド内部に該当メンバがなかった場合、その上位(タイムライン・クラス)にそのメンバを探しに行きます。付け加えれば、それでも存在しない場合は_globalというグローバルメンバに探しに行きます。これら、一連の動きを俗にスコープチェーンと呼びます。
試しに、以下のように匿名メソッド内にメンバseedを付け加えてみます。
main.as
---
this.createEmptyMovieClip("test_movieclip",1);
var mc:MovieClip=this.test_movieclip;
mc.createEmptyMovieClip("seed",1);
var seed:MovieClip=mc.seed;
seed.loadMovie("test.jpg");
mc.onEnterFrame=function(){
    trace("Now Loading.");
    var seed:MovieClip;
    var l:Number=seed.getBytesLoaded();
    var t:Number=seed.getBytesTotal();
    var wi:Number=seed._width;
    var he:Number=seed._height;
    if(l>=t && t>2 && wi>0 && he>0){
        trace("Load Complete.");
        delete(this.onEnterFrame);
    }
};
stop();
試していただければ分かるように、上位のseedムービークリップにアクセスできなくなるため、正常に機能しなくなります。

次のポイントとして挙げられるのが、匿名メソッド内の条件式、(l>=t && t>2 && wi>0 && he>0) です。
まず、ロード済みバイト数とファイルのバイト数の比較は当然ですが、なぜファイルのバイト数が2より大きいなどという条件を付けるのでしょうか。これは、ファイルへのアクセスが成功するまで、getBytesTotalメソッドで取得できる数値が0になってしまうことに起因しています。この記述を書かないと、0=0の式が成り立って、実際のロード完了前に、FlashPlayerがロードを完了したと勘違いしてしまうことを防ぐためです。また、その後の記述、横幅・縦幅の比較式は何かと言うと、Macromediaのバグで、ロードしたバイト数とファイルのバイト数が一致して、一見ロードが完了したように思えても、実は、即座にこのムービークリップの座標・サイズにアクセスしようとすると、0が返ってきてしまうことがあることを防ぐためです。
なんだか、Macromediaのバグだらけですね。使いづらそうです。
FlashPlayer7からは、MovieClipLoaderクラスというものが存在し、画像ファイルロードの管理を簡便に行うことができるようになっているため、この問題は解決しています。



BACKTOPNEXT




All Contents Copyright (C) 2005 HOSHI Tetsuya
Home