JavaしかかけないおいらがiPhoneアプリをリリースするまで

今回の内容は前回よりだいぶましだぞ・・・。

の続きになります。

正直実装的にはmixiアプリ第2弾のエントリ(GWT+Flash+JavaSEとの互換レイヤでサクサク開発)が飛びぬけていると思いますが、それ以来くらいのインパクトはあると思います。


長文です。

iOS版を開発するぞ

マモノバスター2のAndroid版は無事だせました。読んでない人は上に並んでる過去のエントリを読んでみてください。
AndroidはJavaSEと同じJava言語ということで、JavaSEと互換のレイヤーを作成して、JavaSE上で開発、そのままアプリのソースは変えずにAndroid版を生成するというものでした。

やはり、Androidと並ぶプラットフォームであるiOS版もださないと片手落ちだろうと。ゲーム機と違ってAndroidiPhoneを同時に所有している人は少ないはずです。ガラケー時代もそれが理由で遊べないゲームはたくさんありましたし。

問題は開発プラットフォーム選択だけでした。

ObjectiveCは短期的に習得できる状態ではなく、Unityは自分との相性は最悪です。cocos2d-xは触るならver3かなぁ、ver2は触りたくないなぁということで、なかなかいいのがありません。

そこで、思い出します。急激に成長をしているiOS向けの開発環境を。

RoboVM、君に決めた!

そう、RoboVMです。
http://www.robovm.org/

Javaで描いたコードがiOS向けに動きます。シミュレータ用にx86ももちろん出力できます。
パフォーマンスもかなり良好で、iPhone4s/iPod touch5(Apple A5搭載。初代miniもおそらく)でAndroidの現行のハイエンド並のなめらかさ。ただし、負荷が高い部分では差が出ますが、60fpsが安定して出たりします。

RoboVMのいいところはGWTと違い、ソースコードからのジェネレートではなく、コンパイルしたあとのclassファイルから生成されるという点です。したがってjarファイルの既存のライブラリをRoboVMに食わせるとそのまま動きます。びびるくらい動きます。

RoboVMのサンプルコードを書いてみましょう。iOSの開発者は多分、これが何をしているかすぐにわかると思います。

UIButton button = new UIButton(new CGRect(0, 0, 160, 50));

button.setTitle("ぼたん", UIControlState.Normal);
button.setBackgroundColor(UIColor.colorDarkGray());
button.addOnTouchUpInsideListener(new UIControl.OnTouchUpInsideListener() {
  @Override
  public void onTouchUpInside(UIControl uic, UIEvent uie) {
    System.out.println("くりっくした!");
  }
});
window.addSubview(button);

JavaIDEは非常に優れているため、さくさく補完だけでホイホイ進んでいけますね。

また、サポートされている範囲はGWTの比ではなく、まず問題にならないレベルでサポートされています。恐らくびっくりすると思います。

生成されたipaにjarファイルがありますが、ここにクラスファイルは一切入っていません。たんなるリソース参照用にディレクトリなどがそのままの構造で彫ってあるみたいです。便利ですね。Androidもassets使わず、自動でやってくれるといいのにね。

ちなみにあの有名なJavaFX for iPadもRoboVMを利用しています。サンプルプロジェクトを作るとわかりますが。自分が見たやつはかなり古いバージョンだったと記憶しています。


libGDX、が勝利のカギだ!

RoboVMはいいのですが、JavaSEで実行できる開発環境がなくてはいけません。いちいちシミュレータとか実機起動などたるいことはやっていられないのです。そんな環境で開発している人はいないとは思いますが。

とはいえ、クロスプラットフォームの環境を今、しかも慣れない環境で作るには限界があります。
そこで、クロスプラットフォームで有名なプロダクトに手を出します。

みなさんご存じlibGDXですね。歴史もそこそこあります。最近ぽっと出てきたわけではありません。
http://libgdx.badlogicgames.com/

libGDXはもともとWindows/Mac/Linux/Android/HTMLに対応しています。
iOSも以前はXamarin経由で出力できていたのですが、お金が勿論かかりますし、パフォーマンスもよいとは言えませんでした。

それが去年の夏くらいからRoboVMに対応していきました。こちらも恐ろしいスピードで。昨年末には十分使い物になる感じでした。これでいきます。


libGDXはゲームエンジン統合開発環境とかいった御大層なものではなく、ただのフレームワーク、ライブラリです。Jarファイル(や環境によってはsoファイル)を配備するだけで環境が整います。クロスプラットフォーム系でこれほど簡単に開発環境が整うのも珍しいと思います。JavaSE版はjarを4ついれるだけの超簡単なものですので試してみてもよいでしょう。AndroidiOS版(RoboVM)もほんの少しのファイルをクラスパスに入れるだけです。


普段はこのようにJavaSEでそのまま動くので、コードを修正したら一瞬でアプリ起動でさくさく動作確認。
http://shinsan.s3.amazonaws.com/diary/2014/0520-01.png
トライアンドエラーがやりやすいので便利ですね。


HTML5出力というのはGWTを利用しているようです。細かく動かして確認したわけではないのですが、GWTはそれなりに長く追っていたので使い勝手はわかっているため、大体想像はできます。PC向けでWebで出したいのなら少しはありかもしれません。ただし、言語的にRoboVMやAndroidのように気軽にJavaSEという感覚で使えるほどサポートされていませんので、HTML5版を含めて完全にクロスで出力できるとは思わないほうがいいでしょう。

バージョンについて

RoboVM、libGDXともに活発なのでどんどんバージョンアップしていきます。

