そうかdispatchEvent()を使えばいいんだ

眠りに就く前のベッドの中で前回のエントリーがどうも気になって考えてたら、別の方法を思いつきました。

リスナー登録したオブジェクトのdispatchEventを呼んでやるだけ。実際にはクリックはしていないんだけれど、手動でクリックイベントを発生させるわけですね。これならイベントリスナーが受取るパラメータの型も本来通りのMouseEventのままでOK。

var sprite:Sprite = new Sprite();
sprite.graphics.beginFill(0x333333);
sprite.graphics.drawRect(0, 0, 100, 20);
sprite.graphics.endFill();
addChild(sprite);

sprite.addEventListener(MouseEvent.CLICK, myMethod);
sprite.dispatchEvent(new MouseEvent(MouseEvent.CLICK));
//この時点でclickイベントが発生

function myMethod(event:MouseEvent):void {
  trace(event.type);
}

このやり方はAS2.0で以下のようにしてMovieClipのイベントリスナーを呼ぶのと同じ感じだと思います。

mc.onRelease = myMethod;
mc.onRelease();
//この時点でonReleaseイベントが発生
 
function myMethod():Void {
  trace("onRelease");
}

ということで、前回の僕のやり方はやっぱり邪道みたい。さて、スッキリしたところで、寝よう。

Flashプロジェクトとか設計の話

あまり話題になっているのをみかけないのでエントリーしてみましたが、FLASHerのみなさまはFlashのプロジェクトファイルを活用しているでしょうか?

扱うクラスの数が増え、パッケージの階層も深くなっていくと、目的のファイルを探すのも一苦労ですよね。僕は実際のパッケージ構成と同じになるように、プロジェクトファイル内にフォルダを作成し、扱うクラスファイルをすべて登録するようにしています。プロジェクトへの登録が、フォルダごと行えないのはAdobeさんに是非改善してほしいところですね。

プリッシュするflaファイルは右クリックして、「デフォルトのドキュメントにする」設定にしておけば、flaファイルが開いてない状態でも、プロジェクトウィンドウの「プロジェクトのテスト」ボタンをクリックすれば、swfをプレビューすることができるので便利です。

また、作成された.flpファイルをデスクトップ等すぐにアクセスできるところにエイリアス(ショートカット)を作成しておくというも、なかなか便利ですよ。

Windows版の場合はバージョン管理とやらも行えるらしいのですが、これは見た感じDreamweaverのチェックイン/チェックアウト機能みたいものでしょうか。個人でも扱えるバージョン管理ツールみたいなものだと良かったのですが。

さて、パッケージ構成の話が出た流れで書きますが、実はこれもどうしていいものなのかあまりよく分かりません。僕はパッケージ構成は基本的にhtmlでサイトを作る時と同じような感じでやっています。ルートにはindex.htmlとしてのMain.as(ドキュメントクラス)。そして例えばプロフィールというコンテンツがあるとすれば、profileというフォルダを作り、public設定したProfileMain.asを作成し、ドキュメントクラスから参照できるようにします。プロフィールパッケージ内の他のクラスは全てinternalで作成し、他のパッケージからアクセスできないようにしておきます。

ドキュメントクラス(Main.as)および、ドキュメントクラスから唯一参照が許される各パッケージ内の○○Main.asはシングルトンで作成し、それらへの参照が必要な場合はgetInstance()で参照します。そして同一パッケージ内で共通して扱う主要なデータは、この○○Mainクラスのprivateインスタンスとして集中管理できるように、getter/setterで常に最新の値を取得/代入できるようにしています。(いま気づいたけれど、この場合はgetter/setterもpublicじゃなくてinternalで良かったのかも)

といっても、実際のプログラムはこれほど綺麗に型通りに行えない場合も多々あるのですが。この辺りの話も皆さんどうしてらっしゃるのか、興味があるところです。

Flashをやっていると、ビットマップ処理とか3D表現とか数学系モーション?とか、そういうビジュアル的なインパクトが強い特定のフィールドに特化したプログラム技術/知識にばかりつい注目しがちになってしまいますが、実はこういうプログラム全体の構造を設計する力が実践では必要なんだよなぁーと痛感している今日このごろです。それにはやはりもっと手を動かさないとダメなんでしょうねー。ハー。

ガベージコレクションを意識してみる

