(BACK)

外部ファイルの読み込み

06/7/26 加筆修正
06/3/4 加筆修正
swfに入っていないファイル(外部ファイル)を読み込み、利用することが出来る。
数種類の方法があるが、最も簡単に出来るものを解説する。

注意
読み込むファイルを、例えば「01.jpg」と指定すると、呼び出すswfと読みこまれるファイルが同じ場所(フォルダ、ディレクトリ)に無ければならない。
paraflaでのプレビューの時は、parafla.exeと同じ場所(ディレクトリ)にある「_preview.swf」が使われるので、これと同じ場所に読み込むべき外部ファイルを置く必要がある。
呼び出すswfと読みこまれるファイルが同じ場所に無い場合、「http://〜/01.jpg」のようにパスを含めて書くか、または相対パスで書かなければならない。
([プレビュー]-[プレビューの設定]-[プレビューファイルをプロジェクトのフォルダに作成]にチェックを推奨)

1.画像ファイルの読み込み
2.テキストファイルの読み込み
3.音声ファイルの読み込み
4.キャッシュ問題について
5.進度の取得


1.画像ファイルの読み込み
すでに存在するスプライトの中に、外部の画像ファイルを読み込んで表示することが出来る。
画像ファイルとは、jpgファイルと、swfファイルを指す。

swfファイルの読み込みは「アクション:URL取得」と似ているが、URL取得により表示した外部swfは、全ての画面よりも前に表示されるのに対して、こちらはスプライトの中に外部swfを読み込むので、それより前に別の画像を表示する事や、スプライトごと変化させる事による変化が可能という利点がある。

使う命令は以下である。
loadMovie()(ロードムービー)

使い方:
インスタンス名.loadMovie(ファイル名の文字列)

スプライトに対して、外部のjpg/swfファイルを読み込む事を決め、読み込みを開始する読み込みが終了次第、画面に反映される。
読み込んでいる間、イベントが停止したりはしない。

例:
spr.loadMovie("black.jpg");


unloadMovie()(アンロードムービー) 使い方: インスタンス名.unloadMovie() スプライトに読み込まれている外部ファイルを削除する。 これを使わず、スプライトごと画像消去で消しても別に構わない。 例: spr.unloadMovie();

ひとつのスプライトに読み込める画像は1つである。
新たな画像を読み込んだ時、古いものは消える。

読み込まれた画像は、スプライトの(0,0)の位置に表示される。
この表示位置を変えることは出来ないので、スプライトそのものを動かすなどして対処する。

親イベント(_root)には読み込まないこと。正常に動作しないようである。(_rootはFlashの基となる画面であるので、そこに読み込むと壊れてしまうからと推測)

クリップアクションの中で自分自身(this)に読み込むことは出来ないようである。(情報求む)
スプライトの中のイベント(アクション:スクリプト)であれば可能。

2.テキストファイルの読み込み
決まった形式で書かれたテキストファイルを読み込み、変数に反映させる事が出来る。

flashが読み込めるテキストファイルの形式は完全に決まっており、以下の内容である。
変数名=変数の値&変数名=変数の値&変数名=変数の値&
この中には基本的に改行は含まれず、もしも改行があった場合は、その改行を含んだ値になる。
(扱いがよく判らなければ改行を使うべきではない)

例:
name=nagisa&hp=50&mp=20
これが正しく読みこまれた場合、変数nameには「nagisa」が、変数hpには「50」が、変数mpには「20」が代入される。(ただしこれらは全て文字列である…後述)

使う命令は以下である。
loadVariables()(ロードバリアブルス)

使い方:
インスタンス名.loadVariables(ファイル名の文字列)

_rootまたはスプライトに対して、外部のテキストファイルを読み込む事を決め、読み込みを開始する読み込みが終了次第、変数に反映される。
読み込んでいる間、イベントが停止したりはしない。

例:
_root.loadVariables("read.txt");


