getChildByNameの謎


通常、タイムラインで配置したオブジェクトや、外部から読み込んだswfに名前をつけようとしても

Error: Error #2078: タイムラインに配置されたオブジェクトの name プロパティは修正できません。

というエラーが出て名前を変更できない。

それならば、と思ってカスタムクラスを作って、

private var _name:String;
public override function get name():String{return _name;}
public override function set name(value:String):void{_name = value;}

ってやって無理矢理名前をセットできるようにしてみましたが、これをやると、

//hogeを名前をつけられるようにしたオブジェクトとする
hoge.name = 'test';//エラーは出ない
OBJ.addChild(hoge);
trace(OBJ.getChildByName('test'));//結果はnull
trace(OBJ.getChildAt(0).name)//結果はtest

という謎の状態になってしまいました。

カスタムクラスのsetterで

super.name = value;

とするとやはりエラーが出るので、setterのnameは上のような動作ではなく、違う動作をすると思われます。何か内部的なIDを割り振っているんでしょうか。あるいは子の名前のリストを内部的に持っているとか?

別の方法で何とかしましたが、思いつきだけで動かしていると痛い目に遭いますね・・・。

余談:

既にunloadしているMovieClipをもう1度unloadしようとすると、エラーになる。

自分でunloadを仕込んだのに忘れてunloadしようとしたら

Error #2099: 読み込み中のオブジェクトは、十分に読み込まれていないので、その情報を表示することができません。

というエラーが。loaderが取得できないのかと思ったら、そもそもその前に削除していたという・・・。まあ確かにloaderが取得できない、という想像は正しいですがw

BitmapとShapeの扱い


ビットマップはタイムラインに置いておくと、パブリッシュ時にShapeに変換される(ただし、AS書き出ししていると、Bitmapになる)。というような話を前に書いてましたが、もうちょっと調べた話。

タイムラインに置いたShapeは隣接レイヤーにShapeがあると統合される。これは上記ビットマップのデータにも有効であり、AS書き出しをしていなければShapeに統合される。

したがって、レイヤー3つに

画像/画像/Shape

という感じでデータをタイムラインに置き、そのクリップ内で

trace(this.numChildren);

すると結果は

1

となる。

このとき、真ん中の画像をASに書き出しすると、

3

となる。

trace(this.getChildAt(0));
trace(this.getChildAt(1));
trace(this.getChildAt(2));

の結果は

[object Shape]
[object Bitmap]
[object Shape]

になる。

勝手にShapeが合成されない方法を編み出したらきっと便利かもしれない。今のところ一番手っ取り早そうなのはシンボルに変換することだろうか。スクリプトで書けばまったく問題にならない部分ではありますが。

ActionScript3.0エラーアーカイブスを少し読んだ。


エラーが出たときにここから探す本・・・というよりは「ふんふんこんなエラーがあるのか」と読むような本の気がする。

だいたいエラーを吐いて困る場合は、「こうすれば解決なのは分かってるけど、実際にその処理は何らかの理由で実装できない」という場合が多い気がするし、そもそもエラーは出ないが動きが変という場合が圧倒的に多い気がする。エラーを吐いてくれさえすればJavaScriptよりは親切な気がする。AS。

なので、これで安心のスクリプトが書ける、というよりはプログラマとして読んで楽しむもののような気がします。

先日

1084:シンタックスエラー:leftparenがcolonの前に必要です

というエラーを吐いたんですが、調べても解決しませんでした。

まあgetterに()をつけ忘れたという初歩的なミスなので数分で解決しましたが。

・・・というかエラー文をちゃんと読めばコロンの前に括弧が足りないと明確に書いてあるんですよね。ちゃんとエラー文を読めよ、と。(left parenで左括弧ですね)

エラー集もいいんですが、FlashDeveloperがハマった罠を集めたAS3罠集みたいなのがあったらすごくいいなぁと思ったりします。

カヤックさん辺りが新サービスとしてやったりするんじゃなかろうかと勝手に思ってるんですがどうなんでしょう。罠共有サイト。問題はどうやって検索させるか、ということでしょうね。どういう状況でどうなったのかという説明を文字だけでするのは至難の業で、絵を使うと検索し辛くなるので、どういう方法で検索させるかが問題になりそうな予感。でもあったらFlash作るのが少しでも楽になるかなぁと思います。

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


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

今回は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した方が速かったりして。この辺は時間があるときに確認してみたいです。