まずは安定バージョンで開発しました。

当時の安定板はlibGDXが0.9.9、RoboVMが0.0.9でした。Xcodeは5.0です。


ナイトリーでは便利な機能がどんどん追加されていくのがわかっていましたが、互換性も失うところもありました。そのため、リリース間近までこのまま開発していきます。

libGDXの次の正式版が出ました。しかし、ぎりぎりまでひっぱります。開発がほぼ終わった段階で移行しました。1.0.0です。それに合わせて対応しているRoboVMもあげました。0.0.11です。Xcodeは5.1です。

このバージョンに上げることによる変更点は自分はメソッド名が多少変更したという程度ですみました。が、OpenGL ESのデフォルトバージョンが1から2に変更になり、従来は設定で2がつかえたのが今は設定で3が使えるようになりました。OpenGLのコードをがりがり書いていた場合は致命傷でしたが、中/高レベルAPIを利用していたため助かりました。

RoboVMもバージョンが変わることによって大幅に変わっています。iOSへのアクセスするクラスのパッケージがごっそりかわっていました。ですが、このへんからObjectiveCのライブラリ呼び出すブリッジが非常に簡単に扱えるようになり、iOSAPIサポートも加速していきます。

BROという仕組みなのですが、Javaのコードにアノテーションを付けることによってObjectiveCの呼び出しにマッピングします。ドキュメントが追い付いていないのでバインディングプロジェクトを参考にするとよいでしょう。


で、1.0.0に差し替えて動作を確認した翌日に1.0.1がでました。対応するRoboVMも0.0.12にあがっています。こちらも差し替えましたが、コードの修正はありませんでした。それなりに機能が増えているのも確認しました。




libGDXはプロジェクトをセットアップするツールがついているのが伝統ですが、0.0.9まではEclipseプロジェクトベース、1.0.0以降はGradleベースです。これらはRoboVMのセットアップもしてくれますので(特に後者)試してみたいと思った人はすぐに試すことができます。

NetBeansでJavaSE環境でのGradleはあまりよくないため(Mavenとかと同じ。JavaEEなどのコンテナ系だと気にならないが)、おそらく真面目に開発しようと思うならrobovmコマンドをたたいた方がわかりやすくはるかに幸せになれるかと思います。AndroidやJavaSE版もAntのほうがおそらくよいでしょう。


macNetBeans上からビルド、シミュレータを起動可能。実機やIPA作成も。デフォルトのセットアッププログラムで生成したものをベースにGradle利用している例。
http://shinsan.s3.amazonaws.com/diary/2014/0520-02.png



ちなみに、Android版はすでにリリース済みのため、このRoboVM + libGDXではiOS版のみ出力しています。もちろん、開発はJavaSEで行っていますので、Windows/Mac/Linux上でもそのまま動きますし、出力しようと思えばAndroidもすぐにはだせます。

libGDXのバランスの良さ

アプリを書くのはlibGDXであって、RoboVMかどうかは全く意識しません。
libGDXは単なるライブラリのため、すきなように利用できるのもポイントです。

GLを取得してそのままガリガリ低レベルに書くこともできるし、高レベルの2Dのシーングラフ、ウィジェットAPIもあります。その一部の高レベルAPIであるノード部分の描画だけを低レベルなGL直で処理してもいいですし、中レベルAPI?(勝手に命名ウィジェットとGL直の間)で描画することもできます。中レベルAPIはラッピングをしていて、GLを知らずに基本的な描画が可能です。たとえば中レベルAPIのTextureクラスもGLのテクスチャIDをダイレクトに取得可能にしてあるあたり、ボトルネックができたら逃げる道がある、という考え方なのでしょう。

こういった柔軟なことができるバランスの良さが広く支持されている理由だと思います。

あ、そういやなぜか日本だけ知名度ないですね。トレンドみるとcocos2d系は中国韓国(大きく離れてアジア)だけ突出しているっぽい(というか中国が多すぎてなんでも圧倒するけど)のに対して、libGDXはエリアが割とばらけていてアメリカやヨーロッパが多い感じですね。


個人的にはシーングラフを利用しつつ、高レベルコンポーネントの使用をほとんどしない、というのが一番良いと思っています。拡張はいくらでも可能なので、思い切って利用するActor(シーングラフのノードの基本単位)を大きく絞るとよいでしょう。

個人的なベストはベースとなるクラスのActorのほかは以下の3種類のみに絞ることだと思います。

  • Group系(Actorを載せる他のAPIでいうPanel系)
  • ScrollPane
  • Image(癖があると思うのでActorを継承して自前でテクスチャを描画したほうがわかりやすい可能性も大)

言語化とかスタイルとか闇がありそうなそのへんに振り回されないもの、という意味で。ゲーム用途ならこれで十分でしょう。


とりあえず、8bit時代のBASICとか16bit時代のC言語とかでガリガリゲーム作れた、ソースコードを打ち込んだことがある、という人はlibGDXを利用すれば簡単に当時の感覚でゲームが作れますよ。それもiOSAndroidMacWindowsLinuxで60fpsでさくっと動かせるものが。基本的にOpenGLとかは知る必要はありません。


自分がどれだけlibGDXに惚れこんでいるかといえば、スマホ向けに出力する予定が全くない、PCでのみ動けばよいアプリを開発する場合もlibGDXを採用するだろう、といえばわかるでしょうか。


今回は移植という形でしたが(それでもロジック部分は同じJava言語のため6割はもってこれてる)、次からは最初からAndroidiOSを同時にリリースするつもりで作っていきます。