[as2]の最近のブログ記事

AS3の EventDispatcher クラスをAS2でも使えるようにと思って作ったクラスです。

EventDispatcher クラス
Event クラス

サンプル用 fla ファイル
demo.fla
demo2.fla

willTriggerメソッドが、どうやって実装するか悩んだ(willTriggerの挙動自体いまいち把握してない)のでとりあえずほったらかしてます。

あと、mx.events.EventDispatcherを継承してますが、中身はまったく別物です。
ムービークリップに適応した場合、イベント通知がルートからたどっていくようになってます。(微妙ですが)

で、AS3的に「addEventListener("enterFrame", handler )」とかやりたいところですが、
元々AS2のMovieClipにそんな機能は実装されてないので、前のエントリーで書いた EventMediator クラスを使います。

こんな感じです。
import flash.events.EventDispatcher;
import flash.events.Event;

import com.seyself.events.EnterFrameBeacon;
import com.seyself.events.EventMediator;

EventDispatcher.initialize( MovieClip.prototype );

var madiator:EventMediator = new EventMediator( new EnterFrameBeacon() );

madiator.addEventListener( "enterFrame" , null );
madiator.member = [mc];   // ステージ上に配置してあるムービークリップ

mc.addEventListener( "enterFrame" , enterFrameHandler );
function enterFrameHandler( event:Event ):Void
{
    trace(event.target);// _level0.mc
}

EnterFrameBeaconクラスは、単純にenterFrameイベントを通知し続けるクラスです。
AS3を使っててAS2に戻ると、何かと不便に感じることが多いです。
AS3とAS2に互換性が無いのが、今、一番厄介に感じます。
いずれ完全にAS3に移行したときのことを考えて、少しAS2にAS3らしさを取り入れたほうがいいのかな?なんて思ったりもしますが、それが正しいのか間違ってるのかはよくわかりません。
ただAS3からAS2にクラスを逆移植することがあるのですが、Eventクラスとか、デフォルトのクラスでよく使うものはAS2にもほしい。
誰か作ってないかなあ。と思う今日この頃。
あと、個人的にProxyクラスがAS2にもほしいけど実装の仕方がわからない。

flash.utils.Dictionary
import flash.utils.Dictionary;

var dic:Dictionary = new Dictionary();
var a = {};
var b = {};
var c = {};

dic.add( a , 1 );
dic.add( b , 2 );
dic.add( c , b );

trace("length : "+dic.length);// output 3
trace("object a : "+dic.value(a));// output 1
trace("object b : "+dic.value(dic.value(c)));// output 2
dic.del(c);
trace("length : "+dic.length);// output 2
trace("has a : "+dic.has(a));// output true
trace("has b : "+dic.has(b));// output true
trace("has c : "+dic.has(c));// output false
以前書いた「画像をロードしたMC 上に attachMovie」という記事に
助言をいただきまして、ちょっと試してみたので掲載しておきます。

読み込み先の"sub.swf"には「imageMC」というムービークリップが配置されてます。
var mc:MovieClip = this.createEmptyMovieClip("loadSWF",10);
var loader:MovieClipLoader = new MovieClipLoader();
listener = { onLoadComplete:function(){
    trace(mc.imageMC);                      // output 1
    mc.onEnterFrame=function(){
      trace("onEnterFrame : "+mc.imageMC);  // output 2
      delete this.onEnterFrame;
    }}, 
    onLoadInit:function(){
      trace("onLoadInit : "+mc.imageMC);    // output 3
    }};
loader.addListener( listener );
loader.loadClip( "sub.swf" , mc );
出力結果
undefined
onEnterFrame : _level0.loadSWF.imageMC
_level0.loadSWF
onLoadInit : _level0.loadSWF.imageMC
出力結果の1行目は "output 1" 、2行目は "output 2"、
3行目は sub.swf のルート1フレーム目に書かれた「 trace(this); 」の出力、
4行目が "output 3"になります。

僕は今まで onLoadInit が読み込みを開始したときのイベントだと勝手に勘違いしてました。
実際にはonLoadInitは読み込まれたswfの1フレーム目のスクリプトが実行された後に呼び出されるみたいです。
onEnterFrameは各フレームのスクリプトの一番最初に実行されるルールがここでも有効みたいなので、onLoadInitが呼び出される前(読み込まれたswfのスクリプトが実行されるよりも前)に実行されるみたいです。

それぞれ実行されるタイミングが違うので、意図的にこれらを使い分ければ便利かもしれないです。
Yoropan@Flaさんのブログ記事にコメントしたら失敗してしまいました。
http://yoropan.no.coocan.jp/wp/index.php/archives/85#comment-31

ここにコメントで書こうとしたソースを掲載しておきます。

Yoropan@Flaの筆者さん、すいませんでした。

var arr:Array = [0,1,2];

for(var i=0; i<arr.length; i++){
  var names="hoge"+i;
  var box_mc = this.createEmptyMovieClip(names,i)
  box_mc.i=i;
  box_mc.onRelease=function(){
    box_mc.name=arr[this.i];
    trace("--release event");
    trace("box_mc.name = "+box_mc.name);
    trace("hoge0.name = "+hoge0.name);
    trace("hoge1.name = "+hoge1.name);
    trace("hoge2.name = "+hoge2.name);
    trace("box_mc = "+box_mc);
    trace("this = "+this);
    trace("");
  }
  fillRect( box_mc );
  box_mc._x = i*110;
}
trace([i,box_mc]);

function fillRect( mc )
{
  var x = 100;
  mc.beginFill(0,100);
  mc.moveTo(0,0); mc.lineTo(x,0);
  mc.lineTo(x,x); mc.lineTo(0,x);
}