読み込んだ変数は、全て文字列である。 数値として扱いたい場合は、数値に変換する必要がある。 そのために、Numberという命令を使う。 scoreint = Number(score); 読み込んだscoreの中身は「100」であるが文字列である為に変換する。 scoreintに数値の「100」が代入される。
あくまで、読み込むのは_rootまたはスプライトに対して、である。
スプライトの中に読み込めば、そのスプライトの中の変数が書き換わる。

また、全角文字を含むテキストファイルを読み込むと、その部分は文字化けする。
これを防ぐには、読み込むよりも前に以下を書いておけばよい。
System.useCodepage = true;



さて、画像の読み込みの時は、多少画像の表示が遅れてもたいした問題にはならなかったが、テキストファイルを読み込む場合、読み込みが完全に終わってからでなければ、その変数を扱うことは出来ない。

取得が遅れても、取得が出来なくても後に影響が無い(テキストの書き換えなど)場合は、特に気にする必要はないが、
変数を取得した事を前提として次の処理を行う場合、読み込みが終わるまで待つという処理が必要になる。

「読み込みが終わるまで待つ」にはいくつかの方法があるが、ここでは2つを解説する。

1.正しく読み込まれていると判断出来るまで、同じ場所でループして待つ

例えば、テキストを読み込んだ結果、変数name="black"になる、とする。(必要に応じて、このチェック用の変数とその値を用意する)
・スクリプト
name = ""; //念のためこの変数は空にしておく
・スクリプト
this.loadVariables("read.txt"); //read.txtの読みこみを開始する
・ラベル
・スクリプト
if (name == "black") { gotoAndPlay("loopout"); }
// 読み込みが完了すれば 変数name="black" になっているはずなので
// それが確認出来たらループから抜ける
・ラベルへジャンプ:_PrevLabel 読み込みが完了するまで同じ部分をループし続ける
・ラベル:loopout

同じ内容を、やや強引かつ簡潔に書くことも出来る。
・スクリプト
name = ""; //念のためこの変数は空にしておく
this.loadVariables("read.txt"); //read.txtの読みこみを開始する
・何もしない(1フレーム)
・スクリプト
if (name != "black") { gotoAndPlay(_currentframe-1); }
状態変数_currentframeは、今実行されているフレーム番号が入っているので、これは「1フレーム戻る」という意味になる。
1フレーム前は確実に「何もしていない」フレームにしておかないと誤作動しかねないので注意。


2.dataハンドラを使う

クリップアクションには、読み込みが終了したら実行されるという「dataハンドラ」があり、これを使うと非常に簡潔に書く事が出来る。

まず、何も入っていない空のスプライトを作成し、適当なインスタンス名(ここではsprとする)をつけて表示、次のクリップアクションをつける。
onClipEvent(load){

	this.loadVariables("read.txt");

}
-
onClipEvent(data){ //読み込みが終わったら1回だけ実行

	_root.play(); // 「停止」している親イベントを再び再生させる

}

このスプライトを表示した後に親イベントを「停止」させると、
・親イベントが停止したまま、スプライトにて読み込みが開始される
・読み込みが終わったら、dataハンドラが実行される
・停止している親イベントが、play()により再び動き出す
というような仕組みになる。

親イベントが再び動いたという事は読み込みが終わったという事なので、それから変数を扱えばよい。用が済んだらスプライトは消してよい。
スプライトの中から読み込んだので、スプライトの中の変数が使われている点に注意!
// 読み込みにより、変数name="black"であるはずだが…
spr.name ←スプライトsprの中で読み込んだので、値が入っているのはこの変数である
_root.name ←この変数には影響を与えない



もしも何らかの原因で読み込みに失敗した場合、いずれの場合でも、同じ場所で無限ループあるいは停止し、先に進まない事になる。この場合の事も考えておかなければならない。

一番簡単な方法は、何も対策しない事である。
読み込みを開始する前に「もしもこの表示で止まったら読み込みに失敗です残念」といった意味の事を表示し、読み込みに成功した時点で消せばよい。

