Adobe MAX の季節も終わり、FlashPlayer 11 も無事リリースされた。FlashPlayer 11 の目玉機能と言えば、なんと言っても、強化された 3D 機能である Stage3D だろう。Flash との付き合いも 10 年を超えたおじちゃんはこの API にひとこと物申したい。
10.2 から追加された StageVideo もそうなのだけど、Stage3D は、DisplayObject ツリー上に自由に追加削除して表示できるものではなく、ステージ上の決められた領域だけに描画出来る、その代わり速かったり高機能だったりするよ。ってものだ。そして、提供される API はかなり低レベルなものばかりだ。僕はこれを「DisplayObject ツリーから外れた API」(良い略称募集中) と呼んでいる。
僕は、Flash の良さは、DisplayObject ツリーとそれにまつわる高レベルな API にあると思っている。DisplayObject ツリーはとても良く出来ていて、描画や入力やイベントなどの面倒な部分をかなりの割合で担ってくれている。この辺りは DirectX や OpenGL で自分で 2D ゲームエンジンを作ってみる (或いは作る事を想像してみる…) と良く分かるもので、正直マトモにやると面倒過ぎて俺はいつになったらゲームが作れるんだ…状態になる。あとは iPhone で cocos2d を触ってみて、微妙な融通の利かなさにやきもきしてみるとか。その点、FlashPlayer の API は、とりあえず数行書けば画面にモノを出して動かす事が出来る程度には高レベルで、規模が大きくなってきてもそこまでは不自由しない程度には充実しているという、良いバランスを保っている。ユーザーとのインタラクションがあり、動きがあるものを作る上で、ラピッドに手を動かせる数少ない環境の一つであるのは間違いないと思う。
その点で、「DisplayObject ツリーから外れた API」が増加しつつあるのは、個人的にかなり不安を煽る要素だ。なんせ、「DisplayObject で使えるノウハウはほとんど通用しません」と宣告されているようなものだからだ。それって Flash でやる意味あるのかなー?と思ってしまう要因の一つだ。Adobe さんは「ゲーム開発も格段に凄くなりますよ!」みたいなこと言ってるけど、「ゲーム開発のことしか考えてないんじゃないの?」と思ってしまう。「そういうもんです」と言われればそれまでなのだけれど、3D ゲーム開発にさほど興味が無い自分にとっては、全く表現の幅が広がった気がしない。「Stage3D は 2D も高速になるから表現の幅広がるでしょ!」と言う人も居るだろうけれど、DisplayObject から外れている時点で、うまく使わないと相当な茨の道になるだろうな〜ということが予想出来る。レンダリング結果を BitmapData に転写する機能はあるようなので、それを使ってうまく DisplayObject にはめ込む系のノウハウなんかが、今後もてはやされそうな気がする。
話が少し逸れたけれども、今後この調子で、出来ることが増えるからといって安易に過去の API のメリットを捨てた API が増え続けると、最終的には何をするにも面倒で中途半端・ネイティブコードでやった方がいいじゃん、な状態の何か Flash だったらしきものだけが残りそうで心配なのだ。もちろん杞憂だったらいいのだけれども。ビルトインクラスだけでなく、ライブラリやフレームワークも Adobe がきちんと開発やサポートをするということも織り込み済みなのであれば、是非ともそちらも頑張ってもらいたい。最近は Unity や UnrealEngine から Flash への書き出しなんて話もあるようだけれども、ミドルウェアからの書き出しが主流になり、単なるプレイヤーに成り下がってしまったら本当に Flash はオワコンですな…。
気がつけば5ヶ月ぐらいブログ更新してなかったんですね。しかも最後が XCode の記事…。管理画面へのログイン方法も半分忘れてました。…そんな残暑と世間の目が厳しい今日この頃ですが皆さんいかがお過ごしでしょうか?
「新藤さんはいつも何してるのか良く分からない。そもそも仕事してるの?」とか「ニコゲーあっという間に終わり過ぎ」とか「TOUCH WOOD より INFOBAR の方が注目されててジェラシー」とか良く言われる、あ、最後のは僕の心の叫びですけど…、な僕ですが、今日は久々に皆さんにお知らせがあって暗闇の地底から戻って参りました。
なんと!本日!「シュヴァリエ サーガ タクティクス」のプレス発表会が行われ、クローズドベータテスターの募集が開始されました。ワーパチパチ!
…え、シュヴァ…何?と思った方のために説明させて頂くと、「シュヴァリエ サーガ タクティクス」とは、近々ハンゲームからリリースされるオンラインゲームです。内容は某オウガのような王道SRPGをベースに、攻城戦や協力プレイ、オフラインの間にも遊べる遠征といった要素を盛り込んだ本格的なものとなっています。開発は、ハンゲームを運営するNHN Japanと、数々の家庭用ゲームを手掛けてきたイメージエポックが共同で行っており、ブラウザで遊べる Flash ゲーでありながら、家庭用ゲームのクオリティを目指しているというかなり無謀な夢のあるプロジェクトとなっております。
お察しの通り、BeInteractive! はここに一人戦場の FLASHer としてアサインされ、かれこれ一年以上、この夢一杯のプロジェクト (?) を実現に向けて奮闘していたのでした。そして、いよいよ皆さんに試して頂ける段階になったので御座居〼 (なってるといいな〜)。名前が長くて覚えにくいですが、これから開発ラストスパートですので、ぜひベータテストに参加してご意見頂けると嬉しいです!
最近は70%ぐらいシュヴァリエにコミットしつつ、他には iPhone 関係のほにゃららを作っていたり、新たに面白そうなご相談を数件頂いたりしております。年末近くにはまた何かお披露目出来るかもしれません。ではまた〜。
- Cocos2d の XCode4 用テンプレート → Cocos2d Templates in XCode4?
- develop ブランチに動くヤツ上げたぜ!! by 作者
- Debug/Release ビルドの切替方法 → How can I build for release/distribution on the XCode 4.3?
- 左上の再生ボタンの二個隣のドロップダウンの "Edit scheme..." で変更可能な模様
- そもそも開発用の実行 (Run Hoge.app) と配布用のビルド (Archive) が分かれたので、Debug/Release を切り替える必要なくね??って思想っぽい気がする
- XCode4 導入まとめ (Apple 公式) → XCode 4 Transition Guide: Orientation to XCode 4
- 読むのめんどいけど一通り読んでおけば間違い無さそう
- デフォルトで挿入される Copyright がイラッとする → Define __MyCompanyName__ in XCode per project?
- XCode4 では PBXCustomTemplateMacroDefinitions の値よりも Address Book.app のカレントユーザのカードの値を優先して使用するからそれを変えろ
- AdHoc ビルドのやり方 → iPhone ad hoc build using Xcode 4
- ドロップダウンからシミュレータではなくデバイスを選んだ上で、[Pdocut] -> [Archive]。Organizer を開き (ビルドが終わると自動で開くっぽいけど念のため) 、Archives タブで今ビルドしたアプリを選び、[Share...] を押す。[iOS App Store Package] を選んで、Identity は予めインストールしておいた AdHoc 用のプロビジョニングプロファイルを選べば OK
いやしかし、XCode 4 は足し算足し算でデザインされてる感じが結構するんだけど、どうなんだろう…。ごちゃごちゃ感が凄い。
東北地方太平洋沖地震に伴い、復興支援になるか分かりませんが、少しでも助けになればと思い、子供ウケにも定評がある JellyPics と、快眠の助けになるかもしれない…というよりは、iPhone を傾けてもらって延々流れ続ける羊を見て「アホなアプリだなぁ」と思ってもらえればこれ幸いな IntinifySheep を無料化しました。不安な日々が続くと思いますが、少しでも笑顔が戻ればと思います。
なお、手順が公表され次第、BeInteractive! からも ¥100,000 ほど日本赤十字社に寄付をしようと思います。FAQ にもある通り、日本赤十字社に寄付をした場合、所得税控除の対象となるようですので、僕のようなフリーランサーの皆さんはこちらで寄付をされてはいかがでしょうか。
また、今回の災害で被害を受けた地域の方々、及び申告が困難になった方々については、確定申告・納付等の期限延長措置が国税庁から発表されています。もし、知らずに心配してらっしゃる方が居ましたら教えてあげて下さい。
被災された皆様には心よりお見舞い申し上げます。
ヒノキの間伐材で作られた携帯「TOUCH WOOD」がいよいよ発売されます!SH-05C/06C に続き、TOUCH WOOD の UI についても BeInteractive! が諸々開発をお手伝いさせて頂きました。
なんと言っても特徴的なのは、UI が斜めであること。利き手に合わせて斜めの向きを変えることも出来ます。更に自分の好きなように分割してカスタマイズ可能なメニューが加わり、キュートな木のボディと相まって、かなり素敵な感じに仕上がっております。以下のサイトでちょこっと見ることができます。
公式サイトにも書いてありますが、UI はハイジ・インターフェイス株式会社/株式会社ライトニングの美馬さんプロデュース。デザインは原口航さんで、お二人のステキ UI デザイン・グラフィックデザインを最大限生かせるよう、ライブラリ・フレームワークの整備からナナメ & 分割 UI、編集モードの実装・演出などなど鼻血を出しながら尽力しました。
15,000台限定ですが、ぜひ手に取ってみて下さい。僕も買います!!
- Client: NTT DOCOMO, Inc
- Produce: HYGE Interface Inc.
- Direction: Naoki Mima (HYGE Interface Inc.)
- Management: Hiroshi Kamasawa (HYGE Interface Inc.)
- Design: Wataru Haraguchi
- Flash:
- UI library, Framework, Tilt UI, Edit mode: Yoshihiro Shindo (BeInteractive!)
- Call widget, Mail widget: Yusuke Nakahara (CD-IM)
- Clock and other widgets: Yuki Kawahara (HINATA Ltd.)
- Photo widget: Daisuke Kanda (Ameya)
- Test: Ichiro Shimura (HINATA Ltd.)
例えば DisplayObject をインターフェイス化したい場合:
public interface IDisplayObject
{
function get asDisplayObject():DisplayObject;
}
実装:
public class MyDisplayObject extends Sprite implements IDisplayObject
{
...
public function get asDisplayObject():DisplayObject
{
return this;
}
}
利用:
public function move(d:IDisplayObject):void
{
d.asDisplayObject.x += 10;
d.asDisplayObject.y += 10;
}
少なくとも、全プロパティとメソッドを定義し直したインターフェイスを用意するよりはスマートでお手軽だと思う。
ちなみに Google Web Toolkit の IsWidget インターフェイスがこの手法を使っててなるほどと思ったんだけど、偉い人達の間では普通に使われてるのかな?
FlashBuilder そのものには ASDoc を出力する機能はついてないけど、「Flash Builder 4 beta – exporting ASDoc documentation」のように、Eclipse の「外部ツールの構成」機能を使って外部ツールとして登録してしまえば、開いているプロジェクトに対してお手軽に ASDoc コマンドを実行出来るようになる。
…ただ、日本語環境だと、コンソールへの出力が化けてて、エラーが起きた時に何がなんだか分かりにくい。池田さんの記事を見ても化けてる (こっちは Ant 使用だけど) ので、たぶんみんな化けてるんだと思う (ただし OSX だけかもしれない)。
なぜ化けるかというと、ASDoc は SHIFT-JIS を Microsoft が独自に拡張した CP932 (MS932 とも言うらしい) という文字コードで出力しているところを、UTF-8 とか全然違う文字コードで表示しようとしているからだ。
幸い、先ほどの「外部ツールの構成」には「共通」タブの「コンソール・エンコーディング」という場所に、コンソールへの出力文字コードを指定出来る部分がある。…が、しかし!!MS932 が存在しない。ここが最大の罠。
実は、プロジェクトやワークスペースの文字コードとして一度 MS932 を指定しないと選べないらしい (リンク先 4 番参照)。というわけで、一度プロジェクトのプロパティを開いて、「リソース」の「テキスト・ファイル・エンコード」で「MS932」を手動で入力して「OK」、その後また UTF-8 に戻すと、無事「外部ツールの構成」でも「MS932」が選べるようになり、ASDoc のログも文字化けしなくなった。めでたしめでたし。
分かりにくいよ!!
dispose() とか unload() とかってあるじゃん。そうそう、アレだよアレ。BitmapData とか Loader とかに用意されてる、破棄することを目的としたメソッドね。これをちゃんと呼ばないとメモリリークする—ってのは半分嘘で、実際には GC 対象になったうえで GC が発動すればきちんとメモリは開放されるんだけれども、GC が発動する頻度が高くないので巨大なリソースなんかを使った場合にはいつまでもメモリを占有し続けることがあって問題になる (たぶんね) —ので呼ばなきゃいけないんだけど、いつ呼べばいいの?って思ったこと無いですか?
いつってそりゃ、「不要になったら」ですよ。はい、この話はおしまい。…じゃなくてですね、意外とこの問題根が深い気がするんですけど、どう思いますか?というのも、「不要」ってどう判断するんでしょう?もう少し言うと、それを「誰が責任を持って」行うんでしょう?
インスタンスのスコープと寿命が短ければ、そんなに問題にはなりません。
protected function doSomething():void
{
var b:BitmapData = new BitmapData(1024, 768);
// ...
b.dispose();
}
BitmapData を生成したのは自分ですし、ここでしか使わないことも分かっています。だから自分で責任を持ってこのメソッドの終わりと終わりとともに dispose() を呼び出すことができるわけです。
ではこれが次のようになっていたらどうでしょう。
protected function doSomething():void
{
var b:BitmapData = new BitmapData(1024, 768);
var nazo:Nazo = new Nazo();
nazo.bitmapData = b;
b.dispose(); // いいの?
}
なんか見るからに得体の知れない謎クラスに BitmapData を渡してます。中がどうなってるのか良く分かりません。この状態で、dispose() を呼び出して大丈夫なんでしょうか?
もしかしたら、中身は次のような実装になってるかもしれません。
public function set bitmapData(value:BitmapData):void
{
_bitmapData = value.clone(); // 実は複製していた!
}
この場合、dispose() は呼ばないとマズい (こともある…というのは、実際 GC 任せにしていても解放されることはされるので必須ではないということ…ただ話が面倒なので今回は GC に任せず解放しないと支障が出ることにしましょう) でしょう。
はたまた、次のような実装になってるかもしれません。
public function set bitmapData(value:BitmapData):void
{
_bitmapData = value; // なんかそのまま使い続けるみたい
}
この場合、逆に dispose() を呼び出してはマズいわけです。
更にスコープが広がって、BitmapData も Nazo も自分クラスのインスタンス変数として保持されるようになると、より混乱してきます。
早速、呼び出すタイミングと責任があやふやになってきました。そんなもん、Nazo クラスに押し付けりゃいいだろ!という声もありそうですが、そのまま自分でも BitmapData を使い続けるので、Nazo クラスに勝手に解放されては困る、という場合も考えられます。お互いに好き勝手な判断で動かれては困るのです。何かしらルールを決める必要がありそうです。
恐らく、「インスタンスを生成した人が責任を持って管理する」というのが一般的な原則な気がする [要出典] んですが、BitmapData を dispose() するためには、Nazo クラスが BitmapData を使用していないことを保証しなければならないので、Nazo クラスを生成した人、つまり自分なんですけど…が、Nazo クラスにあるであろう (ないといけない) dispose() メソッドを呼ぶ必要が出てきます。このとき、自分自身がいつ、自分を作った人から、「お前もうイラネ」と言われるかも分かりませんから、自分の dispose() メソッドを公開する必要が出てきます。そうすると、自分を使う可能性があるクラスについても同様に…といった具合で dispose() メソッドがどんどん感染していき、しかも確実に呼び出す必要が出てきます。
折角 GC があるのに、なんでこんなレガシーな管理をしなきゃならないんだ…と思っちゃう訳です。できれば自動化したいんです。
だんだん Flash 特有の話になっていきますが、こういった問題が発生するのは、たいがい BitmapData とか Loader とかそういう表示に関係するオブジェクトです。例えば Sprite を継承した自前のクラスの中で BitmapData を生成して Bitmap でラップして addChild して、毎フレーム何かレンダリングする…その BitmapData いつ dispose() すんの?という感じで。個人的な体感ですが、表示系のオブジェクトの寿命はステージから削除される (すなわち REMOVED_FROM_STAGE イベントが起こる) と共に終了することが多いように思えます。ということは、ここで (ここでってのは、REMOVED_FROM_STAGE イベントハンドラの中で) 自分がそれまでに生成したリソースを dispose() すれば問題ないのでは…?
大抵の場合、これで良い気もします。ただ、例えばタブだったりスタックだったりで、一時的にオブジェクトを removeChild して、再び addChild する必要がある場合、意図せずリソースが破棄されてしまう危険があります。そいういう場合に備えて、「まだ破棄しないで!フラグ」を用意して、addChild する予定がある場合だけに、そのフラグを立てておいて removeChild すれば破棄されないとかそういう機構が必要かもしれません。仮にその宙ぶらりんな状態 (表示はされてないけど破棄もまだな状態) で、それを管理しているタブやスタックそのものが解放フェーズに入ったら、そのときに明示的に dispose() を呼び出してもらう。うーん、なんとかいけそうな気もします。ただし、宙ぶらりんさんの子として dispose() が必要なオブジェクトがいる場合、ステージから外れた瞬間に破棄されては困りますから、親の「まだ解放しないで!フラグ」の状態も見る必要がありそうです。更に、そのような子供達のために、宙ぶらりんな状態で dispose() が呼ばれた際には子の dispose() も、もれなく呼ばないといけないでしょう。作れなくはなさそうです。
ところで、上述の仕組みだと「生成した人が dispose() を呼ぶ」という原則は微妙に守れていません。自分が Sprite 派生クラスで、自分で子を new して addChild するのであれば問題ないですが、次のようにタブなりスタックなりのコンテナ、要するに他人に、生成したインスタンスを addChild するような場合は、自分 (=生成した人) ではなく、他人 (=生成してない人) に dispose() の呼び出しを任せるという結果になります。
tab.addChild(new Image('A')); // dispose の呼び出しは tab に任せた!
tab.addChild(new Image('B')); // dispose の呼び出しは tab に任せた!
tab.addChild(new Image('C')); // dispose の呼び出しは(ry
これも恐らく大抵の場合問題なくて、そしてこういう用途の方が多い気がします。tab と Image の寿命も大体一緒でしょう。仮に tab よりも長い寿命で Image を使う必要がある場合、その時だけ先ほどの「まだ破棄しないで!フラグ」を立てたうえで tab に addChild して色々して、最終的に自分で dispose() を呼び出せばいいのかなとか。本当?
次のような AbstractFactory をはじめ、インスタンスを生成してもらう系も微妙です。生成してもらった人 (=ファクトリ) にインスタンスを返して破棄してもらわなければならないのでしょうか?
addChild(imageFactory.makeImage('A'));
さすがにそれはあんまりなので、ファクトリメソッドを使う == 自分で new すると同じと見て良い気がします。
さてさて。今までは BitmapData の話でしたが、実際のところ、本当のメモリリークにつながる訳ではないので無視しても良いと言えば良いのです。本当のメモリリークにつながる危険性があるのはそうアイツ、イベントリスナーです。寿命が長いオブジェクト (例えば Flash が再生されている間は生存し続けるモデルオブジェクトとか…) にうっかり (弱参照でない) イベントリスナーを仕掛けて削除し忘れたまま放っておくと、たちまちメモリリークに繋がる訳です。Model-View の関係を保とうとするとありがちな罠です。
そういう罠にはまらないために、「イベントリスナーは弱参照 (useWeakReferene = true) ではっとけ」という宗派 (宗派ってなんだ) もあるかと思います。最近はそれでもいいかなーと思わなくもないですが、逆にうっかり GC 対象にならないよう気をつけねばなりません。例えば、次のようなゆるい書き方は御法度なります。
protected function initialize():void
{
// new したら何処かに保持しておかないと GC されちゃうヨ!
// ※ Binding クラスは中で model にイベントリスナー登録したりしていい感じに動いてくれる何か
new Binding(model, 'name', nameField, 'text');
new Binding(model, 'age', ageSlider, 'value');
}
一々、そのあと使いもしないプロパティに入れておく必要があります。
protected function initialize():void
{
_nameBinding = new Binding(model, 'name', nameField, 'text');
_ageBinding = new Binding(model, 'age', ageSlider, 'value');
}
どうでもいいですけど、Flash ビルトインの Tween クラスは本当に酷いと思います。 (アニメ再生中に GC されることがある)
それはともかく、書いていて気付きましたが、強参照 (not 弱参照) の場合でも、イベントリスナーを削除する必要があるのでプロパティには入れておかなければなりませんね。すみません。ただ、削除しなくても正しく GC 対象になると分かっている場合であればプロパティに入れずに済むというメリットはありそうです (意識しておくのが大変ですけれども)。
結局どちらにしろプロパティとして持っておく必要があるのであれば、先ほどの自動 dispose() 機能付き DisplayObject の中では、次のように、運命を共にする (あんたの dispose() が呼ばれるまでは俺達生きてるぜ!あんたの dispose() が呼ばれたら俺達の dispose() も呼んで null ってくれよな!の意) 決意を表明する仕組みがあると良いのかもしれません。
protected function initialize():void
{
// 「運命を共にする」をi英辞郎で引いたら「share the fate」だった
share(new Binding(model, 'name', nameField, 'text'));
share(new Binding(model, 'age', ageSlider, 'value'));
}
長々とふわふわした話を書きました。「そもそも、そんな共通の仕組み無理して考えなくてよくね?」と思うかもしれませんし僕もそんな気がするんですが、ある程度汎用性のあるライブラリ (BEComponents のことなんですけどね) では避けて通れない気もしたのです。
なんか良いプラクティスとかないんですかねー。