はじめてトラックバックという機能を使ってみます。緊張の一瞬です。

trick7さんがblogに「画像をロードしたMC 上に attachMovie できない」という記事を書かれてまして、これってよくいろいろと聞かれるので書いておこうと思いました。

まずテスト用に以下の図のような構成の"main.swf"と"sub.swf"というファイルを用意しました。


"sub.swf"のルートの1フレーム目には
trace(this);
とだけ書かれています。
あと、ムービークリップ「imageMC」を配置、そのなかに直接画像を配置しています。

で、"main.swf"にはリンケージ設定をした「attachMC」がライブラリに入った状態で、以下のスクリプトをルートに書いておきます。
import flash.display.BitmapData;

var loadMC:MovieClip = this.createEmptyMovieClip("loadMC",10);
var bmp1:BitmapData = new BitmapData(100,100,true,0);
var bmp2:BitmapData = new BitmapData(100,100,true,0);
var draw1:MovieClip = this.createEmptyMovieClip("draw_1",20);
var draw2:MovieClip = this.createEmptyMovieClip("draw_2",30);
loadMC._y = 120;
draw2._x = 120;

var loader:MovieClipLoader = new MovieClipLoader();
var listener = { onLoadComplete:function(){ 
    trace(loadMC.imageMC); // output : undefined
	
    loadMC.attachMovie( "attachMC", "attachMC" , 10 );
    bmp1.draw( loadMC ); // 描画されない
    draw1.attachBitmap( bmp1, 10, "auto", true );
    
	loadMC.onEnterFrame=function(){
      trace(mc.imageMC); // output : _level0.loadSWF.imageMC
      
	  bmp2.draw( loadMC ); // 描画される
      draw2.attachBitmap( bmp2, 10, "auto", true );
      delete this.onEnterFrame;
    } 
  }};
loader.addListener( listener );
loader.loadClip( "sub.swf" , loadMC );
結果は以下のようになります。

出力結果
undefined
_level0.loadMC.imageMC
_level0.loadMC
「出力結果」の3行目が"child.swf"の「trace(this);」の出力になります。

まず、AS2では読み込み元(この場合は"loadMC")が"sub.swf"のルートになります。(画像の場合も同様かと思います)
読み込みが完了した後、15行目の「loadMC.attachMovie(~」でattachしようとしているのですが、この時"loadMC"は"sub.swf"のルートになっているので、"sub.swf"のルートに attachMovie しようとしていることになります。
AS2では外部読み込みしたSWFに対してattachで配置することができません。(逆も同じです。)
なのでこの場合も配置することができないのです。


あと、合わせてよく聞かれるのが BitmapData の draw とかその辺です。というかイベントのタイミングの話になるのですが。
なので一緒にテストしてみました。
最初の図と見比べていただくと"draw1"の箇所が表示されていないのが分かります。
スクリプトでいうところの16、17行目の箇所です。
これは、"onLoadComplete"イベントが発生した時点では、読み込みは完了しているが画面上に書き出されていないことをあらわしています。
まだ書き出されていないので、13行目の参照も、結果は「undefined」になってしまいます。

そこで一連の処理が終わって、描画処理も終わった後で"draw"を実行するために"onEnterFrame"を使っています。
"onEnterFrame"は現在のフレームの処理がすべて終わった後、次のフレームに移った瞬間に実行されるので、おそらく読み込みが完了してから最短で"draw"する方法じゃないかと思います。
それが20行目から24行目になります。1回実行したらこの処理はもういらないので"delete"で削除してます。


さらについでなのでAS3でも試してみました。
sub.swf
trace(this.name);
main.swf
import flash.display.*;
import flash.net.URLLoader;
import flash.net.URLRequest;

var loadMC:Loader = new Loader();
var bmp1:BitmapData = new BitmapData(100,100,true,0);
var bmp2:BitmapData = new BitmapData(100,100,true,0);
var draw1:Bitmap = new Bitmap( bmp1, "auto", true );
var draw2:Bitmap = new Bitmap( bmp2, "auto", true );
this.addChild(loadMC);
this.addChild(draw1);
this.addChild(draw2);
loadMC.y = 120;
draw2.x = 120;

var request:URLRequest = new URLRequest('sub.swf');
var info = loadMC.contentLoaderInfo;
info.addEventListener( "complete" , listener );
function listener( e ){ 
  trace(loadMC.getChildByName("imageMC")); // null
  trace(loadMC.getChildAt(0).getChildByName("imageMC").name); // imageMC
  
  //mc.addChild( new attachMC() );//Error: Error #2069: Loader クラスは、このメソッドを実装しません。
  loadMC.getChildAt(0).addChild( new attachMC() );
  bmp1.draw( loadMC );
  
  loadMC.addEventListener( "enterFrame" , function(e){
    trace(loadMC.getChildByName("imageMC")); // null
    trace(loadMC.getChildAt(0).getChildByName("imageMC").name); // imageMC
    
    bmp2.draw( loadMC );
    loadMC.removeEventListener( "enterFrame" , arguments.callee );
  } );
}; 
loadMC.load( request );

出力結果
instance4
null
imageMC
null
imageMC
AS3だと外部ファイルにも"new"で配置できるんですね。
AS2と違っているのは"loadMC"が"sub.swf"のルートになるんじゃなくて、"loadMC"の中に"sub.swf"が入るようになったんですね。
あと、この結果からイベントのタイミングが描画されたあとに発生してるのもわかります。

なんか異様に長くなってしもた。
追記:
サンプルのflaファイルをアップしときました
attach_sample.zip