ActionScript3のScrollPaneでハマる

ActionScript3つまりFLASHでのお話です。
HTMLの場合はdivタグのスタイルwidthやheightを設定してoverflow:autoとすれば簡単なスクロール領域を用意できます。
ActionScript3の場合はScrollPaneを使えばいいらしいのです(それがわかるまで自分で大きさやScrollRectを計算してスクロールバーまで自作してこんな機能はflashにないのかと愚痴ってました)が、その内容をあてがうところで躓きました。単純にaddChildすると手前に表示されてScrollPaneが奥になってしまいます。てっきり子供にさえすればコンポーネントが勝手にやってくれるのかと思いましたが違いました。sourceというメソッドがあって、それにオブジェクトを放り込む必要があったのです。
さらに、このScrollPaneのsourceに放り込んだオブジェクトは使い回しができません。ほかの子供になると対象から外れてしまうようです。別のScrollPaneのsourceにあてがってやると一番最後のもののみが表示されます。オブジェクトの単純コピーでは参照になるためかやはりだめで、別の入れ物を用意してやらないとだめのようです。異なる窓で大きさの異なるMovieClipを表示させたかったのに、できませんでした。

ActionScript3でdrawRectのバグ

ACtionScript3で矩形を描くのにdrawRectがあるけど、よくよく見るとどうもおかしい。
どうも基点にごみが混ざっているようだ。
内部的にはlinetoでやっているのか、基点つまりlinetoだt基点と終点が重なる場所、つまり線でいうところのcapsがsquareになっている。表示を拡縮すると消えるけれど、小さく表示すると露骨にはみ出る。
drawRectは使えないってことなのかなぁ・・・あぁ、めんどくさい。

ActionScript3で一度loadした画像をキャッシュとして扱うのにハマった

Flash的にはインスタンスの複製とでもいうのだろうけど、こういう独自の呼び方はなかなか覚えられない傾向があるで覚える気もない(だから覚えないんだろうけど)。
ライブラリに最初から埋め込んである画像はクラスとして書き出しておけばnew hoge(0,0);とかでいくらでも表示を量産できるんだけど、Loaderでloadした画像で同じことをしようとしてはまった。
いろいろ端折ってるけど、たとえばこういう使い方

var loaderObj:Object = new Object(); // グローバルに宣言

var bm:Bitmap = Bitmap( loader.content ); // loadした内容をbmへ
loaderObj[ 'huga' ] = loader.content; // loadの内容をオブジェクトに入れて

var bm2:Bitmap = Bitmap( loaderObj[ 'huga'] ); // 他の関数から呼んでみる


実際に有効なのはbm2のみ。
オブジェクトに丸ごと放り込みさえすれば後は使い放題なのかと思いきや、1対1の関係らしい。
「actionScript3 loader」をググってヒットしたページを順番に眺めていたらヒントがあった。
Loaderではなく、bmを見に行けばいいらしい。

var bm:Bitmap = Bitmap( loader.content ); // loadした対象をbmへ
loaderObj[ 'huga' ] = bm; // loadの内容ではなくbmをオブジェクトに入れて

var bm2:Bitmap = Bitmap( loaderObj[ 'huga' ].bitmapData ); // 他の関数から呼んでみる


ここまで書いておいて、もしかすると?と思って書き直してみた。

var bm:Bitmap = Bitmap( loader.content ); // loadした対象をbmへ
loaderObj[ 'huga' ] = Bitmap( loader.content ); // loadの内容ではなBitmapの・・・(なんて呼び方?キャストではないしオブジェクトの変換?)をオブジェクトに入れて

var bm2:Bitmap = Bitmap( loaderObj[ 'huga' ].bitmapData ); // 他の関数から呼んでみる


リファレンス眺めてもこの挙動につながる箇所を見つけられなかったけど、とりあえずBitmapとしてオブジェクトに入れておけば、自由に扱えるらしいことが分かった。
BitmapでLoaderの何らかの制限から開放されているといったところか。
「Loaderはファイルを読むためのオブジェクト」とあるので、それ以外の用法は制限されるのか、一度Bitmapにすればその制限から開放されて通常の(期待した)使用ができるのか。
loaderObj[ ‘huga’ ]自体の型には何も違いはないのだけれど。
Loaderだから何々ができないという書き方がどこにもない(探した中では)のが悲しい。

ちなみに、clone()なしでも表示は量産できるだけど、オリジナルをnullにするとかどうにかすると道連れになるかどうかとかなのかもしれないけど、今のとこ必要ないので気にしないことにする。オブジェクトに入れたものが何者なのかこんがらがったままだし。

Adobe Flash CS4の不可解な挙動