次に、やり直しボタンを置いておく方法がある。
あらかじめ、flashの最初からやり直す(最初にジャンプする)ようなボタンを表示しておき、先のように「もしもこの表示で止まったらボタンを押してやり直して下さい残念」のような表示をしておく。停止や無限ループにはまっていても、ボタンは機能する事を利用している。



前述した、外部テキストから読み込んだ文章を表示する(厳密には書き換える)だけの場合は、読み込む変数と同じ名前の変数のテキストで「読み込み中」とでも表示しておき、それから読み込めば、変数が書き換わり、自動的にテキストも書き換わることになる。

・変数名「textbox」のテキストを表示、「ロード中」と表示する。
・外部テキストから読み込む。
this.loadVariables("読み込み.txt");

[読み込み.txtの内容]
textbox=って頃●さんが言ってました
 この結果、変数textboxの内容が書き換わるので、すでに表示されているテキストの表示も書き換わることになる。
 読み込み待ちをしていないので、テキストの書き換わりは一瞬以上遅れる。

3.音声ファイルの読み込み
読み込んだ音声ファイルでは同期が取れないことに注意。

まず、以下の記述により、新しくサウンドオブジェクトを作成する必要がある。
サウンドオブジェクト名 = new Sound();
サウンドオブジェクト名とは、ひとつの音声ファイルに割り当てる名前であり、自由につける事が出来る。
スプライトについてのインスタンス名と同じである。

音声についての命令は以下である。
loadSound()(ロードサウンド)

使い方:
サウンドオブジェクト名.loadSound(ファイル名の文字列,読み込みモード)

外部のmp3ファイルをサウンドオブジェクト名と関連付け、読み込みを開始する。
読みこんでいる間イベントが停止したりはしない。

読み込みモードには、以下のどちらかを記述する。
true : ファイルを読み込みながら再生するモード。
       ストリーミング再生と言う。(paraflaでの用語とは意味が違う)
       再生側の読み込み速度(ダウンロード速度)がある程度以上なければ意味が無い。
       このモードの時は、startしなくても再生がはじまる。また、ループ再生出来ない。
       勝手に再生される事を防ぐには、loadSoundの後すぐにstopしておけばよい。
false : ファイルの全てを読み込んでいなければ再生されない。

例:
bgm.loadSound("op.mp3",true);
サウンドオブジェクトbgmに、外部ファイル"op.mp3"を関連付け、
ストリーミング再生モードで、読み込みを開始する。


start()(スタート)

使い方:
サウンドオブジェクト名.start(再生位置,ループ回数)

サウンドオブジェクト名で示されたサウンドの再生を開始する。

再生位置は、再生が開始される位置を書く。
10であれば10秒目から再生される。省略または0と書けば最初から。

ループ回数は、繰り返し再生する回数を書く。
無限にループさせたい時は適当に大きな数を書いておく。
ストリーミング再生モードの時はループしないので、この数字は無視される。

例:
bgm.start(0,10);
サウンドオブジェクトbgmのサウンドを最初から再生する。10回ループする。


stop()(ストップ)

使い方:
サウンドオブジェクト名.stop()

サウンドオブジェクト名で示されたサウンドを停止する。


getVolume() / setVolume()(ゲットボリューム/セットボリューム)

使い方:
変数 = サウンドオブジェクト名.getVolume();

対象となるサウンドの音量を取得し、変数に代入する。

使い方:
サウンドオブジェクト名.setVolume(音量);

対象となるサウンドの音量を設定する。

音量の値とは、0の時無音、100の時標準、200なら2倍の音量になる。
(厳密には絶対値が使用される。100の時と-100の時は同じ。負数になる時は注意すること)

フェードアウトの例:
for (i=100;i>=0;i--){
	bgm.setVolume(i);
	//本来ここで時間待ち
}


duration / position(デュレイション/ポジション)

durationとpositionは、サウンドについての状態変数である。
共に読み込み専用であり、値を書き換えることは出来ない。

