フラッシュゴーゴー

Macromediaの製品Flash、とても簡単にインタラクティブな
ホームページができると言うことであっというまに広まってしまったが
簡単にできるのは、ほんの入り口でその実はすごい深いものだったのです。

その深くて難しいのが「ActionScript」これはFlashのプログラム言語なのだが

このサンプルスクリプトが雑誌やHPで出回っており、それをペタペタ貼り付けて、
動けばラッキー、動かないと「わからん〜、たすけて〜」という人が
続発しているので、プログラマーから見たFlashの使い方を書いてみます。

【はじめに】

マクロメディアが新バージョンを出すたびに、大々的に雑誌が取り上げ、魅力的な文章で
祭り上げるので、すぐバージョンアップしたがる人が多いが、新バージョンで作ったものは
新プレーヤーが必要で、バージョンアップできない環境の人は見えないと言うことを忘れないでほしいです。

ここで紹介するのは、Macromedia Flash MX でバージョンにすると6です。
このバージョンもそろそろこなれてきたので、このバージョンで解説します。

【シンボル】

Flashはまず「シンボル」という考え方を理解しなければなりません。
プログラマーの人に分かりやすく言うと、「オブジェクト 」になるのかな?

絵を描いてー>シンボルにしてー>命令を与える

これが、一連の流れになります。

上へ トップページへ

【step1 シンボルを動かす】

まず、「矩形ツール」を選択し、キャンバスに四角を書きます。
ただの四角に見えますが、「矢印ツール」でクリックしてみれば分かりますが
「左側の線」「右側の線」「上の線」「下の線」「中身」と分かれたものになっています。

この状態は、ただの絵の状態なのでバラバラの部品になっています。

まず、この絵をシンボルに変換します

「矢印ツールで」書いた四角をすべて選択して、選択した絵の上で右クリックし
「シンボルに変換」をクリックします。



取り合えず、名前を「rectangle」にします。
なぜこんな名前にするかと言うと、日本語は「ひらがな・カタカナ・半角・全角・送り仮名」など一つの言葉でも
複数の表現方法があるので、指定間違いなどのミスがはっせいするので・・・・。

でも「aaa」とか適当にすると、完成した後の数ヵ月後に修正しようと開いたときに「aaa」ってなんだったっけ・・;
と言う状態になっちゃいますw

「タイプ」をムービークリップにし「OK」ボタンをクリックします。

Flashは、なかなか凝ったつくりになっているのですが、それをユーザに意識させないようにしているので
そのせいでFlash難民が多数発生してしまっています。

実はこのシンボルに変換すると言う行為は、ライブラリを作成すると言う行為なのです。
「ウィンドウ」−>「ライブラリ」を選択し、表示してみてください。



できていますね^^
ややこしいのは、このライブラリのムービークリップとキャンバスにできているムービークリップには
イコールではないと言うことです。

試しに、キャンバスのムービークリップを削除してみてください。
ライブラリにまったく変化はありません。

つまり、ライブラリを作り、そのライブラリのコピーをキャンバスに配置する行為が
「シンボルに変換」なのです。

取り合えず、ライブラリの中を「シンボル」シンボルをコピーしたものを「インスタンス」と呼んでみます。

続きますので、キャンバスのムービークリップを削除した人は、ライブラリのrectangleを
キャンバスにドラッグアンドドロップして、復活させてください。



先ほどつけた「rectangle」はライブラリ用につけた名前なので、キャンバス上に配置された
ムービークリップにも名前をつける必要があります。
「プロパティ」の中に「インスタンス名」と書かれた場所があるので、そこに「rectangle1」と入力します。

さて、指示を出す前に「ActionScript」を記述するレイヤーを作成します。
ここにスクリプトをまとめることにより、分かりやすくすっきりします。

そして、「Action」レイヤーのフレーム1を選択し、そこにアクションを書きます。

