Go言語で書いたモジュールをUnityのC#スクリプトから呼び出すまでの方法を紹介します。初めて試してみて若干手間取った部分があるので備忘録も兼ねて書き残しておきます。内容は高度な事はしてません。初心者、初めての人向けです。
# 前提
- ・ Windows環境を想定。Macの人は適宜置き換えてください。
- ・ [Go言語](https://go.dev/)の開発環境は別途インストールする必要がある。
- ・ [Mingw64](https://www.mingw-w64.org/)がビルドするために別途インストールする必要がある。
- ・ GOPATHやMingw64のpathなどを事前に通してある。 AndroidやiOS向けにビルドする方法は既に他の人のブログがあるので、そちらを参照して下さい。 DLL化してエディター上で実行する記事が見当たらなかったので、ここではUnityエディター上での実行を確認するまでとさせていただきます。。
# 変数の型について
Go言語やC#に限った話ではなく、異なる言語間でデータのやり取りをする場合、その変数の型はプリミティブ型しか使えない事がほとんどです。
プリミティブ型とは最も基本的な型で、int float char byte bool などで言語によって異なります。Vector3などもそのままでは他言語には渡せないので、float x,float yなどに分解してやる必要があります。プリミティブ型の変数、関数は特段難しい事はないので割愛します。
ここではstring型のやり取り、厳密にはstring型の引数、戻り値をUnity~Go言語で受け渡しする方法を紹介します。
# C#のstringとGo言語のstringは違う
C#にもGo言語にもstring型が存在しますが、
func GetSampleText(text string) string {・・・}
のようにGo言語側で定義して、Unity C#側で
private static extern string GetSampleText(string text);
と呼び出しても動作しません。エラーも出ません。多くの場合暴走したり落ちます。
これはC#のstringとGo言語のstringは一見名前が同じでも実はGoStringという型が適用されていて内部での形が微妙に違うからです。C#の文字列を正しくGo言語に渡したければ方法はいくつかあると思いますが、例として
のようにchar型(の配列)のポインタを受け渡しする必要があります。
# Go言語でWindows DLLをビルドする
go build -buildmode=c-shared -o hoge.dll hoge.go
ターミナルで上記のように打ち込んでビルドする。.dllと.hの二つが出力されるがUnityで必要なのはdllだけなのでdllファイルをUnityエディターのAssets-Pluginsフォルダにコピーする。 dllは一度でも実行されると変更も削除も出来なくなるので、一度でもPlayボタンを押してテスト実行させた後はdllを変更するには一度Unityを終了して再実行する必要があります。
# Unityで呼び出し用のC#スクリプトを作る
呼び出すUnity側では、
のようなスクリプトを作ります。なるべく戻り値もstring型で取得したかったけど面倒だったので一旦挫折しました。
unsafe private static extern byte* GetSampleTest(string text);
元はcharポインタですが、あとでbyteポインタとして使うのでUnity側では初めからbyteで定義しておきます。
またUnityでポインタを使うにはunsafeを入れて宣言しなければいけないし、事前にUnityエディターでunsafeの設定にチェックを入れる必要があります。
またGO言語には全角文字にUTF8が使用されるので、
System.Text.Encoding.UTF8.GetString(p, _maxLength)
のようにエンコードする必要があります。maxLengthは好きな数字でOK。
実行するとこのようになります。
# 結論
C# ~ Go言語の間で文字列データの受け渡しは一応可能ではあるけどunsafeは使わずに、なるべく直接文字列を避けてシリアライザとか上手く使うなり他の手を用いる方が良いと思います。
以上、初めてUnity-Go言語のネイティブプラグイン作成で手こずった部分を纏めてお行きました。世間で需要があるかはわかりませんが・・・