「AS3」カテゴリーアーカイブ

タイムラインに置いて、名前をつけたシンボルのインスタンス名を取得するうまい方法はないだろうか。


随分あけてしまいましたが、なかなか書くネタを搾り出すのも大変ですね。もうちょっと間隔を狭められるように書けたらいいなと思ってます。

今回はFlash使ってて変な現象に出くわしたのでその話。

まあタイトルの通りなんですが、タイムラインに配置して、同じシンボルを違う名前で配置する時というのはそれなりにあると思います。タイムラインに置いてしまったほうが位置の調整が楽ということもあり、たまにやります。

で、タイムラインに配置したオブジェクトを、『オブジェクトにつけた名前はそのままに、インスタンス名に応じて処理をする』という処理が必要になりました。まあASだけで配置していれば適当に名前をつけてグループ化すればよかったんですが、タイムラインに配置しているので、そうもいかない。

諦めてASで配置することも考えましたが結構な手間になってしまうので、何か方法はないか、ということで探ってみたら、擬似的に何とかできました。

方法 → 対象となるオブジェクトの1フレーム目にラベルを付ける

ラベルがついていればMC.currentLabelで取得できるので、そこから名前を情報を取得する、と。うーん、多用すべきでないテクニック臭がプンプンしますね。どう考えてもスマートじゃありません。しかしまあ、目的は達成できてるので、OKとしておきます。

調べていく過程で気づいたのは、「対象となるオブジェクト自身のタイムラインのフレームアクションに何かしらのスクリプトが記述されていればインスタンス名が取得できるようになる」ということです。スクリプト、と言ってはいますが、単なるコメントのみならず半角スペース1つ入れるだけでインスタンス名が取得できるようになります。

trace((対象オブジェクト).toString())

というような感じで。(toString()は無くても動作します。)

通常、何も書かれてなければ

[object MovieClip]

になるけれど、何かしら書かれていると、

[object インスタンス名_数字]

となるので、インスタンス名を切り出せば使えることになります。

ただこの方法だと、MovieClipでない新しいクラスが作られているようにも見えるので、あまり良くないような気もします。どちらがメモリを食うか等々は調べてないので不明です。その作り方が悪い、というのはもっともな話ですが、小細工をすればある程度のことは何とかなるようです。

↑以外でもスクリプト付けたし法ではうまく行かない条件が何かあった気がするんですが(MovieClipに変換されますのような警告がでた気が)、また同じ状況に出くわしたら書いてみます。

画像をタイムラインに置いた場合のBitmapDataへのアクセス


FlashIDE上で画像を配置して、後でそのビットマップデータへアクセスしようと思ってもうまくいかない。

例えば、ステージに画像を直接貼り付けただけのflaファイルがあったとして、1フレーム目のスクリプトに

trace(this.getChildAt(0));

と書くと、

[object Shape]

となって、BitmapやBitmapDataにはアクセスできないみたい。

これをどうにかできないかと思っていろいろ情報を探してみたら、ライブラリでその画像データを『ASに書き出し』にすると、その他何も変更しなくても

[object Bitmap]

となって、画像へアクセスできるようになる様子。

つまりは画像をタイムラインに配置しているだけだと、その画像は内部的には自動でFlashIDE上で「分解」をしてShapeになった状態として認識されてるということかな?

アクセスはし辛い代わりに後でdispose()する必要もなくなるわけで、必要によりけりですが、どうしてもタイムラインに配置した画像を制御したいという時には役に立つかもしれません。

ただ、この間これをやろうとしたら、対象となるMCを作り直すときに毎回画像データとしてnewすることになるのか、ASに書き出したほうが動作が遅くなった気がします。

スクリプトで画像をnewして表示する場合も多々あると思いますが、意外とBitmapを作るよりもshapeにbeginBitmapFillした方が速かったりして。この辺は時間があるときに確認してみたいです。

swfの親の有無


たまに使おうとすると忘れてるのでメモ。

自分に親がいるかどうか確認する

this.loaderInfo.addEventlistener(Event.COMPLETE, selfLoadComp);
private function selfLoadComp(e:Event):void{
if(!loaderinfo.loader){
//親がいない
}
else{
//親がいる
}
}

これを最初に仕込んでおいて、initializeメソッドを呼ぶ前に何か処理させれば使えるはず。「自分が読み込まれたら」というイベントは自分だけで実行した時もEvent.COMPLETEするようです。

プリローダを実装している場合や、後読みのswfファイルである場合に、親となるswfがいないときでも正常に動作させるために、親がいない場合の特殊処理を書く時に使えると思ってます。特に親ファイルでデータをロードして子供に渡す場合、これを使うと親なしで子供だけでパブリッシュして実験できるようになったりするので便利かなーと。(間違えると2重に読み込んだりすることになりますがw)

この場では関係ないですが、Loaderで指定したURLがない場合、IOErrorEventになるわけですが、この時の失敗したURLをIOErrorEvent自体から取得する方法というのはないんでしょうか。どうにもロード失敗すると、loaderInfoのプロパティが一部しか取得できないみたいで、urlその取得できない値の一部の様子。

単品だったらそれでOKですが、何個もロードしている時はどれがエラーだったのかわかると便利そうなんですけどね。loaderにname属性をつけたらなんとかなるのかな・・・?

論理演算のXORを実現する


AS3ではビット単位でのXORはできるけど(^)、論理演算でのXORは用意されていないようなので、何とかできるように工夫してみた。

普通に

if(isA ^ isB){
//XORでtrueの処理
}

という感じで書くこともできるかと思ったら、数値型でないとパブリッシュできません。というわけで、

if(int(isA) ^ int(isB)){
//XORでtrueの処理
}

のような感じにしたらできました。一応traceさせると、

trace(Boolean(int(true) ^ int(true)));//false
trace(Boolean(int(true) ^ int(false)));//true
trace(Boolean(int(false) ^ int(true)));//true
trace(Boolean(int(false) ^ int(false)));//false

ということでXORが実現できました。まあビット単位の演算はできる以上当たり前ですし、遅くなったりしないのかという疑問も残りますが、条件文2つ書くよりはいいかなと。

計算もビット演算使った方が早い場合もあるようなので、ビット演算についてはもうちょっと使えるようにしたい。ビットシフトとか。