_level0.rectangle1._x = _level0.rectangle1._x + 10;

インスタンス は初期配置では「level0」と言う層に配置されます。
フラッシュは階層を持っているので、これを指定します。
そして、インスタンス「rectangle1」の横座標「x」を右に「10」移動させます。

Flashではシステム予約語にアクセスするために「_」を使います。

つまり上のスクリプトは

(_level0)に配置されている(rectangle1)インスタンスの横座標(x)に(_level0)に配置されている
(rectangle1)インスタンスの横座標(x)に10を足したものに設定しろ
」と言うことです。

プログラムは何でもそうですが、左辺を基準とし、右辺での計算を左辺に入れるということをします。

算数では
 1 + 1 = 2
プログラムでは
 2 = 1 + 1

となります。

このままでは実行しても1回右に動くだけなので、動いたように見えません。
ず〜っと右に動くようにしてみましょう。
現在「1フレーム」を処理しただけで終了していますので
「2フレーム」に「1フレームに戻れ」と言う、スクリプトを記述します。
まず、記述するために「Action」「レイヤー1」ともに2フレーム目に
キーフレームを挿入します。
「キーフレーム」とは、変化を指定できるキーポイントになるフレームです。



gotoAndPlay(1);

右に行ったと思います。

プログラマーの方はびっくりしていると思います。
なぜなら「無限ループ」に陥っているからです。
しかし、大丈夫です。FlashはFlashそのものがタイマーになっており、「タイムライン」の下に表示してある
「12.0 fps」とあると思います。
これがタイマーのインターバルで、「frame/second」で設定します。
つまり1秒間に12回しかフレームが動かないので、無限ループでPCがハングアップすることはありませんw

しかし、右に行ったままでは「お〜い、帰ってこいよ〜♪」なので
端まで言ったら、左に動くように変更します。

ここで重要なことを書きます。
まず、現在あるフレームをすべて選択し、1フレーム分右にずらします。

これによって空いた1フレーム目に「初期設定」を記述します。

今回の場合は

var intGain = 10; //x座標の増加量

だけです。
なぜこんなことをするかと言うと、初期設定が何回も実行されると
どんな変化させても、すぐにリセットされてしまうからです。

もし、既存のFlashに初期設定フレームを作るのが困難な方は

var boolInitialized; //true=初期化済み false=未初期化
var intGain; //x座標の増加量

if(boolInitialized != true)
{
  boolInitialized = true;
  intGain = 10;
}


↑これで、if内は1回しか実行されないはずなので、代用してください。

今後フラッシュを作る際に、まず上記のことを必ずしてください。

キャンバスの横幅を見るには、キャンバスの何もないところをクリックして
プロパティを見ると分かります。



そうすると「ドキュメント」って書いてありますw
キャンバスじゃなかったんですねw、でもドキュメントは分かりにくいので
ここではキャンバスで通します。

標準で「550x400」になっています。
つまり左端は「0」右端は「550」です。

後は小学校の算数です^^
2フレーム目を以下に変更します。

if(_level0.rectangle1._x + _level0.rectangle1._width >= 550)
{//左に移動に変更
  intGain = -10;
}
else if(_level0.rectangle1._x <= 0)
{//右に移動に変更
  intGain = 10;
}
//x座標を変化
_level0.rectangle1._x = _level0.rectangle1._x + intGain;


ここで出てきた「//」ですがこれは、説明文を記入できる「コメント」と言うもので
Flashは「//」が出てくると、その行のそれ以上は無視します。
「/*コメント*/」と/*から*/で囲まれたものも、コメントにできます。

このコメントをしっかり書いていないと、他の人どころか自分で後日見たときに
何がなんだか分からなくなるので、しっかり書きましょう。


さて、スクリプトの説明ですが

もし、rectangle1の左上のx座標とrectangle1の横幅の合計が550以上の場合(つまり右端に到達した場合)
  xの増加量を-10に変更