ちょうど一週間前の1月27日、満を持して SH-05C が発売になりました。SH-07B に引き続き、今回も待受 UI である「待受アクセサリ」の開発に携わらせて頂きました。以前よりも格段に進化し、フィーチャーフォンでありながらスマートフォンのような UI が搭載されています。デモ動画などはこちら。
SH-07B がそうであったように、SH-05C も「待受アクセサリ」は Flash Lite 3.1 で作られています。今回は前回よりも人数が増え、4人で開発を行ったのですが、僕は基本となるタッチ UI ライブラリの作成、分業するためのフレームワークの開発、HOME 画面の機能の実装を担当しました。AIR for Android なども出始めるなか、AS2 でタッチ UI というかなりチャレンジングかつアクロバティックなプロジェクトでしたが、SH-07B の時の経験も生かし、なんとか形にすることが出来ました。このプロジェクトを通じてタッチ UI に関するノウハウも大分溜まってきました。モックも出回ると思うので、ぜひ触ってみて下さい。
余談ですが、今後発売予定の SH-06C という機種にも同様の UI が搭載されます。SH-05C は AQUOS SHOT 端末でカメラ性能が良い一方、SH-06C はプロジェクター搭載という変わった端末です。個人的にはプロジェクターおすすめです。
- Client: Sharp Corporation
- Produce: HYGE Interface Inc.
- Direction: Naoki Mima (HYGE Interface Inc.)
- Management: Hiroshi Kamasawa (HYGE Interface Inc.)
- Design: Wataru Haraguchi
- Flash:
- UI Library, Framework, Home Screen: Yoshihiro Shindo (BeInteractive!)
- Call Screen, Mail Screen: Yusuke Nakahara (CD-IM)
- Home Screen Widgets: Yuki Kawahara (HINATA Ltd.)
- Photo Screen: Daisuke Kanda (Ameya)
- Test: Ichiro Shimura (HINATA Ltd.)
土曜日に F-site お越し下さった皆様ありがとうございました。& すみませんでした。あまりにグダグダだったので、プレゼン資料加筆してから公開します。とりあえず講演中に触れた四分木空間分割による衝突判定の URL だけ載せときます↓。



