- 2008-03-19 (水) 8:38
- ActionScript3.0 | Flash | Flex

以前も書いたことですが、色々増えてきたのでまとめてみた。
Flex と Flash CS3 でハイブリッドな SWF を作る場合、
大抵は Flex で土台を作り、グラフィック部分などを Flash で作るということになるだろう。
その際に俺が実際引っかかったりした部分をまとめた。
なので Flash しか関係ないじゃんとか Flex しか関係ないじゃんと思わずに
Flash しか関係ないじゃん?って所は それを制御する側がいるということを考えて
Flex しか関係ないじゃん?って所は それに制御される側がいるということを考えて
読んで欲しい。
- Flex と Flash CS3 では コンパイラが違う。
Flex で出来ることは Flash でも同じように実装できるわけではない。
逆もまた然り。
また、エラーの出力なども違う。
Flash CS3 では出るエラーも Flex では出ない場合がある。
逆もまた然り。
基本的には Flash CS3 のコンパイラは 甘い。型チェックが甘すぎて気持ち悪いときがある。
Flex のコンパイラ (MXMLC) は 厳しい。てかコレが普通かも。
Flash CS3 はやはり絵を描くことがメイン。
Flex はやはりアプリケーションを作ることがメイン。
- - Flash CS3 のオーサリング上の操作
Flash CS3 ではプログラムをほとんどかけない人でも簡単に、有る程度できるように
オーサリングツール上でマスクをかけたりすることが出来る。
それは便利といえば便利だが、予期せぬことを起こす原因にもなる。
一番怖いと思ったのはマスク。
オーサリングツール上では、チョチョイのドンでマスクをかけることが出来る。
そのマスクの設定されたインスタンスの上 (深度上の上) に addChild などをすると
勝手にマスク対象にされてしまう。
さらにこのマスクが意味不明で、マスクのインスタンスの mask プロパティは null のまま。
解決方法は mask の下に置く、またはもっと上 (深度上の上) に置くしかないかもしれない。
ちなみに、マスクの設定がされているインスタンスの mask に null を代入してやるとマスクが外れる。
イミフ・・・。
- - フレームの移動は最後に行われる。
コレは周知の問題ですが、コレが意外と厄介で。
たとえば、4フレーム目などに MC を配置して、 gotoAndStop() で4フレーム目に飛ばし、
その MC を取得しようとする。
すると、 gotoAndStop() は最後に実行されるので、制御している側が、
swf.gotoAndStop(4);
swf.getChildByName(”hoge_mc”);
とやっても取得はできません。
じゃあ EnterFrame イベントを取るか。ということで EnterFrame イベントでフレームが変わったら取得しようとしても、
取得できる場合もあるが、取得できない場合もある。
さらに、EnterFrame イベントは遅い。 結局のところ最初からMC をすべて配置しておくか、EnterFrame で
指定した Frame にきたことを確かめてから取得するしかないようだ。
- - シーンの削除
Scene は Flash CS3オーサリング環境でしか作ることができない。
それはまぁいいが、パブリッシュする際に Scene が統合される場合がある。
その条件としては以下の二つ。- ActionScript がまったく記述されていない。
- MovieClip に インスタンス名が記述されていない。
まぁどちらも同じ意味だ。
つまり、ActionScript を使用する見込みが無いものは、 Scene を必要としないと判断され、
パブリッシュ時に 統合されてしまう。
逆に Scene を保持するには 何か MovieClip を配置してインスタンス名を書くか
ActionScript を何か記述する必要がある。
- - フレームの切れ目が 縁 の切れ目
例えば、mc をタイムライン上に配置して、そのままシーンを移動、または
フレームを移動させ、フレームの切れ目があるとその後は同じインスタンス名でも
別のインスタンスになるようだ。
コレは フレームが離れている場合だけではない。
例えば、1フレーム目に TextField (MC でもよい) を配置して
2フレーム目以降には別のインスタンス、または空白のキーフレームを配置しておく。
1フレーム目にいる状態で1フレーム目の TextField (または MC ) を getChildByName(); などで
取得し、参照をどこかに保持しておく。
フレームを移動させ、その後1フレーム目に戻ると、
保持していた参照にはインスタンスが存在しているが、その値をいくら変更しても
グラフィックに変化は無い。
試しに == で比較しても別のものといわれてしまう。
- - フレームの切れ目が 縁 の切れ目2
コレは何も MC, や TextField に限った話ではなく
Sceneにもいえることだ。
Scene を取得するには MovieClip のプロパティに scenes があるので それで Scene の配列を取得できる。
現在のフレームの Scene は MovieClip のプロパティの currentScene で取得できる。
では、この scenes の中にある Scene は currentScene と一致するのか。実は別のもの。scenes の中身全部と currentScene を == で比較してみたら、一致するものは無かった。
結局コレの解決法は scene の name を比較するしかない。 - タイムラインって何?
例えば
child.swf を読み込む parent.swf を作ったとしよう。
child.swf のとあるフレーム(例えば4シーン中の3シーン目の途中にあるラベル)
に来たときに parent.swf から child.swf の root 上 (MainTimeLine 上) に
何かの MovieClip を addChild するように作ってある。
さて child.swf のタイムラインがどんどん進み、
一周したときに addChild された MovieClip は存在するだろうか。
さらに、コレはインスタンスとして同じものだろうか?
今までの「フレームの切れ目は 縁 の切れ目」説から考えると
「同じものではない、むしろ存在しない。」
が正解のように思えるが実は、
「存在するし同じもの」
である。
ただし周りのタイムライン上で動いているものは常に新しいものと入れ替わっている。
なので、最初に addChild されたときは画面上では一番上に存在するが、
2週目には一番下になっている。ここから考えられる「Flash においてのタイムライン」とは 「Flash においてタイムラインは addChild するタイミングや
その他のアクションにおいての『スケジュール』の様なもの」であると考えられる。シーンについても同じだ。
シーンはタイムラインの大き目の区切りだ。
Flash を扱うときに一番混乱しやすいのはここであると思う。
俺も初めて Flash を触ったときに混乱した場所だ。
- - Flex に Flash の SWF ファイルを Embed する場合
Embed を使うことで コンパイル時に SWF 内に 別の SWF や JPG などを埋め込むことが出来る。
Embed する方法では以前書いたエントリーを参考にしていただきたい。
http://blog.bk-zen.com/2007/12/27/46/
-
- Flex に Flash の SWF ファイルを Load する場合
ロードする場合は読み込まれる SWF の変更があった場合でも
変更側の再コンパイルのみで OK となる (必ずしもそうである保障はないが)
Load する場合は SWFLoader や Loader などを使用するとよい。
後に記述する SWF の複製と一緒に行うとよりよい。
SWFLoader などで読み込んだ場合、 Event.COMPLETE で呼ばれるハンドラ内で
8. と同じことをしてやればいい。
- - Flex に Flex の SWF ファイルを Load する場合
Flex に Flex で作った SWF を読み込む場合、
読み込まれた側と読み込んだ側で通信、または制御・操作が発生するかしないかで
大きく挙動が変わってくる。まずは読み込むだけの場合。
コレは特に問題なく読み込み、動作を確認できると思う。 Flex を読み込みそれを操作する場合。
Flex では Flex の SWF を読み込み、制御することは コンポーネントを読み込むことと ≒ らしい。
そのため、読み込まれる側に StyleSheet を書くことは出来ないようだ。
が。
それを回避する方法が実はある。
その方法は操作の部分で一緒に書くとしよう。
- - Flex に Flex の SWF ファイルを Embed する場合
Flex に Flex で作った SWF を Embed する場合は、
主に 10. と同じだが少し違う、
ただ Embed するだけなら Image や SWFLoader でEmbed してやれば OK。
※ source=”@Embed(’hoge.swf’)”Flex を Embed して Flex を操作する場合は
メタタグを使う。
詳しくは操作の方で。
- - Flash に Flex の SWF ファイルを Load する場合
Flash には Embed の方法が無いので、Flex を読み込むことの一つに絞って書く。
特にその他の方法と変わりはなく、Loader を使用してロードする。
たまにエラーが出る場合があるので注意。
操作するのは “ほぼ” 不可能に近い。
- - 読み込む側の Flex から読み込まれた Flash を制御する方法 (逆も可)
操作する場合には Interface を活用する。
最初で書いた通りで Flex のコンパイラと Flash のコンパイラは別物で扱えるパッケージも変わってくる。
Flash は 主に FlashCS3 についてきている fl パッケージを使用する。
Flex では Flex 2 sdk に付いてくる mx パッケージを使用する。
mx クラスのパッケージで rpc などの部分は Flash 側が使おうとするとコンパイルエラー
になるので実験してみてもいいとおもう。
サンプル(loadFlashTest.zip)
先ほど説明した通りの方法で読み込まれた SWF の
root (MainTimeLine) を取得したという前提条件で進める。
読み込まれた SWF の root に対して .hoge(); とやれば コンパイルエラーも出ず、
先に進むのだが、きれいに書くには Interface を使う。
Flash CS3 から Document クラスを設定できるようになった。
サンプルでは
Document クラスに MovieClip を継承し、 ILoadChild Interface を実装した
LoadChildDoc クラスを設定した。
root を ILoadChild クラスにキャストして ILoadChild で設定したメソッドを呼ぶときれいになる。きれいになるとだけ書いたが、実はこの方法が正しい方法で、何か分からないものに対して
あるかどうか分からないメソッドを呼ぶのは危険だ。
それよりも Interface を実装した確実に存在することが保障されたメソッドを呼ぶほうが正しい。さて Interface に実装した setLoadTest() の引数には
this を渡すのだがこの “this” は ILoadTest Interface を
実装した LoadTest クラスだ。
もう分かると思うが、 setLoadTest() 内で保持するのは ILoadTest Interface を実装した
クラスのインスタンスだ。こうすることで Flex は Flash から、 Flash は Flex から渡ってきたインスタンスの参照の
“中身” を知らなくて済むことになる。
後はそのインスタンスに実装されている Interface がメソッドの実装を保障してくれるので
そのメソッドを呼べばよい。この実装方法でおそらくすべてすんなりいくと思う。他にも方法はあるがこの方法が一番簡単。
サンプルではイベントを渡すとかもやってみている。
- - 読み込む側の Flex から 読み込まれる側の Flex を操作する方法 (逆も可)
よく紹介されているやり方は loadSample の LoadTest.mxml (読み込む側)、SWFLoadChild.mxml (読み込まれる側)
のようなやり方だ。
これでは先ほど書いた通り StyleSheet の実装ができない。
そこでここでも Interface を使う。
MXML での Interface の実装はあまり知られていない気がする。(俺だけ?)
詳しくは LiveDocs を参照のこと。
http://livedocs.adobe.com/flex/201_jp/html/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Book_Parts&file=mxmlcomponents_advanced_145_18.html
やっていることは 13. と変わらないので特に問題は無いと思う。
サンプル (loadSample.zip)
Interface を使用したやり方は loadSample の
LoadTest2.mxml (読み込まれる側) SWFLoadChild2.mxml (読み込まれる側) を参照。
この方法では StyleSheet の実装も可能。
- - 読み込む側の Flash から 読み込まれる側の Flex を操作する方法
結論から言うとできるが、あまりに無理やりすぎてお勧めできない。
というか無理な場合が何の前ぶりもなく訪れる場合がある。
なので考え方だけ載せておくことにしよう。13. のやり方とほぼ同じで、どちらにも Interface を実装しておく。
読み込まれた Flex 側から 自分のインスタンスを渡してやる。
その際に root を探す必要がある。
root プロパティではアクセスできない場合があったので root (Main Timeline) を
探す方法。 var target: DisplayObject = this;
while (target.parent.parent) {
target = target.parent;
}
return target;これで帰ってきた DisplayObject を Flash側の Interface に キャストしてやり
それに対してメソッドをコールする。引数は this。
Flash 側では それを Flex側 の Interface にキャストしてやり
メソッドコールは それぞれ Interface を実装した インスタンスに対して行う。
すると操作ができる。
※ 注意 : ランタイムエラーでできないときがある。
※ 備考 : できるときがある。といったほうが良いかもしれない。
- - Embed する側の Flex から Embed する側の Flex を操作する方法 (逆も可)
この方法もあまりお勧めできない。
なぜならばレイアウトがコレでもかというくらい崩れることがある。
上手くレイアウトできる人は挑戦してみるといいと思う。
サンプル(EmbedSample.zip)
サンプルはそれを再現したバージョンで載せてみる。
14. とほぼ同じなのでメソッドのコメントは省いた。
コレも Interface を実装することをお勧めする。
Interface の実装版も (14) と同じなので省いた。
- - SWF の複製
SWF を複製することはロード時間の短縮につながる。
もし同じ SWF を複数ロードする場合があるなら、以下の方法をとることをお勧めする。
いまだにナローバンドな環境にいる人もいないわけではないだろうから。
ついでに 何度もリクエストを投げるのはサーバーにも負荷になる。
さらに AS3 から MovieClip の複製が出来ないので この方法をとるとよい。 Loader は loadBytes を使うことで ByteArray オブジェクトに保管されている
バイナリデータからロードすることが可能。それを利用する。原理的には以下のようにする。
まずは URLLoader を使い、 dataFormat は BINARY 形式でロードする。
this.loader = new URLLoader();
this.loader.dataFormat = URLLoaderDataFormat.BINARY;
this.loader.load();
Complete Event で呼ばれるハンドラでロードされたバイナリデータを保管する。this.loadedSWF = loader.data; // loadedSWF = ByteArrayその後複製をする。this.copyLoader: Loader = new Loader();
this.copyLoader.loadBytes(this.loadedSWF);※ 参考までに AIR の場合は このときに LoaderContext を引数で渡してやる必要がある。
var loaderContext:LoaderContext = new LoaderContext();
loaderContext.allowLoadBytesCodeExecution = true;
copyLoader.loadBytes(this.loadedSWF, loaderContext);
参考 http://livedocs.adobe.com/flex/3_jp/html/help.html?content=security_7.htmlあとは Complete Event でthis.copyLoader.content
を取得すれば SWF の複製が出来上がる。
※ 以前 CopyLoader Class を作ったがちょっとバグがあったので修正中。
※ 直ったらうpするかも。
- - Flex での Stage を取得方
MXML に Script タグを書き、applicationCompleteEvent が呼ばれる前(initialize イベント時など)に
stage にアクセスすると null が帰ってくる。
そんなときの stage の取得方法。
var target: DisplayObject = this;
while (target.parent) {
target = target.parent;
}
var s: Stage = target as Stage;
ステージは DisplayObject の一番上の階層にいるので
DisplayObject の parent をたどっていけば Stage にたどり着ける。
- - Event が発生しない?
Event が発生しない問題がある。
原因は不明だが SWF のロード時にたまにあるようだ。
再現性のきわめて低い問題で対策は Timer などで監視するしかないように思える。
- - 外部からロードした SWF から Class を取得する[2008/03/24 追記+修正]
外部 SWF をロードして その SWF 内で定義された リンケージ内の Class などを取得する方法
例えば、 Flex で読み込んだ SWF の中で リンケージで設定した Class があったとする。
それを Flex 側で new するには以下のようにする。
読み込む場合には Loader を使うのが一番簡単っぽい。
ApplicationDomain.getDefinition() を使うとよい。
具体的には以下の通り。
どちらもロードするところまではほぼ変わらないので省略する。(Event.Complete のハンドラが呼ばれたところから)- Loader を 使用する場合。
// loader -> private var loader: Loader;
loader.contentLoaderInfo.applicationDomain.getDefinition(”ClassName”);
で SWF のリンケージ内の Class を取得できる。 - SWFLoader を使う場合。
// loader -> private var loader: SWFLoader;
Loader(loader.getChildAt(0)).contentLoaderInfo.applicationDomain.getDefinition(”ClassName”);
で SWF のリンケージ内の Class を取得できる。
こっちの方が簡単でした↓
DisplayObject(event.target.content).loaderInfo.applicationDomain.getDefinition(”ClassName”);
-
- Loader を 使用する場合。
以上。
まとめ
Flash と Flex を扱う状況は冒頭でも書いたとおり、
Flex で アプリケーションの土台を作り、 Flash でその部品を作るという形が多い。
そのときに一番重要なのは Flex を作る側の人と、 Flash を作る側の人でしっかりと決め事をすることだ。
間に入るのはもちろん Interface 。
Flex と Flash を扱って Interface の重要性に気づいた。
お互いコレさえ決めてしまえば後はほぼ自由に作れると言っても過言ではないと思う。
それと、Flash にはまだまだ謎な仕様が多い。
また何かが見つかったら報告するとしよう。
では、花粉症に悩まされる JC でした。
Embed の話題が大量に出てきたついでに。
Embed を楽にする Embedder - http://blog.bk-zen.com/2009/08/17/207/
- Newer: 驚いた
- Older: FlashDevelop 3.0.0 Beta6 がリリースされていた
Comments:1
- jc 08-03-19 (水) 8:44
-
うーん。
何かエディタが微妙に変なことしてるっぽくてごちゃごちゃ表示されてるなぁ。。。
何かいいエディタは無いものか・・・。
Trackbacks:3
- Trackback URL for this entry
- http://blog.bk-zen.com/2008/03/19/53/trackback/
- Listed below are links to weblogs that reference
- Flex と FlashCS3 で SWF を作るときの 18 のポイント+α from 馬鹿全
- pingback from 馬鹿全 - Flex と FlashCS3 で SWF を作るときの 18 のポイント+α | 次なるもの 08-03-20 (木) 1:00
-
[...] 馬鹿全 - Flex と FlashCS3 で SWF を作るときの 18 のポイント+αTopic: 未分類| 以前も書いたことですが、色々増えてきたのでまとめてみた。 Flex と Flash CS3 でハイブリッドな SWF を作る場合、 大抵は Flex で土台を作り、グラフィック部分などを Flash で作るということになるだろう。 その際に俺が実際引っかかったりした部分をまとめた。 なので Flash しか関係ないじゃんとか Flex しか関係ないじゃんと思わずに Flash しか関係ないじゃん… original article [...]
- trackback from 馬鹿全 08-03-24 (月) 16:59
-
Flex と FlashCS3 で・・・に追記…
http://blog.bk-zen.com/2008/03/19/53/
に追記した。
20. 外部からロードした SWF から Class (more…) - trackback from SCRATCHBRAIN.BLOG v2// 洋楽・音楽サービス・Flash ActionScript3.0・グラフィックアート 08-05-13 (火) 20:23
-
PageFlipクラス(AS3)の基本的な使い方、ついでにF…
[demoページ] Flash 8(AS2)でPageFlipと言えば76des… (more…)

