読者です 読者をやめる 読者になる 読者になる

PATAPON(パタポン) はてなダイアリーキーワードミニゲーム

12月10日(月)から12月16日(日)までキーワードページで PSP用ゲームソフトパタポンのミニゲームを遊ぶことが出来ます。まだ遊んだことが無い方は、是非遊んでみてください:D。
自分はこのミニゲームで、キーワードの位置情報を利用したミニゲームシステムの考案からゲーム内容、レイアウト等のデザインからサーバサイドの実装まで、ほぼ最初から最後までかなり自由に作らせて貰いました。
以前からはて☆すた OPなんかでやっていた Flash を背景透過にして、ブラウザ内部に全画面表示させ、レンダリングされてる HTML コンテンツ(位置や文字情報)などをサーバサイドを通さず、直接 Flash からアクセスしてなんか作ってみたいなー、と思っていたのでそれが実現出来た感じです。結構今後 Flash 側から ExternalInterface (JS) を通してブラウザの DOM にアクセスしてあれこれ、というのが流行ってくるんじゃないかなぁ、と漠然と思ったりしてます。
今までは Blog パーツなどはあくまでサイドバー内に収まっているだけで、そこから飛び出であれこれ、というのははそんな無かったなのですが、HTML からの様々な情報を利用することで、もっと面白い試みが増えてきそうな感じです。

技術的なこと

背景透過

Flash で背景透過にするには wmode を transparent にすれば良いのですが、wmode=transparent にはいろいろな罠があります。特に全画面で背景透過は全ブラウザで挙動が違うのでそこらへんの Flash/JS を追っかける気力がないとかなり辛いです…。

  • Flash 上へのテキスト入力が変になる・入力できない
    • どうにもならないので ExternalInterface で JS を呼び出し、HTML の要素の zIndex を高く設定した要素を SWF 上に重ねて表示したりする必要が…
  • マウスホイール・キーイベントを受け取るブラウザと受け取らないブラウザがある
    • Flash にフォーカスが当たっていても、カーソルキーやホイールがブラウザのスクロールだったり、はたまた Flash へイベントが渡ったり、両方にイベントが渡ったりとなんとも素敵な感じなります
  • OSX でアニメーションさせたときの FPS ががくっと落ちる。
    • wmode=transparent にしないときに比べ三倍ぐらい重くなります。どうしようもないので最適化でカバー。
  • Opera 9.21 以降で ExternalInterface#call が使えなくなる
    • 9.21でFlashPlayerの不具合?
    • JS と連携してると致命的です。ExternalInterface#addCallback の方は使えるので、JS 側から Flash 内部の関数は呼べます。それを利用して Opera の場合は ExternalInterace#call をラップして Flash 側に JS の実行キューを溜めて、定期的に JS からキューの内容を取得して、キューが貯まってたら eval とかしてます…。

その他いろいろあったような…。

Ten.EventDispatcher

はてな製の JS ライブラリには DOM イベントライク(最初は DOM Level3 Events をほぼ実装してましたが、Ten は出来るだけ軽量に、必要な所のみを実装するというポリシーのため、現在の形になりました)な Ten.EventDispatcher というのがあります。
かなりこれが便利で、必要なときには dispatchEvent() でイベントを送り、待ち受けてるハンドラがそれを実行します。
JS 側では onEnterFrame のような一定間隔でイベントを dispatchEvent('ENTER_FRAME') を送り、フレーム毎処理を実行したり、Flash 側の初期化が終わったら ExternalInterface で dispatchEvent('SWF_LOADED') を送ったり、position fixed に対応してないブラウザでは addEventListener('FIXED', function(points) { ... } ); とか登録しておいたりと、イベントをどんどん登録・送信できて便利です。
Ten.EventDispatcher では

var ed = Ten.EventDispatcher();
ed.addEventListener('test', function() {
    alert('test');
});
ed.dispatchEvent('test'); // イベント送信

もしくは Ten.EventDispatcher#implementEventDispatcher を使い、特定オブジェクトにイベントディスパッチャを実装します。

var o = {};
o.foo = 'foo';
Ten.EventDispatcher.implementEventDispatcher(o);
o.addEventListener('ALERT_FOO', function() {
    alert(this.foo);
});
o.dispatchEvent('ALERT_FOO');

な感じで使えると思います。JS での DOM 要素以外でも使えるイベントディスパッチャの実装はかなり便利だと思うのですが、メジャーな JS ライブラリではどれも実装してない気がします。

サーバサイド

Rails + RubyAMF で。実際の所、別に AMF の必然性は感じなかったのですが使えるなら使ってみようという感じで。Rails + WebORB という組み合わせもあったのですが、WebORB では設定ファイル周りが面倒なのでさくっと使える RubyAMF で。AS3 からそのまんま Rails のコントローラとメソッド、引数を指定してリモート呼び出しが行えるのはかなり楽でした。