いろいろいじくっていると、パブリッシュ時にエラーを吐いてくれます。
もちろん、構文に問題があるからなのですが。
で、出くわしたこんなエラー
「ReferenceError: Error #1065: 変数 ComponentShim は定義されていません。」
グーグル先生に尋ねても知らん振り。
仕方がないので何千行もあるソースをコメントアウトしたりtraceの場所を増やしてみても変えたりしてもこのメッセージ1行のみ。
つまりコンパイル時のエラーらしい。

ならコンパイルエラーと書け。
構文エラーじゃないじゃん?

いろいろ弄っていると、いつの間にかシンボルの1つが画面から消えているのに気がついた。
オブジェクトとしては存在するんだけれど、表示されない。
ボタンでは表示できるがムービークリップでは表示できない。
一度ファイルを閉じて開きなおしてみるが、なぜか保存時のものに回復されず、最新の状態が復帰してしまう。
これはまさに顔面蒼白という状態である。

もうどうにでもなれと、アプリケーションを落として再起動してみると・・・
なんてことはない。
正常に機能していた。

そういえば操作を戻す作業をしてからおかしくなったような・・・?
どうやらFlashのガベージコレクションには欠陥があるようだ。
どういう手順で発症するのかわからないが、何らかの条件で最新の状態のみが優先されリセットされていないらしい。
それで戻る操作をすると整合性が取れなくなり、コンパイラのどっかで構文エラーが発生してパブリッシュに失敗するようだ。
しかし検索してもヒットしないエラーにお目にかかれるとは。

ActionScript3のthisに悶え苦しんだ

Javascriptがそれなりに使いこなせれば、ActionScript2も特に問題がなかったわけですが、今頃になっていじり始めたActionScript3(以下AS3)で悶え苦しみました。
イベントやシンボルの扱いが変わったことも、調べさえすれば特に問題にならず、着実に開発は進んでいたのですが・・・
さて、行き詰ったのが「this」の扱い。
いままでは、とにかく「オレオレ!」でよかったので、イベントに関数を宛がってやれば、関数からオブジェクトをごにょるのはとても簡単でした。
が、AS3ではなぜか常にグローバル?なオブジェクト(実在してないっぽいのだが)になってしまう。

for( var i = 0; i < 10; i ++ ){
    var mc:Object = new mcHoge();
    mc.name = 'hoge' + i;
    mc.addEventListener(
        MouseEvent.MOUSE_OVER,
        editPointAnchorMouseOverHandler
    );
    function editPointAnchorMouseOverHandler(evt:MouseEvent):void{
        trace(this.name);
    }
    obj.addChild( mc );
}


いままではこんな感じで(AS3用にイベントを書いてあるよ)thisを追跡できたのに、AS3ではできない。
マウスが乗っかるとundefinedとなる。
ちなみにobjはStageとかで読み替えてみて。
いろいろ調べてもどうでもいいウンチク(もちろん大事なのだが)ばかりで、AS3の解説本の著者がグダグダ語っていたりするがよく見ればAdobeの例文のままで悲しい思いをするだけで実例がない。「ActionScript3 this global」とかでググってもだめっぽい。
本当はクラスにすればいいんだろうけど、別ファイルにしなければならないらしい?
同じファイルの中でパッケージ宣言できないのは厳しい。
使いまわさなくても都合上クラスが便利なこともある(性格にはクラスであるべきことのほうが多いのだが)のにファイル分けなきゃいけないの?
と、それたところで軌道修正。

結局のところ、別に関数を用意して、その中でオブジェクトを作ってやって戻り値もオブジェクトにすれば、擬似的にパッケージ化できることが判明。OOPを実装したはずのAS3のコンパイラが関数をどう扱っているのかなぞである。
結局はこうなった。

for( var i = 0; i < 10; i ++ ){
    var mc:Object = fuga( i );
    obj.addChild( mc );
}
function fuga( i:int ):Object {
    var mc:Object = new mcHoge();
    mc.name = 'hoge' + i;
    mc.addEventListener(
        MouseEvent.MOUSE_OVER,
        editPointAnchorMouseOverHandler
    );
    function editPointAnchorMouseOverHandler(evt:MouseEvent):void{
        trace(this.name);
    }
    return mc;
}


実質、関数をオブジェクトと定義しているわけだが、関数は関数しか宣言できないのでオブジェクト・・・あれ?
もしかしてこう書けばいい?
var mc:Object = function( i:int ):Object{ var mc:Object = new mcHoge(); [省略]; return mc; }
とすると強制型変換に失敗したと怒られた。
理屈ではこれでいいはずなのに、なんでだろ?
まぁ、初めたばかりだし、AS3の書き方に慣れてからまた考えよう。