Go MobileでAndroidアプリ開発

12
-1

Published on

Droid Kaigi 2016で発表したものです。

Published in: Technology
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
12
On SlideShare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
0
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

Go MobileでAndroidアプリ開発

  1. 1. Go Mobileで Androidアプリ開発 2016/02/18(木) @Droid Kaigi 2016 The Go gopher was designed by Renee French. The gopher stickers was made by Takuya Ueda. Licensed under the Creative Commons 3.0 Attributions license.
  2. 2. アジェンダ ■ 自己紹介 ■ Goについて ● Goの特徴 ■ Androidアプリ開発とGo ● Goで開発ツールを作ろう ● Android上で動くツールを作ろう ■ Go Mobile ● ネイティブアプリ ● SDKアプリ ■ まとめ 2
  3. 3. 自己紹介 KLab株式会社 KLabGames事業本部 エンジニア 上田拓也 twitter: @tenntenn ■ 好きな言語 Go, JavaScript, Lua ■ 業務 モバイルオンラインゲームの開発(クライアントサイド) 主にゲームエンジンを使ったゲーム開発 Androidのコードを直接書くことは多くない 3
  4. 4. Goについて ● Goの特徴 ○ 強力でシンプルな言語設計と文法 ○ 並行プログラミング ○ 周辺ツールの充実 ○ 豊富な標準ライブラリ ○ シングルバイナリ/クロスコンパイル 4
  5. 5. Goとは? Googleが開発しているプログラミング言語 ■ 特徴 ● 強力でシンプルな言語設計と文法 ● 並行プログラミング ● 豊富な標準ライブラリ群 ● 周辺ツールの充実 ● シングルバイナリ/クロスコンパイル Goについて/Goの特徴 5
  6. 6. 強力でシンプルな言語設計と文法 Goについて/Goの特徴 ■ スクリプト言語の書きやすさ ● 冗長な記述は必要ない ■ 型のある言語の厳密さ ● 曖昧な記述はできない 6 非常に書きやすい!
  7. 7. 並行プログラム ■ ゴールーチン ● 軽量なスレッドに近いもの ● goキーワードをつけて関数呼び出し ■ チャネル ● ゴールーチン間のデータのやり取り ● 安全にデータをやり取りできる Goについて/Goの特徴 7 チャネル ゴールーチン A ゴールーチン B データ データ go f()
  8. 8. 豊富な標準ライブラリ ■ 標準ライブラリ一覧  https://golang.org/pkg/ 基本的なライブラリは標 準で揃っている Goについて/Goの特徴 8 net/http HTTPサーバなど archive, compress zipやgzipなど crypto 暗号化 encoding JSON, XML, CSVなど html/template HTMLテンプレート os, path/filepath ファイル操作など
  9. 9. 周辺ツールの充実(go tool) ■ go toolとして標準/準標準として提供 Goについて/Goの特徴 9 go build ビルドを行うコマンド go test xxxx_test.goに書かれたテスト コードの実行 go doc / godoc ドキュメント生成 gofmt / goimports コードフォーマッター golint コードチェッカー、リンター gocode コード補完
  10. 10. シングルバイナリ/クロスコンパイル ■ 環境変数のGOOSとGOARCHを指定する 開発環境とは違うOSやアーキテクチャ向けに クロスコンパイルできる # Windows(32ビット)向けにコンパイル $ GOOS=windows GOARCH=386 go build # Linux(64ビット)向けにコンパイル $ GOOS=linux GOARCH=amd64 go build シングルバイナリになるので 動作環境を用意しなくてよい go buildはコンパイルするコマンド Goについて/Goの特徴 10
  11. 11. Goを勉強するには ■ golang.org ● 公式ドキュメント類が充実 ■ コミュニティ ● Gophers Slack #japan ● Google+ Golang JP ■ Qiita ● Goタグでまとまっている ● Go言語の初心者が見ると幸せになれる場所 ■ 書籍 ● The Go Programming Language ● Go in Action Goについて/Goの特徴 11
  12. 12. Androidアプリ開発でGoは使える? Goについて/Goの特徴 ■ 特徴 ● 強力でシンプルな言語設計と文法 ● 並行プログラミング ● 豊富な標準ライブラリ群 ● go tool ● シングルバイナリ/クロスコンパイル これらの特徴が どうAndroid開発で活かせるか? 12
  13. 13. Androidアプリ開発とGo ● Goで開発ツールを作ろう ● Android上で動くツールを作ろう 13
  14. 14. Goで開発ツールを作ろう その1 簡単に画像をアップロードできて、 アプリ上から確認できるツールを作って! 非エンジニア まだAPIサーバはできていない... 専用サーバをさくっと用意できないかな... とあるアプリ開発の序盤にて... Android開発とGo/Goで開発ツールを作ろう 14 エンジニア
  15. 15. Goで開発ツールの作り方 その1 ■ 簡易コンテンツ管理システム Android開発とGo/Goで開発ツールを作ろう 15 Android端末 確認アプリ 非エンジニアのPC Go製のサーバ ● net/httpでHTTPサーバ ● html/templateでWebアプリ ● osでファイル操作 ● archive/zipで圧縮 ● imageで画像処理 開発サーバ コンテンツのアップロード コンテンツのダウンロード 開発サーバにコンパイルして バイナリを置き実行するだけ
  16. 16. net/httpパッケージを使おう ■ 簡単にHTTPサーバを作れる(コード) func main() { http.HandleFunc("/hello", hello) http.ListenAndServe(":8080", nil) } func hello(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "hello, golang!") } HTTPハンドラ "/hello"のパスで ハンドラを設定 ポート8080で HTTPサーバを起動 Goについて/Goの特徴 $ curl http://localhost:8080/hello hello, golang! curlでアクセスしてみると 16
  17. 17. Goで開発ツールを作ろう その2 とあるアプリ開発の中盤にて... Android開発とGo/Goで開発ツールを作ろう 17 JSONをCSVに変換したい! Windowsで動くツールを作って! 開発環境はMacだから... D&DしたらJSONをCSVに変換するか... エンジニア 非エンジニア
  18. 18. Goで開発ツールの作り方 その2 ■ Windowsでも動く変換ツール Android開発とGo/Goで開発ツールを作ろう 18 Go製のツール ● クロスコンパイル ● encoding/json ● encoding/csv ● osでファイル操作 エンジニアの Mac Windows用の バイナリを渡す 非エンジニアの Windows ファイルをD&Dで変換クロスコンパイル
  19. 19. Goで開発ツールを作ろう ■ シングルバイナリ/クロスコンパイル ● Windows, Linux, Macなどで動く ● 動作環境を準備しなくていい ■ 豊富な標準ライブラリ ● HTTPサーバが簡単につくれる ● ファイル操作や各種エンコード ● 圧縮処理や画像処理 ■ 並行処理 ● リソースを効率的に使う 19 Android開発とGo/Goで開発ツールを作ろう
  20. 20. Androidアプリ開発とGo ● Goで開発ツールを作ろう ● Android上で動くツールを作ろう 20
  21. 21. Android上で動かそう ■ クロスコンパイルすれば、Androidで動く 21 Android端末 開発PC AndroidもLinuxなので Linux用にコンパイルする クロスコンパイル adb push adb shellで動かす Android開発とGo/Android上で動くツールを作ろう
  22. 22. Android上で動かそう ■ クロスコンパイルする ■ adb pushで端末に送る ■ adb shellで実行権限を与えて動かす $ GOOS=linux GOARCH=arm go build mytool.go $ adb push mytool /data/local/tmp $ adb shell $ chmod 755 /data/local/tmp/mytool $ /data/local/tmp/mytool 22 Android開発とGo/Android上で動くツールを作ろう
  23. 23. Android上で動くツール その1 アプリ上でダウンロードしたファイルが サイズが0になってることがある。 他に破損してるファイルがないか調べたい。 エンジニアA 特定の端末だけ発生する... 端末内に入ってファイル1つ1つ調べるか... エンジニアB Android開発とGo/Android上で動くツールを作ろう 23
  24. 24. サイズ0のファイルを探す 24 Android開発とGo/Android上で動くツールを作ろう Youtubeで見る コード 母艦のシェル adb shell 端末
  25. 25. Android上で動くツール その2 SNSの写真をダウンロードして リストで表示する部分のテストをしたい。 SNSへの接続部分はできてない。サイズ未定。 エンジニアA モック画像の配信サーバを用意する... 10x10.pngがきたら10x10の画像を返す... 端末からアクセスできるサーバがないから 端末でサーバを動かすか... エンジニアB 25 Android開発とGo/Android上で動くツールを作ろう
  26. 26. 画像配信のモックサーバ 26 Android開発とGo/Android上で動くツールを作ろう Youtubeで見る コード 母艦のシェル adb shell 端末
  27. 27. Android上で動かすツール ■ adb shell上で使えるコマンドを作る ● 動作環境を用意しないで済む ● Android上だけで完結 ● ファイル操作に関するパッケージが充実 ○ os, path/filepath など ■ 端末内サーバ ● ブラウザやアプリからアクセスできる ● モックサーバ ● プロキシサーバ ○ goproxyが便利 27 Android開発とGo/Android上で動くツールを作ろう
  28. 28. Android上で動かすツールの注意点 ■ ピュアGoでないとコンパイルが難しい ● cgoで書かれてると設定が必要 ○ cgoを使うとCで書かれたライブラリが使える ○ CCにNDKのCコンパイラを指定(後述) ■ OSに依存する処理には注意 ● OSに依存するライブラリ ● 環境によってサイズの異なる型の扱い ○ 環境によって32ビットだったりする ○ サイズ固定の型に書き変える ■ int32, int64, float32, float64など 28 Android開発とGo/Android上で動くツールを作ろう
  29. 29. Go Mobile ● cgoとGo Mobile ● SDKアプリ ● Nativeアプリ 29
  30. 30. cgo ■ Cで書かれたコードやライブラリが使える import "unsafe" /* #include <stdio.h> #include <stdlib.h> void hello(char *s) { printf("Hello, %sn", s); } */ import "C" func main() { str := C.CString("Droid Kaigi") C.hello(str) C.free(unsafe.Pointer(str)) } import "C"の上の コメント内にCのコードが書ける GoからCのコードを呼び出せる C上扱える値はGoのGCに回収されない Cの char * の変数を用意 30 Go Mobile/cgoとGo Mobile コード
  31. 31. Android向けにcgoを使ってビルド ■ cgoのコードもクロスコンパイルできる $ CGO_ENABLED=1 CC=arm-linux-androideabi-gcc GOOS=android GOARCH=arm GOARM=7 go buid -build-mode=pie hellocgo.go $ adb push hellocgo /data/local/tmp $ chmod 755 /data/local/tmp/hellocgo $ /data/local/tmp/hellocgo Hello, Droid Kaigi Go1.5までは -ldflags="-extldflags=-pie" cgoを含む場合はandroid クロスコンパイルでcgoを使う場合 31 Go Mobile/cgoとGo Mobile
  32. 32. build-mode ■ どうビルドするかを指定するオプション ● archive, c-archive ○ Cアーカイブ(.a)を作る ● shared, c-shared ○ 共有ライブラリ(.so)を作る ● exec ○ 実行可能ファイル ● pie ○ PIE形式の実行可能ファイル c-{archive, shared}は mainパッケージが対象 Android向けにも.soファイルが作れる 32 Go Mobile/cgoとGo Mobile
  33. 33. cgoとNDK 33 Go Mobile/cgoとGo Mobile Go cgo NDK ・クロスコンパイル ・共有ライブラリ ・Cのライブラリ ・JNI ・NativeActivity Go Mobile GoでAndroidアプリの開発
  34. 34. Go Mobileとは? ● Goでモバイルアプリを作るツール群 ○ iOS / Androidに対応 ○ golang.org/x/mobile ● 2通りのスタイル ○ SDKアプリ ⇒ Goで書いたライブラリを呼び出す ○ Nativeアプリ ⇒ Goだけで書く 参考:https://github.com/golang/go/wiki/Mobile 34 Go Mobile/cgoとGo Mobile
  35. 35. 35 https://github.com/golang/mobile
  36. 36. Go Mobileのインストール ■ 事前に必要なもの ● Goの開発環境(1.5以上) ● Androidの開発環境 ■ インストール $ go get golang.org/x/mobile/cmd/gomobile $ gomobile init -v # NDKなどをインストール 他に必要なものはこの2つのコマンドで揃う 36 Go Mobile/cgoとGo Mobile
  37. 37. Go Mobile ● cgoとGo Mobile ● SDKアプリ ● Nativeアプリ 37
  38. 38. Go aarファイル SDKアプリとNativeアプリ 38 Go Mobile/SDKアプリとNativeアプリ バインディングクラス(Java) 共有ライブラリ(.so) Java gomobile bind ■ SDKアプリ ■ Nativeアプリ apkファイル Go NativeActivity 共有ライブラリ(.so) gomobile build メイン ライブラリとして メイン
  39. 39. SDKアプリの例 ■ Ivy big number calculator(コード) ● APLっぽい言語の処理系のアプリ ● Rob Pikeが書いた実装をライブラリとして呼び出す ● Android版とiOS版でライブラリは同じ 39 Go Mobile/SDKアプリ Google Play App Store
  40. 40. gomobile bindの使い方 ■ aar(Androidアーカイブ)を生成 ● Goをビルドした共有ライブラリ(.so) ● バインディング(Java)をビルドした.jar ■ Android Studio(AS)のプラグインを使う ● gobindPlugin ● ASからgomobile bindを走らせる ● 生成したaarをリンク $ gomobile bind mypkg 40 Go Mobile/SDKアプリ
  41. 41. JavaからGoを呼び出す 41 Go Mobile/SDKアプリ Javaバインディング Javaのコード Cのコード Goのコード JNI cgo gomobile bindが 自動生成する
  42. 42. パッケージ GoとJavaのバインディング 42 Go Mobile/SDKアプリ シングルトン抽象クラス 構造体 抽象クラス フィールド Getter/Setter メソッド 抽象メソッド パッケージ関数 staticメソッド JNIをつかった呼び出しは 具象クラスに隠蔽されている Go Java
  43. 43. gomobile bindで使えるGoの型 ■ 基本的な対応型 ● 符号付き整数と浮動小数点数 ● ブーリアン型と文字列型 ● バイトスライス([]byte) ■ 関数 ● 引数と戻り値が対応型の関数 ○ 戻り値は原則1つまで、error型は2つ目にできる ○ 2つ目のerror型はJavaのExceptionになる ■ 構造体 ● 公開された対応型のメソッドとフィールド ■ インタフェース ● 対応型のメソッド 今後増える予定 スライス =配列の参照型 Goは多値が返せる 43 Go Mobile/SDKアプリ
  44. 44. Go Mobile ● cgoとGo Mobile ● SDKアプリ ● Nativeアプリ 44
  45. 45. Go aarファイル SDKアプリとNativeアプリ 45 Go Mobile/Nativeアプリ バインディングクラス(Java) 共有ライブラリ(.so) Java gomobile bind ■ SDKアプリ ■ Nativeアプリ apkファイル Go GoNativeActivity 共有ライブラリ(.so) gomobile build メイン ライブラリとして メイン
  46. 46. Go Mobileでゲーム ■ Flappy Gopher ● GoCon キーノート ○ ソースコード ● Goだけで書かれている ● タッチイベント ● 画像の描画 ● 解説記事 ○ KLabGames Tech Blog 46 Go Mobile/Nativeアプリ $ go get github.com/adg/game $ cd $GOPATH/src/github.com/adg/game $ gomobile build
  47. 47. gomobile buildの使い方 ■ apkを生成 ● Goをビルドした.so ● GoNativeActivityをビルドしたdex ■ インストールまで行う ● 内部adb installを使う ● Androidのみ対応 $ gomobile build mypkg $ gomobile install mypkg 47 Go Mobile/Nativeアプリ goコマンドでビルドするとPCでも動く
  48. 48. Nativeアプリの機能 ■ 描画 ● OpenGL ES 2(gl, exp/gl/glutil) ● 2Dシーングラフ(exp/sprite) ■ イベント ● タッチイベント(event/touch) ● ライフサイクル(event/lifecycle) ■ センサー(exp/sensor) ● 加速度、ジャイロ、磁気センサ ■ 音(exp/audio) 48 Go Mobile/Nativeアプリ パッケージ名
  49. 49. Nativeアプリの基本 49 Go Mobile/Nativeアプリ イベントループ 描画イベント タッチイベント ライフサイクルイベント ■ ループしながらイベントを受信して処理 イベントの種類ごとに 分岐して処理 Androidの onStartなど
  50. 50. Nativieアプリの描画 ■ OpenGL ES 2 ● gl, exp/gl/glutil ● 自前でShaderなどを書く ■ スプライトエンジン ● exp/sprite ● 2Dシーングラフ ● OpenGLの関数を余り触らなくて良い ● お手軽に2Dゲームを作れる (OpenGLをゴリゴリ書くよりかは) 50 Go Mobile/Nativeアプリ
  51. 51. スプライトエンジン 51 Go Mobile/Nativeアプリ scene gopher スプライトエンジン ground1 ・・・ ノード テクスチャ サブテクスチャ ゲーム画面 描画 シーングラフ
  52. 52. スプライトエンジンを使った描画 52 Go Mobile/Nativeアプリ ・テスクチャのロード ・シーングラフの構築 描画イベント ライフサイクルイベント (画面表示開始) ・ノードの再配置 ・サブテクスチャの張替え 繰り返す 初期化処理 アフィン変換行列を セットして、座標、 角度、縮尺を設定
  53. 53. Nativeアプリの現状の問題点 ■ Google Playで公開できない ● resディレクトリが取り込めない ○ アイコンが変えれない ● 署名なしでビルドが出来ない ■ テキスト入力 ● テキスト入力が出来ない ● テキストの描画は頑張ればできる ■ プラットホームのAPIが呼べない ● Go側にインタフェースがない 53 Go Mobile/Nativeアプリ
  54. 54. ちょっと残念な解決策 ■ resディレクトリが取り込めない ● 後からapkに入れ込む ■ 署名なしでビルドが出来ない ● 一旦消して、別のkeystoreで署名する ■プラットホームのAPIが呼べない ● 内部で使ってるcgoの領域で定義された JavaVMオブジェクトを使う ● apkの中の.soを持ってきて、Android Studio のプロジェクトに読み込ませる せっかくapkまで作ってくれるのに! 54 Go Mobile/Nativeアプリ
  55. 55. Google Playで公開できました http://github.com/tenntenn/gofun 55 Go Mobile/Nativeアプリ
  56. 56. GoからToastが呼び出せました 56 Go Mobile/Nativeアプリ
  57. 57. Nativeアプリへの願望 ■ apkまで自動で行わない ● .soとjarの入ったaarを作る ○ gomobile bindと同じような方法 ○ Android Studioに読み込むプラグインを用意 ■ Javaを呼び出すインタフェースを公開する ● 実は存在してるけど内部パッケージ ● gomobile bindのバインディングに近い 57 Go Mobile/Nativeアプリ
  58. 58. しかしながら... ■ iOSのことも考える必要がある ● 同じフローでいけるのか? ● Obj-C/swiftのコードを呼べるのか? ■ GoやGo Mobileのコンセプトに沿うのか ● プラットフォームごとに違う方法は取れない ● ツール(gomobileコマンド)で面倒な処理をすべて行え るか? 58 Go Mobile/Nativeアプリ
  59. 59. まとめ ■ GoはAndroid開発に使える? ● さくっと開発ツールを作る ● Android上で直接動くツール ■ Go Mobile ● まだ実験段階のプロジェクト ● C/C++で書かれていた部分が置き換わっ ていってほしい ○ それでもcgoでCを書く必要あり 59
  60. 60. おまけ ■ shiny ● GUIライブラリ ● Go Mobileに似ている ● まだ始まったばかり ■ 2つのレイヤーからなる ● 基礎的な機能(ドライバ)を提供 ⇒ OpenGLやX11などの実装を提供 ● ピュアGoで書かれたウィジェット ⇒ 特定のドライバ実装に依存しない サンプルをMacで動かしたところ 60
  61. 61. 61
  62. 62. 62 以下、補足スライド
  63. 63. 63 SDKアプリの詳細
  64. 64. gomobile bindで生成されるバインディング ■ Goのコード(参考) ■ 生成されるJavaのコード package mypkg type Counter struct{Value int} func (c *Counter) Inc(){c.Value++} func New() *Counter{return &Counter{5}} public abstract class Mypkg { private Mypkg() {} public static final class Counter { public void Inc(); public long GetValue(); public void SetValue(long value); } public static Counter New(); } Java Go 自動生成
  65. 65. JavaからGoのコードを呼び出す ■ バインディングオブジェクト経由で呼び出す ● パッケージは抽象クラス ○ パッケージレベルの関数はパッケージクラスのメソッ ドになる ● 構造体は内部クラス ○ メソッドは内部クラスのメソッドになる ○ フィールドはGetter/Setter付きのフィールド Counter c = Mypkg.New(); c.Inc(); String s = String.format("%d", c.GetValue()); Log.d("Mypkg", s); // 1 Java
  66. 66. GoからJavaを呼び出す 66 Go Mobile/SDKアプリ Javaバインディング Javaのコード Cのコード Goのコード インタフェースを実装 インタフェースを 引数に関数呼び出し Javaバインディング Javaのコード Cのコード インタフェースの メソッドを呼び出し インタフェースの スタブは自動生成 Javaで実装したものをGoで呼び出せる
  67. 67. GoからJavaのコードを呼び出す ■ Go側でインタフェースとそれを使う関数を用意 ■ Java側でインタフェースを実装する public class SysPrint extends Myfmt.Printer.Stub { public void Print(String s) { System.out.println(s); } } Java package myfmt type Printer interface {Print(s string)} func PrintHello(p Printer) { p.Print("Hello, World!") } Go スタブクラスが 自動生成される
  68. 68. GoからJavaのコードを呼び出す ■ gomobile bindで生成されるバインディング public abstract class Myfmt { private Myfmt() {} public interface Printer { public void Print(String s); public static abstract class Stub implements Printer { ・・・ } ・・・ } public static void PrintHello(Printer p) { ・・・ } } Java GoのPrintHelloを 呼び出すメソッド Printerを実装
  69. 69. GoからJavaのコードを呼び出す Myfmt.Printer printer = new SysPrint(); Myfmt.PrintHello(printer); Java ■ Java側からPinterを使用する関数を呼び出す ■ 手順まとめ ● Goでインタフェースとインタフェースを引数に取 る関数を用意 ● gomobile bindでスタブを作る ● Java側でスタブを継承して実装する ● Java側からインタフェースを引数に取るGoの関 数を呼ぶ
  70. 70. SDKアプリでアプリ内サーバ 70 Go Mobile/SDKアプリ Androidアプリ Javaのコード Go製アプリ内サーバ HTTPリクエスト アプリ内サーバへHTTPリクエストを投げ るという選択肢も APIサーバ DBサーバ HTTPリクエスト
  71. 71. 71 Nativeアプリの詳細
  72. 72. app.Main ■ イベントループを行う関数 func main() { app.Main(func(a app.App) { // イベントループを書く }) }
  73. 73. イベントループ ■ app.App.Events()からイベントを取得 // Events() <-chan interface{} for e := range a.Events() { switch e := a.Filter(e).(type) { case lifecycle.Event: // ... case paint.Event: // ... } }
  74. 74. テクスチャのロード ■ アセットのオープン a, err := asset.Open("gopher.png") ■ 画像のデコード img, err := image.Decode(a) ■ テクスチャのロード t, err := eng.LoadTexture(img) assetsディレクトリ以下 のファイルを見に行く
  75. 75. シーングラフの構築 ■ ノードの作成と登録 ■ 子ノードの追加 scene := &sprite.Node{} eng.Register(scene) n := &sprite.Node{} eng.Register(n) scene.AppendChild(n)
  76. 76. サブテクスチャの作成と設定 ■ サブテクスチャの作成 st := sprite.Subtex { T:t, // テクスチャ R:iamge.Rect(0, 0, 100, 200) } ■ サブテクスチャの設定 eng.SetSubTex(n, st) テクスチャ上の該当の領 域を指定する
  77. 77. アフィン変換行列の設定 ■ アフィン変換行列の設定 ルートノードは、サイズ:1pt x 1pt、 座標:(0,0)、角度:0に対して変換行列を掛け合わせる // Scale(2,2)して、(5,5)だけ並行移動 eng.SetTransform(root, f32.Affine{ {2, 0, 5}, {0, 2, 5}, }) 1pt = 1/72 inch
  78. 78. アフィン変換行列の計算 ■ 親ノードから子ノードへ 親ノードの変換結果に子ノードの変換行列を 掛けわせて子ノードの描画位置を決める root n eng.SetTransform(root, f32.Affine{ {2, 0, 5}, {0, 2, 5}, }) eng.SetTransform(n, f32.Affine{ {100, 0, 10}, {0, 100, 10}, }) 2x2, (5, 5) 200x200, (25, 25)
  79. 79. ノードの配置 ■ Node.Arranger.Arrange ● 毎フレーム呼ばれる ● ノードの位置を変更したりする type Arranger interface{ Arrange(e Engine, n *Node, t clock.Time) }

×