上の条件以外で、rectangle1の左上のx座標が0以下になった場合(つまり左端に到達した場合)
  xの増加量を10に変更


rectangle1のx座標に、rectangle1のx座標+増加量を設定

です。
最後に、1フレームずれたので、3フレーム目の

gotoAndPlay(1);

gotoAndPlay(2);

どうでしょう?
あれっきっちり端っこで折り返さない!?っと言う人がいるかもしれません。
それは、インスタンスに基準座標点があり、それが結構適当に設定されるからです。

スクリプトから制御するために、基準点は左上にしましょう。
ライブラリをダブルクリックして、四角の左上に「+」を合わせましょう。


できましたか?、一応ファイルを置いておきます。
step1.fla
step1.swf

上へ トップページへ

【step2 PreLoader(プリローダー)〜事前読み込み〜】

pre ・・・ あらかじめ
Loader・・ 読み込むもの

step1で初期設定の方法を覚えたので、次はローディング画面を作ってみましょう。

まずシーン設定をします。




シーンウィンドウを開き、step1で作ったシーンが「シーン1」となっていると思うので
「MainScene」に変更してください。


「+」をクリックし新しいシーンを作成し「PreLoader」と名前を変更してください。







シーンは上から順番に実行されるので、クリック&ドラッグで
「PreLoader」を上にしてください。






1フレーム目に変数宣言と初期設定を行います。





step1でのお約束「1フレーム目は初期設定」の為に
2フレーム目にキーフレームを挿入します。






2フレーム目では読み込み済みの容量を取得し、合計と同じかそれ以上なら「MainScene」の1フレームを再生
それ以外なら、何もしない(次のフレームへ)と記述します。

なぜ「==」(イコール)ではないかというと、何らかの事情で、合計とぴったり合わなかった場合
無限に、 「intTotalBytes == intNowLoadedBytes」は成立しない。

この状態では、永遠にロード画面が終わりません。
このような終わりのないループを「無限ループ」といい、PCを不安定にさせたり
終了しないプログラムになってしまうので、プログラムの世界ではご法度である。

これを防ぐために、「〜まで」と言うような条件式を書くときは必ず「<=」もしくは「>=」を書くようにしましょう。





まだ読み込みが終わっていないとき、このままでは
何もせず次のシーンに行ってしまうので、3フレーム目に
「2フレーム目に戻れ」と言うスクリプトを書きますので
キーフレームを挿入してください。







「gotoAndPlay(2)」gotoAndPlay(フレーム番号)、指定した
フレーム番号に飛び、そのフレームから再生せよという命令です。




これで、出来たには出来たのですが、ダウンロード中に暇つぶしの画面がないと
見ている人はバグっているのかと思ってしまいますので、 ダウンロード経過情報を表示します。



フラッシュではフレームに対するスクリプトとインスタンスに対するスクリプトを明確に
別物として理解することにより、流れが分かりやすくなります。
現在行っている作業はフレームに対するスクリプトで「○フレーム目に来たら◆をする」
と言うスクリプトを記述していますので、上記のように単独レイヤーとして分かりやすく分けます。

そして、新しいレイヤーを作り「Info」という名前をつけ、このレイヤーでダウンロード状況を
表示したいと思いますので、このフレームに「テキストツール」を配置してください。



上記のように、テキストツールを配置し、テキストの種類を「ダイナミックテキスト」
インスタンス名を「txtDownloadInfo」変数を「text」と設定してください。

フラッシュ上で動的に文字を変更したいときには「ダイナミックテキスト」にしなければなりません。



配置したダイナミックテキストに
「読み込み済み/合計バイト数Bytes」と表示します。





これで、またまた出来たには出来たのですが、本体のファイルサイズが小さすぎて
読み込み状況が見えません。

そこで、ダミーとして音楽ファイルを配置します。