AS3.0ではこれまで以上にメモリマネージメントについて注意を払う必要があるそうです。そんなわけでMoock先生のEssential ActionScript 3.0のChapter 14: Garbage Collectionを読んでみました。例によってよく理解できないこともあるのですが、理解できたことだけメモ。

ガベージコレクションの仕組み】

  1. Flashが実行されるとある一定量のメモリがOSによって自動的に割当てられる
  2. オブジェクトが生成される度にメモリ容量が蓄積されていく
  3. メモリの蓄積が一定量を超えると、ガベージコレクションが実行される周期が決定される
  4. 3の周期でガベージコレクションが実行され、メモリ内の不要なオブジェクトを削除する


ガベージコレクションの対象】

  • プログラム内で参照されていないオブジェクト。
  • 生成したオブジェクトを手動で削除することはできないが、参照値にnullを代入してやることによってガベージコレクションの対象とすることができる


【その他学んだこと】
ガベージコレクションの対象となっているオブジェクトも、ガベージコレクションが実行されるまでは存在し続ける。そのため、以下のような処理に留意

  1. イベントリスナーの登録解除
  2. timerやintervalの停止
  3. MovieClipの再生停止
  4. 上記の処理を外部から実行できるpublicメソッドを実装*1

こんな感じです。間違って理解している可能性も大いにあり得るので、興味がある方はMoockさんの本を実際に読んでみることをお奨めいたします。

*1:Interfaceの章を読んでたら、ネーミング慣例としてIKillableというのが挙ってました。これはつまりイベントリスナーの解除やタイマーの停止のためのpublicメソッドを実装し忘れないためのInterfaceかと思われます。頭いい!僕はIDisposableインターフェースにdiposeというメソッドを登録して使ってみようと思います。Moock先生にリスペクト。サイン貰いに行きます。

CLICK vs MOUSE_UP

InteractiveObjectのclickとmouseUpというイベントは、ドキュメントを読んでもその違いがよくわかりません。

【click】
ユーザーが InteractiveObject をポインティングデバイスのメインボタンでクリックしたときに送出されます。

【mouseUp】
ユーザーがFlash PlayerウィンドウのInteractiveObjectインスタンスの上でポインティングデバイスのボタンを解放したときに送出されます。

んー?これを読んで2つのイベントの違いが分かる人は、恐らくいないのではないでしょうか。

そんなわけで、こんなテストをしてみましょう。

var sprite:Sprite = new Sprite();
with (sprite.graphics) {
  beginFill(0x333333);
  drawRect(10, 10, 100, 25);
  endFill();
}
addChild(sprite);

sprite.addEventListener(MouseEvent.CLICK, traceEventType);
sprite.addEventListener(MouseEvent.MOUSE_UP, traceEventType);

function traceEventType(event:MouseEvent):void {
  trace(event.type);
}

まず、矩形の上でマウスをクリックすると、mouseUpとclickという2つのイベントが両方ディスパッチされるのが分かります。

では次に、矩形上ではない別の場所でマウスのボタンを押下し、そのまま矩形上にマウスポインタを移動し、そこでボタンを放してみましょう。すると今度はmouseUpというイベントのみがディスパッチされます。なるほどねー。

では、rollOverとmouseOverの違いは?rollOutとmouseOutの違いは?ということになりますが、これはもっと複雑な模様で、野中大先生のこちらの解説を読んで「むむー」と頭を捻ってみると良いかと思われます。

ここが変だよFlash CS3

AS3.0を弄り始めて1ヶ月。Flash CS3で制作しているにも関わらず、意外にも「タイムラインは使わない」という制作スタイルに落ち着きました。

僕のようなデザインのほうからFlashを始めた人間には、タイムラインを使わないという制作スタイルは、ちょっとクールに思えてしまうのです、というアホ丸出し、見栄張りまくりの理由も少なからずあるのは否定しませんが、タイムラインのあちこちにコードが記述されているよりは、外部クラスに全てのコードが書かれているほうが見通しが良いのは確かだと思います。

それに加え、トゥイーン系のモーションもTweenerflashのTweenクラスでスクリプト制御した方が、タイミングの修正などを行うのが容易だというのも大きな理由だと思います。

ただ場合によってはやはり「あぁ、メンドクセー」と思うことも多々あります。例えばテキストフィールドを生成する場合。Flash IDEならテキストツールとプロパティパネルを使えばものの数秒でできてしまうこのような処理も、クラスで生成する場合は大抵以下みたいな記述をしなければなりません。

