絶賛公開中の月面着陸ゲーム。今回は技術寄りの話を少々。といってもまあ私が語れることはとても少ないんだけど。
あれこれ悩んだ所なんかを書いてみようかな。ゲームを作ってる人はちょっとだけ参考になるかもしれない。
今回のゲーム作成に使用したのは以下のアプリケーションやライブラリ。いつもと同じですな。
Adobe Flash Professional CS6
おなじみFlashを編集しコンパイルするためのアプリケーション。
Starling 1.3
FlashのActionScriptからGPUを簡単に使うための2Dライブラリ。
Box2dFlashAS3 2.1a
二次元の物理演算を行うためのライブラリ。Flash用。
Flash Pro CS6は、タイムラインとかまったく使ってない。ステージは常に空っぽ。なのでFlash Developのほうが楽な気もするけど、画像やサウンドの管理用と、スマートフォンのエミュレータによるデバッグが楽なのでこちらを使ってます。本当は高かったから無理やり使ってます。高かったです。ええ。高かった。高かかかっ!
Starlingは、3D表示用の仕組みを使って2Dの画像を高速に表示するためのライブラリ。ちょっとややこしいか。
スマートフォンなんかは画像を描くのがとても遅い。その代わり、3Dキャラの表示は専用のGPUが処理してくれるため高速。そこで平面ゲームでも立体の看板を表示し、そこに2Dの画像を貼り付けて動かそうよ、速いよってことで登場したのがこうしたライブラリ。
デスクトップではそれほど重要じゃないけど、スマートフォンでは必須の技術なので知らない人は覚えましょう。SpriteにCacheAsBitmapとかCacheAsBitmapMatrixとかを使う時代はそのうち終わります。先にFlashが終わるかもしれないけど。
Box2dは説明不要かな。この手のライブラリとしてはかなり歴史がある。仕様がコロコロと変わったんで使ってる人が激減したという噂も。良い子はNapeを使ってるんだってー。えー、そんなー。この程度で使いやすいとか使いにくいなんて言ってたら戦争には勝てんぞヒヨッコども!
ActionScriptでハマったところ
StarlingでGPUを使って描画するSpriteと、FlashのSpriteは混在できない。ここ大切。奥がStarlingレイヤーで手前がFlashレイヤー。それぞれのオブジェクトはそれぞれのレイヤーの下に。エロイカのものはエロイカの元に。
おそらくStarlingだけで済ませてほしいのか、クラスが同じ名前になってたりして非常に面倒くさかった。たとえばSpriteはどっちもSpriteなんで、flash.display.Spriteなのかstarling.display.Spriteなのかハッキリさせないといけない。ユリーシャなのか森雪なのかみたいな。
いやStarlingだけで作れるならいいんだけど、そうはいかないわけですよ。Sprite.graphicsにdrawRectしたい場合だってあるし。なのでどっちをメインにするか決めて、他方をフルネームで呼ぶみたいな事をやらなきゃいかんのです。面倒だ。タッチイベントの扱いも違うから面倒だ。ああ面倒だ。
しかしもっと問題だったのが、画面のスケーリング。あれ、この話、前に書いたっけ?
たとえばFlashの場合、全画面表示にしたいときは
stage.scaleMode =StageScaleMode.SHOW_ALL;
と書くわけです。これで設計時のサイズを実機上の画面へ縦横比を維持して拡大してくれる。ベクター形式で描いた画像なら綺麗に拡大表示される。で、以前のStarlingはこのへんの対応に難があって、ちょっと工夫が必要だった。ワンダーリング2とか円盤と背景がずれたりして大変だったのだよ。
そんな苦労を知ってか知らずかStarling 1.3の新機能に、この全画面表示対応ってのがあって楽しみにしてたんですが、結果は芳しくない。いや、たしかにStarlingのSpriteは拡大してくれて画面ピッタリに収まるんですが、今度はFlashのSpriteがNO_SCALEで表示されちゃう。後からSHOW_ALLに変更しても表示がおかしい。困った。
なので、仕方なくStarling初期化前に
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
mywidth = stage.stageWidth;
myheight = stage.stageHeight;
として実機の画面サイズを調べ、設計時のレクタングルがピッタリと中央に収まる縮尺と座標をゴチャゴチャと計算し、新規にFlashのSpriteを生成してxやyやscaleXやscaleYに突っ込み、stageにaddChildして使ってるわけです。FlashのSpriteは全部これの子供にすれば、ああ面倒くさい。もう誰も読んでないだろこれ。
何か良い方法があるんだろうか。私は知らない。誰か知ってたら教えて下さい。いや、悔しいから教えないで。
ネイティブに対応する
一つのコードでデスクトップもモバイルもなんて。嘘つけー!
いやよくは知らないけどね。知らないけど、Android向けに作るとしたら色々と対応しないといけない事がある。たとえば「戻るキー」なんかをどうするか。
var app:NativeApplication = NativeApplication.nativeApplication;
app.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDownHandler);
みたいにして、Keyboard.BACKをひっかけたりするわけです。
ま、そのくらいなら普通なんだけど、Event.DEACTIVATE(アプリがバックグラウンドに移動した)とかはどうするのか。BGMとかは止めないといけないし、復帰したら鳴らさないといけない。
いや実はもっと深刻な問題があって、そもそも終了はどうするのか。Google先生は終了コマンドの廃止を主張しておられる。でもさあ、ゲームごときがメモリー上にドカンと居座って、名前を呼ばれるまで退場しないってのもユーザーフレンドリーじゃないでしょ。
というわけで、NativeApplication.nativeApplication.exit()もキチンと対応するわけです。こういうのはデスクトップではやらないよね。
試したかったけどできなかった事
サブマリンというエレメカがありまして。こいつの爆発シーンは
—-引用開始—-
オレンジ色の半透明プラスチックによってコンタクトレンズのような形状を作っておき、中途半端に水を入れ、命中時はそれを揺らしながら光を当て、オレンジ色の火のゆらぎを表現
—-引用終了—-
してたんだそうです。お椀みたいなのでやってたんだっけ?で、こいつを再現したいなと思ってはいた。いたんですよ。perlinNoise()で雲みたいな画像を作って、グレースケールにオレンジ色から赤色をpaletteMap()して、円でマスクして、drawTriangle()で歪ませる。いける!
と思ったけどあんまり綺麗にならないし大人の事情もあって却下。また別のところでやってみよう。そうしよう。たんしよう。
でもね。Flashは次のccというバージョンからギアスが使えるようになってぼくはブリタニアをぶっ壊すと言ってるんですよ。言ってません。64bitオンリーになるらしい。なので私はハブられるんだな。OSが32bitだから。デスクトップ用のOSで、これ以上マイクロソフトに投資するのも嫌なんだよねえ。どうしたもんかね。Flashもこちらの要望とかけ離れたものしか出してこないしねえ。やっぱUnity?というわけで要望を並べてオシマイにしとくか。
Flashへの要望など
AIRのランタイムを小さくしなさい!
デカすぎる。せめて、必要な機能だけをコンパイルしてリンクするオプションをつけてよ!
AIRの初期化時間を短くしなさい!
遅すぎる。せめて初期化中にスプラッシュ画面が出せるようなオプションをFlashにも付けて!
Starling的なモノをネイティブに!
Spriteとの連携がとれてないからなんとかして!面倒!
Box2d的なモノをネイティブに!
処理が遅いし仕様が変わるし、なんとかしてー。
ゲーム作り的にはガベージコレクションを何とかしてほしいけど、それはまあ贅沢か。なんにせよ、スマートフォン向けアプリ作成ミドルウェアとしてFlashはいい線いってたのに、最近のAdobeは何だか残念な感じでいっぱい。あれこれ発表になった「まるで魔法のような機能」は手品で終わるんじゃないかと危惧しているんだけど、そんなことない?じゃ、また。
[…] 月面着陸ゲームの(少しだけ)技術寄りの解説 « ど~でもインスタンス […]