音もライブラリとして扱われるので
「ファイル」−>「ライブラリに読み込み」から
なるべくファイルサイズの大きい、音データを読み込みます。














ライブラリに読み込まれたファイルを「MainScene」に
ドラッグ&ドロップします。











省略していますが、用途別にレイヤーを適切に作成して置いてください。
左の例では「Music」と言うレイヤーを作り、そこにドラッグ&ドロップ
しているだけで、何も記述せずに再生されます。






swfに書き出す際におも〜い設定にしてください。


では、↓で確認してみてください。

step2.fla
step2.swf

これからフラッシュを作成するときは↓のようにプリローダーだけのものを
作っておき、それをコピーして作り始めると便利です。
preloader.fla

たったステップ2ですが、ここまで意味を理解して自分で動かすことが出来るようになったら
もう、「フラッシュでActionScriptが書けます!」 とか言って就職したり
「仕事を取ったり」してもOKです。

それほど、フラッシュ市場はアーティストよりで、アクションスクリプトをしっかり理解している人が
すくないですw

このプリローダーについても、雑誌丸写しで、無駄な処理やつじつまの合わない事を
平気で行っている人が結構います。

たまたま動けばいいが、思い通りに動作しなかったら、もうどうしていいか分からない
フラッシュ難民になってしまいます^^;

ここまでで理解できていない人は、もう一度戻り、しっかり見直してください。
Step2までは、フラッシュを作成する際の「初期のお約束」と言う位流して通る部分なので
ここでつまずくと、やっかいですw

上へ トップページへ

【step3 プリローダーをちゃんと作ってみる】

ダイナミックテキストを2つ配置して、「読み込み済み」と「合計」を分けてみます。
「読み込み済みを右揃え」/「合計を左揃え」にします。
step2では、桁が変わると「カクッ」とずれていたので、これで固定します。
ついでに、数字にカンマをつけて見やすくします。

●ダイナミックテキストと変数の関係について
  ダイナミックテキストの変数のアクセスの仕方ですがてっきり
  「インスタンス名ー>変数」と思っていたのですが、ダイナミックテキストにつけた
  変数名って、グローバル変数になっていました。
  なので「A」と言うテキストに「text」と言う変数名をつけて「B」と言うテキストに「text」と言う変数名
  をつけると「A.text=B.text=.text」になってしまいます。

  試しにインスタンス名なしで「text」と言う変数名をつけても「_level0.text」でアクセスできます。
  つまりダイナミックテキストに変数名をつけると

  _level0.text - リンク - _level0.A.text
         \
          リンク - _level0.B.text


  になっていることになります。
  ダイナミックテキストを使用する際は変数名に気をつけて設計しましょう。