package {
	
  import flash.display.Sprite;
  import flash.text.TextField;
  import flash.text.TextFieldAutoSize;
  import flash.text.TextFormat;
	
  public class TextTest extends Sprite {
	
    private var textfield:TextField;
		
    public function TextTest() {
      textfield = createTextField();
      addChild(textfield);
    }
	
    private function createTextField():TextField {
      var textformat:TextFormat = new TextFormat();
      with (textformat) {
        font = "_sans";
        color = 0x333333;
        size = 10;
      }
			
      var textfield = new TextField();
      with (textfield) {
        autoSize = TextFieldAutoSize.LEFT;
        selectable = false;
        defaultTextFormat = textformat;
        text = "Just a text."
      }
			
      return textfield;
    }
		
  }
	
}

確かに同じようなフォーマットのテキストならば、テキスト表示用のクラスファイルを使い回せるようにすれば作業効率も増すのでしょうが、多様なバリエーションのテキストが必要な場合はなかなかそうもいきません。正直これはしんどいです。TextFieldAutoSizeのimportし忘れなんて、これからも何百回もコンパイラに指摘されることでしょう。

Flashのテキストツールで作ったTextFieldにクラス名を割当てることができればいいのですが、ご存知の通りFlash IDEでクラス名を付けてやれるのはButtonとMovieClipだけです。テキストの表示のためだけに、MovieClipクラスを生成するのも、あまり気が進みません。*1

そもそもAS3.0になってクラス編成というのかパッケージ構成というのか分からないけれど、とにかくオブジェクの在り方がAS2.0とは全く異なるようになったのに、相も変わらず「グラフィック、ボタン、ムービークリップ」という3タイプのクラスにしかシンボル化できないというのは、どうもおかしい気がします

Flashの得意とするグラフィカルなパーツ制作を、クラスベースの制作スタイルにももっと有効に活用できればいいと思うのですが、どうでしょう?

*1:MovieClipインスタンスのリンケージ設定で、基本クラスをSpriteに変更してやることは可能なんですね。SpriteにaddChildされてない状態のTextFieldとかは作れないのかなぁ?

Blade Runner Ultimate Edition

今年は映画「Blade Runner」の25周年記念イヤー。ってことで、日本でも今月17日から新宿バルト9でファイナルカット版がハイビジョン上映されたり、DVD5枚組ボックスが発売されたりとウハウハなわけですが、なんと海外ではBluRay版やHD DVD版も発売されるとの情報をゲット。

ニートで貧乏なのにBluRayのUltimate Edition(All Regions)を速攻買ってしまった。送料込みでも¥8600くらい。Amazon.co.jpだとDVD版のUltimat Editionで¥18000以上するのに。ちなみにAmazon.comならDVD版はBluRay版よりも安い$55、送料が$11くらいだから、¥7300くらいで買えます。まぁリージョンコードが1なので、リージョンフリーのプレイヤーが必要というハードルはあるけれど、ちゃんと日本語字幕も付いてますよ。

リージョンコードといえば、Blu-rayの方は日本もリージョン1なんですね(DVDはリージョン2)。なんか政治的理由が多分にありそうな雰囲気ですが、嬉しいことですね。

さて、そんな僕なのですが、実はハイビジョンテレビもBluRayプレイヤーも持っていません。

[追記]
久しぶりにFlash意外のネタをエントリーしたら、Life is Beautifule様のエントリーでも、ブレランについて言及されているのを見つけました。これは「androidは電気羊の夢を見るか?」読みなさいって啓示かも新米。とりあえず今日はヴァンゲリスのサントラ聴いて一人悦に入ってます。

Tweener.addCaller()

以前getter/setterを使えば、TweenerflashのTweenクラスからでもprivateなプロパティをイージング操作できますよ。っていうエントリーをしたのですが、Tweenerにはちゃんとカスタム関数をイージングがアップデートするタイミングで連続して呼び出してくれるaddCaller()というメソッドがあったんですね。なーんだ。でも便利ー。

var num:uint = 0;
function addNum():void {
  trace(++num);
}
Tweener.addCaller(this, {
  onUpdate:addNum, 
  time:5, 
  transion:"easeOutQuint", 
  count:10
});

そーいえば、flashのTweenクラスにもmotionChangeイベントがあるんですねー。