Androidアプリにミニゲームを組み込む!Goでミニゲーム開発 Ebitengine
既にネイティブでアプリ開発をしていて、なんかミニゲーム入れたくなっちゃった時。
どんな選択肢があるのか調べていて、これやっぱ Ebitengine じゃないの!と思って楽しくなってしまった話です。
Ebitengine に関しては Zenn にも色々と紹介記事があって、すごいのだとどんなゲームが作れちゃう、とかはそちらをご覧いただくとして。。2Dの可愛いゲームが作りたければ良き選択肢のようです。
以下 Androidネイティブアプリ に対して組み込むときにたどった道筋を紹介します。
(iOS のことはわからない・・ iOSに関しては こちらの記事 が参考になる)
大まかな作業のロードマップ
- Ebitengine でゲームを作る
- mobile ターゲットにビルドする
- AndroidStudio 側のセットアップ(NDKなど)
- 初回設定(aabを配置するディレクトリの設定など)
- ビルドしたゲームの aab をAndroidプロジェクトの方のディレクトリにコピー
- Android Viewとして組み込む
やっていきましょう!
Ebitengine でゲームを作る
公式のサンプルを参考にディレクトリ構成
.
├── hello
│ └── hello.go # ゲーム部分のロジック
├── main.go # 普通にターミナルからゲームを実行するエントリポイント
├── mobile # mobileビルドを書き出すディレクトリ
│ ├── android
│ │ ├── hello-sources.jar # mobile build で出力される
│ │ └── hello.aar # mobile build で出力される
│ └── mobile.go # モバイル用のゲームを実行するエントリポイント
└── resources # あとで画像リソースを配置するためのディレクトリ
go mod init する
公式サンプルのインストール手順に従い、作業するディレクトリでモジュールを宣言
go mod init github.com/yourname/yourgame
私の場合は自分のgithub account で github.com/maripiyoko/my-first-mobile-game
を使ってみることに。(結局この記事書くのにサンプルコードアップしたのでgithub にアップしましたが、この時点では別にGithub に repository なくても別に大丈夫)
hello/hello.go (hello world のサンプル)
package hello
import (
"fmt"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
)
type Game struct{}
func (g *Game) Update() error {
return nil
}
func (g *Game) Draw(screen *ebiten.Image) {
ebitenutil.DebugPrint(screen, "Hello, World!\n")
ebitenutil.DebugPrint(screen, fmt.Sprintf("\nTPS: %0.2f", ebiten.CurrentTPS()))
}
func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
return 320, 240
}
func NewGame() (*Game, error) {
game := &Game{}
return game, nil
}
main.go
package main
import (
"log"
"github.com/hajimehoshi/ebiten/v2"
"github.com/maripiyoko/my-first-mobile-game/hello"
)
func main() {
game, err := hello.NewGame()
if err != nil {
panic(err)
}
ebiten.SetWindowSize(640, 480)
ebiten.SetWindowTitle("Hello, World!")
if err := ebiten.RunGame(game); err != nil {
log.Fatal(err)
}
}
コンソールで普通に実行する時用なので、通常の RunGame
でゲームを開始している
mobile/mobile.go
package mobile
import (
"github.com/hajimehoshi/ebiten/v2/mobile"
"github.com/maripiyoko/my-first-mobile-game/hello" // 自分が作ったモジュールの hello を読みこんでるとこ
)
func init() {
game, err := hello.NewGame()
if err != nil {
panic(err)
}
mobile.SetGame(game)
}
func Dummy() {}
ゲームスタートに mobile 用の SetGame
でゲームを開始している
(公式のモバイル対応のページ に記載があったやつ)
一旦コンソールで動くことを確認する
go mod tidy
go run main.go
mobile ターゲットにビルドする
公式記載だとこのコマンド
ebitenmobile bind -target android -javapkg your.package.name -o path/to/yourgame.aar .
Go 初心者的にはここで ebitenmobile
ないよーというエラーが出てきてかなりつまづく。。
(ebitenmobile
をローカルに正しくインストールするためにはもう少しGoのモジュール周りの知識が必要そうです・・Githubにある本体の方を指定して実行することで回避できるので一旦そちらで・・)
私の場合、以下の指定でAndroid用にビルド
go run github.com/hajimehoshi/ebiten/v2/cmd/ebitenmobile bind \
-target android \
-javapkg app.chestnuts.mobile.hello \
-o ./mobile/android/hello.aar ./mobile
-javapkg
の後に指定したパッケージ名はあとで Android 側でインポートするときに出てくるやつです。自分のドメイン名とかを入れとけばいいやつ。
./mobile/android
の下に hello.aar
, hello-sources.jar
が作成されていれば大成功です!
Android NDK セットアップ
このときに Android NDK ないよーというエラーが出たので、NDKダウンロードして入れればいいっぽい。
私の場合、AndroidStudio のJDKを使っていたので、空のAndroid project で C++ のやつとか作ればいいのでは、と思って作ってみたら色々インストールされてOKでした。
AndroidStudio で
ファイル > New... > New project > 右下の方にある Native C++
を選んでプロジェクトを作る
一旦出来上がったプロジェクトをビルドして実行しておく。
(ここで出来上がったAndroid projectをこの後ゲームの組み込みサンプルとして使おうとすると、色々いらないライブラリが入ってたりして邪魔くさいのでこいつはここでオサラバの方が良いと思います)
AndroidStudio 側のセットアップ
他の人が作ってくれたaarファイルを自分のプロジェクトで使用する方法
でこちらの記事が参考になります。
今回はこれに倣って、以下のディレクトリ構成にしました。
.
├── app
│ ├── build
│ ├── build.gradle.kts
│ ├── proguard-rules.pro
│ └── src
├── build.gradle.kts
├── gradle
│ ├── libs.versions.toml
│ └── wrapper
├── gradle.properties
├── gradlew
├── gradlew.bat
├── libs // 新規作成(ビルドしたゲームを入れるディレクトリ)
│ ├── build // ゲームを組み込んで動かしてるといつの間にかできてるやつ
│ ├── build.gradle // 新規作成(ターゲットの aar を読み込む指定を追加)
│ ├── hello-sources.jar
│ └── hello.aar
├── local.properties
└── settings.gradle.kts
ディレクトリとファイルを作る
mkdir libs
cd libs
touch build.gradle
libs/build.gradle
configurations.maybeCreate("default")
artifacts.add("default", file("hello.aar"))
作成した aar を読み込む設定を追加している
libs を外部ライブラリとして読み込む設定を追加する
settings.gradle.kts
一番下のあたり
...
include(":app")
include(":libs") // 追加する
app/build.gradle.kts にライブラリを読み込む指定を追加
app/build.gradle.kts
dependencies ブロックのところ
dependencies {
implementation(project(":libs")) // 追加する
...
}
諸々変更したので gradle sync しとく。
ビルドした aar をコピーして配置
hello.aar
, hello-sources.jar
を libs
に配置する
AndroidStudio で読みこみ
外部ライブラリとして組み込む。
このサンプルではいきなり MainActivity のなかに入れちゃってるけど、
普通の Android View として組み込めるので任意の場所に入れ込むことができるはず。
EbitenView
やるね!
MainActivity.kt
package app.chestnuts.game.firstgameapplication
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import app.chestnuts.mobile.hello.mobile.EbitenView
import go.Seq
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Seq.setContext(applicationContext)
}
private fun getEbitenView(): EbitenView {
return this.findViewById(R.id.ebitenview)
}
override fun onPause() {
super.onPause()
this.getEbitenView().suspendGame()
}
override fun onResume() {
super.onResume()
this.getEbitenView().resumeGame()
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:keepScreenOn="true"
tools:context=".MainActivity">
<app.chestnuts.mobile.hello.mobile.EbitenView
android:id="@+id/ebitenview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true" />
</RelativeLayout>
完成したゲームを起動
Hello World!
続き記事予定
ゲームっぽく画像のリソースを読み込んで、Tile map を書くところもやってみたので
次の記事に分けて書きたい。
次のはGoのゲームコードの方を修正するけど、今回指定したAndroid側の設定は変えなくて大丈夫なので良き。
誰かがゲームを開発してくれたものを自分のアプリに組み込みたい、みたいな用途で使いやすそう。
ソースコード
Ebitengin
Android
Discussion