●数字にカンマをつける
  数字の桁数が大きくなるとカンマがないと非常に見難いです。
  そこで、カンマをつけようと思ったのですが、Flashの事は深く知らないので
  自作の関数を作ってみました。

  ↓を初期設定フレームに貼り付けると「_level0.txtTotalBytes = funcFormatCurrency(String(intTotalBytes));」このように使えます。
  コピペしないでね。理解するのが目的のサイトなので^^;

  function funcFormatCurrency(strTargetCur) <-カンマをつけたい数値をもらう
  {//数値にカンマをつける
   var strResult; //戻り値
   var intLoopCount;
   var intStringCount;
   var boolCommaOn;

   intStringCount = 0;
   boolCommaOn = false;
   for(intLoopCount = strTargetCur.length;intLoopCount > 0;intLoopCount--) 
<-数値の桁数の終わりから最高桁までループ
   {
    intStringCount = intStringCount + 1; 
<-現在何桁目かを記録
    if(intStringCount % 3 == 0) 
<-3で割ったあまりが0の時
    {
     boolCommaOn = true;    
<-次カンマだよとマーク
     strResult = strTargetCur.substr(intLoopCount - 1, 1) + strResult; 
<−右から「intStringCount」個目を「strResult」の左にくっつける
    }
    else
    {
    if(boolCommaOn == true)    
<-次カンマだよとマークされているとき
    {  ↓
右から「intStringCount」個目とカンマを「strResult」の左にくっつける
     strResult = strTargetCur.substr(intLoopCount - 1, 1) + "," + strResult;
     boolCommaOn = false;    
<-次カンマ終わったよとマーク
    }
    else
    {
     strResult = strTargetCur.substr(intLoopCount - 1, 1) + strResult;
    }
   }

   return strResult;
  }

step3-1.fla
step3-1.swf

これをちょっとひねると、オープニングムービーが出来ます

step3-2.fla
step3-2.swf

上へ トップページへ

【step4 サウンドを考える】

step3でファイルサイズを重くするためにサウンドをライブラリに登録して
シーンに配置すると言うことをしたのですが、やっぱサウンドも効果的に使いたいので
アクションスクリプトで制御したいと思います。

まず、サウンドライブラリを削除する。
ライブラリのサウンドも制御できるのだろうが、やり方がわからなかったので、スクリプトから
読むようにする。

初期設定フレームの1フレームで以下のように読み込む

ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
var objIntroSound; //イントロ
var objBGMSound; //BGM
var intSoundTotalBytes; //サウンドの全バイト数
var intSoundNowLoadedBytes; //サウンドの現在の読み込み完了バイト数

//BGMをイベントサウンドとして読み込み
objBGMSound = new Sound();
objBGMSound.loadSound("../sound/bgm.mp3", false);
intSoundTotalBytes = objBGMSound.getBytesTotal(); //サウンドの全バイト数取得
intSoundNowLoadedBytes = 0; //サウンドの読み込み中バイト数を0に

//イントロをストリーミングとして読み込み
objIntroSound = new Sound();
objIntroSound.loadSound("../sound/intro.mp3", true);
objIntroSound.start();
ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ

new Sound()でオブジェクトを生成し、loadSound()でファイルを読み込みます。
この際の第2引数のtrue,falseは何かと言うと、true=ストリーミング再生
false=完全読み込み後再生と言うことです。

イントロはプリローダーをかねているので、ストリーミング再生にして
すぐに再生してもらわなければ困ります。

メインシーンは再利用の可能性があるので、完全に読み込んでもらいます。
さらにメインシーンに言ったときに音が出ないとプリローダーの意味がないので
サウンドが読み込み終わるまで、待つ必要があります。

そこでgetBytesTotal()でswfの読み込み待ちと同じように、サウンドの全バイト数を
取得して、読み込みの終わりを待ちます。

2フレーム目の読み込み完了判定のところに、サウンドの判定を追加します。

ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
intSoundNowLoadedBytes = objBGMSound.getBytesLoaded();

if(intTotalBytes <= intNowLoadedBytes && boolFirstJudge == false && intSoundTotalBytes <= intSoundNowLoadedBytes)
{//読み込み完了
 _level0.completemessage = "complete";
 gotoAndPlay("MainScene", 1);
}
ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ

メインシーンの初期設定フレームの1フレームで、BGM再生を指示します。

ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ
// BGM スタート
objBGMSound.start();

objBGMSound.onSoundComplete = function() {
//終了したら又再生
 objBGMSound.start();
}
ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ

BGMはずっと鳴り続けてもらいたいので、サウンド終了イベントonSoundCompleteを受け取ったら
もう一回start()します。

これで完了ですが、読み込みファイル名について少し。

今回のstepで↓の様に名前を決めたのには理由があります。
objBGMSound.loadSound("../sound/bgm.mp3", false);
objIntroSound.loadSound("../sound/intro.mp3", true);
それはせっかく外部ファイルを読み込むのですから、フラッシュ全体を編集しなくても
すぐに、音を変更できるようにするためです。

step4.fla
step4.swf

上へ トップページへ