Go言語でゲームを作る

この記事は、[株式会社ACCESS Advent Calendar 2017](https://qiita.com/advent-calendar/2017/access) 25日目の記事です。
どうも、Go言語大好き @pankona です。

12月25日、世の中クリスマスですけれどもね、皆様いかがお過ごしでしょうか。
何はともあれ、メリークリスマス！

さて、あまり技術的な内容ではないのですが、本日はGo言語でゲーム作って投稿した話を書きます。

# 長い話を短くすると

* gomobile というツールを使ってモバイル向け/PC向けにゲームを作ったよ。`gomobile build` というコマンド便利だよ。
* でも数多の罠があるから気をつけてね。主要な罠を紹介するよ。
* 曲りなりにも作品を完成させて提出するっていうのは自信になるよ！

では、以下、つらつらと書いてみます。

# 事の発端 - Gopher Game Jam

先日 (といってももう数カ月前ですが)、Gopher Game Jam という催しが itch.io というウェブサイトにて行われておりました。
[Gopher Game Jam - https://itch.io/jam/gopher-jam](https://itch.io/jam/gopher-jam)

これは平たく言えば「Go言語でゲームを作って応募してくれよな」という主旨の企画で、これを見た私は「なるほど面白そうやんやってみよかな」と思って軽い気持ちで参加を決意したのでありました。

レギュレーションとしては、

* 基本的にGo言語を使うこと。なお多少の多言語バインディング等はあっても良い。
* 期間は2017年4月末〜同年7月末。期間内にコードを書き始めること。
* ターゲットのプラットフォームは問わない。
* ソースとビルド手順を示すこと。
* 5分以上遊べること。

等が書かれていたような気がしました。
しかしまああまり細かいことは気にしていない様子で、どしどし応募してくれよな、みたいな感じでした。

# 簡単な gomobile の紹介

さて、私はかねてより gomobile というツールに興味を持って色々いじくっておりましのたで、やはりこの催しにも gomobile を用いて参加することにしました。

gomobile というのは Go のサブプロジェクトで、Go言語を使ってモバイルアプリ (Android/iOS向け) を作ろう、という主旨の元、色々モバイルアプリを作るにあたって便利な機能を提供してくれるツールです。
[gomobile の github repository - https://github.com/golang/mobile](https://github.com/golang/mobile)

gomobile 自体は数年にわたって開発が進められており、Google 検索するとそこそこ紹介資料が出てきたりします。gomobile の詳細についてはそれらの資料にゆずりますが、ちょっとだけ、`gomobile build` というコマンドについて本記事で軽く紹介しておきます。

# `gomobile build` コマンドでいきなり APK を吐き出せる

gomobile というツールのサブコマンドのひとつに `build` というのがあり、これがなかなか凄くて Go で書いたソースをいきなり APK にまで変換しちゃうという、ひたすら Go だけ書いていたい私のような人間には胸の熱くなる機能です (その実体としては NDK Build で作る Native Activity みたいなやつになります) 。
基本的には OpenGL を触るための API を駆使して、ひたすら絵を描画していくというスタイルでアプリを書いていきます。

# `gomobile build` でゲームを作るメリット

## PC版でデバッグ

実は `gomobile build` とやってビルドするところを、 `go build` として普段 Go のアプリを作る時みたいにビルドしてすると、PC版で動くアプリが生成されます。PC版が出せると、実機上で動かすのに比べてデバッグが捗るのはお察しいただけるところかと思います。
私はこの度、基本的にPC版にて作っておいて、概ね出来たら実機にデプロイして動作を確認する、という手法で開発を進めまして、まあまあ上手いこと進められたかな、と思っています。[^1]


# `gomobile build` でゲームを作るときの難点

さて早々にメリットが枯渇したところで、ここから難点というかハマりどころを書いてみます。
もしかしたらこれから `gomobile build` でアプリやらゲームやら作ろうって方がいるかもしれないので、もしかしてそういった方々の参考になれば幸いです。

ちなみに、私が iPhone を保持していないこともあり、Android 端末 (とPC版) を開発のターゲットとしていました。以下、Android 向けに開発を行う際のハマり事です。

## Android SDK の機能に (基本的に) 触れない

Go だけで書けるってところと、クロスプラットフォームだってところでしょうがないとは思いますが、
基本的に Android SDK の機能には触れません ([cgoを用いて JNI 経由で無理やり触ることは出来る](https://gist.github.com/tenntenn/0751c856ee363182ba76))。

だとすると何が困るかっていうと、

* インテント発行できない
* トーストみたいなものも出せない
* 他のアプリへの遷移もできない
* 広告貼っといて触ったらウェブページに飛ぶとかも難しい

さっそくゲームとして体を保つのが厳しい感じかもしれませんが、とはいえ私は戦いを続けました。

## アイコン設定できない

実は最近 ([2017年10月のコミット](https://github.com/golang/mobile/commit/eed0461ac20d1917743d85020c404459a7130c91)) 解消されました！ (Android版限定ですが)

そう、ゲームジャム開催当時はアイコンの設定をするための機能がなく、実質、緑のドロイド君 (つまりデフォルトのアイコン) を用いることを強いられていました。
一応、出来た APK を一回開けて、アイコンねじこんで、閉じて、サインしなおす、という手順でアイコンを設定できないことはなかったのですが、ちょっと…。

## キーボード出せない

Android SDK の機能に触れないのと関連しますが、キーボードが出せません。
そもそも入力フィールドとかそういうものも OpenGL で自前で頑張って描くことになるので色々厳しいですが、キーを入力してもらいたかったら、やはりこれも自作ソフトウェアキーボードっていうことになりそうですね。キツイ。

## 生々しい OpenGL の API

絵を出すためにアフィン変換っていうのを知る必要がありますが、残念なことに私は今までそのアフィン何とかっていうのを習ったことがなかったため、単純に絵を指定の位置に指定の大きさと回転具合で出すっていうのだけで割とそり立つ壁でした。知っている人ならここは簡単なのかもしれません。
Go らしいと言ったらそうかもしれませんが、何か絵を出すために便利ライブラリが生えているなんてことはありません。頑張るしか。

## 文字出すの大変

指定の文言を画面に出すにはどうしたら良いかというと、「文字列を画像に変換する」というような処理を経て画面に描画していくことになります。tour-of-go にも登場する image パッケージ、あれを使います。`DrawString` みたいなの欲しくなりますが、ないです。

## 音を鳴らすのが大変

`gomobile` はデフォルトでは音の再生をサポートしておらず、一応、gomobile 初期化時のオプション指定で有効にすることができます。
オプション指定で有効にしようとすると、gomobile は OpenAL のソースを取得、クロスコンパイルまで自動で行おうとしてくれるようなのですが、私の環境ではビルドが通らなかったし一日頑張っても問題解決もできなかったですね…。ぐぬぬ…。

# 工夫した点 (gomo-simra)

つらつらとツライ点を並べましたがもう大丈夫、ちゃんと上記のツライ点をカバーするためのライブラリを作ってみました。その名も gomo-simra です。手前味噌です。スターください！！！！
[GOMObile SIMple wRApper - https://github.com/pankona/gomo-simra](https://github.com/pankona/gomo-simra)

ゲームライブラリというと大げさですが、以下のような部分をサポートしています。

* 指定の絵を指定の場所に指定の大きさで出す
* 音を鳴らす
* テキストの描画
* 絵がクリックされたときにコールバックする
* FPSベースでのタイマー機能
* 端末の画面サイズに合わせて自動的に縮尺
* 簡易アニメーション (パラパラ漫画的なのをループさせる機能)

音の再生に関しては OpenAL の利用を諦め、[go-mp3](https://github.com/hajimehoshi/go-mp3) を使うことにしました。驚くほど簡単に音がでました。はい。

# 出来上がったもの (phantomize)

さて最後になりましたが、作ったものは以下です。
[phantomize (GitHub のリポジトリ) - https://github.com/pankona/phantomize](https://github.com/pankona/phantomize)
[kokeshi-scramble (itch.io でホスティング) - https://pankona.itch.io/kokeshi-scramble](https://pankona.itch.io/kokeshi-scramble)

![1501471350217.png](https://qiita-image-store.s3.amazonaws.com/0/36552/4a72e66b-c232-7160-e1aa-c37a461444ea.png)

こけしスクランブル！

* タワーディフェンス的なゲーム。全 1 ステージ (今後追加予定)。
* プレイヤーの操作はひたすらユニットを配置するだけ。
* ユニット配置にはコスト(お金)が掛かる。敵は自動で沸いてきてユニットは勝手に戦う。敵倒すとちょっとお金もらえる、みたいな。
* 本当は美少女キャラを登用する予定だったが絵心の関係でコケシに変更した。

以下から Linux版、Mac版をダウンロードして試せます (v0.6)。よかったらお試しあれ！
※ 申し訳ないことに Android 版にバグが見つかっているため、現状では Linux/Mac (64bit) 向けです…。
※ それなりに音が出ます！もし試されるときは注意してください！
[phantomize Release v0.6 - https://github.com/pankona/phantomize/releases/tag/v0.6](https://github.com/pankona/phantomize/releases/tag/v0.6)

* Gopher Game Jam では、2 位を獲得しました！[^2]


# まとめ

* 色々困難なこともありつつ、一応ゲームらしい (?) ものを完成させて提出できたというのは個人的には大きかった。完成させるの大事。
* `gomobile build` でも、ある程度慣れればちゃんとゲーム作れそうな感触ではあった。むしろ快適な一面も多い。
* gomobile でゲームは作れる！

それでは皆様、良いお年を！

[^1]: ええ、とはいえ PC で動いたからって実機で素直に動くわけなかったので、ここは最初からもう少しこまめに実機で確認しとくべきだったという反省もあります。
[^2]: 応募総数は 4 作品でした…