サウンドオブジェクト名.duration : サウンドの長さが入っている(ミリ秒単位)
サウンドオブジェクト名.position : 現在再生している地点が入っている(ミリ秒単位)

bgmは全部で40秒のサウンドであり、現在15秒地点を再生しているのであれば、
bgm.duration = 40000
bgm.position = 15000
という値が入っている事になる。

曲の長さを取得する時や、自力で同期を取る場合などに使う。



たとえば画像や変数は、常に親画面かスプライトの中に入っていると考えることができる。
それと同様に、音声ファイルも、親画面かスプライトの中に入っている
特に理由がなければ全て親画面に置けばよいが、そうでない場合はターゲット指定などに気をつけなければならない。

snd = new Sound(); //この場所に、サウンドオブジェクトを作成
_root.snd = new Sound(); //明確に_rootに、サウンドオブジェクトを作成
spr.snd = new Sound(); //スプライトsprの中に、サウンドオブジェクトを作成

4.キャッシュ問題について
ブラウザ上で再生しているflashにおいて外部ファイルを読み込む時、同じ名前のファイルがブラウザのキャッシュに存在する場合、外部ファイルを読み込まずにキャッシュにあるファイルを(勝手に)使う事がある。
これにより、外部ファイルを差し替えた場合でも、差し替える前のファイルが読まれてしまうという事が起きる。

これを回避するには、読み込むファイル名に以下のように細工をすれば良い。
//例えば、pic.jpg というファイルを読み込む場合
filename = "pic.jpg" + "?" + random(1000000);
sprite.loadMovie(filename);
テキストファイルや音声ファイルの場合でも同じである。

以下は理屈。(理解しなくてもよい)
上のスクリプトの結果として、実行されるたびに、
「pic.jpg?12345」
「pic.jpg?45678」
「pic.jpg?13579」
のように、ファイル名の後に「?」で区切ってランダムな数字のついたファイル名を生成し、そのファイルを読み込んでいる。
これはflashとは関係ないURLのルールを利用したもので、通常「URL?DATA」というファイルを読み込もうとした場合、URLのファイルに対してDATAの内容を送り、その結果をも受け取る事が出来る。(CGIにデータを渡して結果を受け取るような場合に使う)
しかし、pic.jpgは当然ただの画像なので、データは送れない。従って、「?」の右に何が書いてあっても無視される事になる。

「pic.jpg?12345」
「pic.jpg?45678」
「pic.jpg?13579」
これらは全て同じファイルを示しているが、ブラウザは「ファイル名が違うので違うファイルである」という誤解をするので、キャッシュの中のファイルは使わず、常にファイルを読み込ませる事が出来る。

註、ブラウザによってキャッシュの扱いが異なる可能性はあるので必ずしも全てのブラウザでこの方法が有効とは言い切れない。少なくともIEとFirefoxでは有効である。

5.進度の取得
大きなファイルを読み込み、それを完全に読み込み終わってから次の処理に進みたいような場合は、どれだけの量を読み込んでいるかを調べればよい。
以下の変数により調べることができる。

オブジェクト名.getBytesLoaded(); //読み込んだバイト数
オブジェクト名.getBytesTotal(); //総バイト数

ここで言うオブジェクト名とは、インスタンス名サウンドオブジェクト名のことである。

これらの値は読み込みが進むたびに変動するので、
if (obj.getBytesLoaded() >= obj.getBytesTotal()) {
	//読み込み終わった
}
のような条件で、読み込み終わったことを判断することが出来る。

ただし、getBytesTotal()は、最初は空である。(0ですらない)
読み込むべきファイルの容量の情報を得てはじめて値がセットされるので、getBytesTotal()に確かに数が入っている事を確認してからでなければ、先の判断は正しくできない。

数が入っているかの判断は何でもいいが、ひとつ例を挙げる。
if (obj.getBytesLoaded() >= obj.getBytesTotal() && obj.getBytesTotal() > 10) {
	//読み込み終わった
}
getBytesTotal()が10より大きいという条件を付け足し、確かに数値が入っている事を確認している。

by D4U