本業では、ゲームのサーバーとインフラ周りの実装をしていますが、せっかくならクライアント側も触ってみたい欲求が高まってきたので、プライベートで Unity に入門中です。
Unity は C# で記述した処理をゲームオブジェクトなどに紐づけて挙動を制御したり、サーバーと通信したりすることが可能です。
Unity で使う C# を書く時には VisualStudio や Rider が採用されていそうですが、普段はエディタに VSCode を使っているので、せっかくなら C# も VSCode で書きたいです。
実現する過程で色々と拾いものをしたので、整理しておきます。
環境 🔗
- macOS Big Sur: v11.6.1
- Processor: Apple M1
- Unity: 2021.3.4f1 Personal
準備 🔗
公式ドキュメント をみながら進めていきます。
.NET SDK 🔗
まずは
.NET SDK
が必要なので入れていきます。
Microsoft の公式の手順
には、
開発者またはユーザーの場合、通常はインストーラーを使用することをお勧めします。
と記載されているので、基本的にはインストーラを使うべきな気はします。
個人的な好みで可能な限りホームディレクトリ配下にインストールしたい主義なので、SDK のバイナリを落としてきて展開しました。
このとき、MacOS のセキュリティ周りの知見を得たので、 おまけ として記載しておきます。
Mono 🔗
Mono
を入れます。
インストーラでグローバルに言えるのはあまり好みではないのですが、Mono に関しては MacOS 向けのバイナリが配布されていなそうなので、大人しくインストーラを使います。
(ソースコードの tarball は公開されているので、ローカルでビルドすることもできなくはないですが、
ここ
にインストーラの挙動が説明されているので、一旦よしとしました…)
C# extension 🔗
VSCode の
C# extension
。
これにより、
OmniSharp
という C# の language server がインストールされます。
Unity の Script Editor 設定 🔗
Unity を開き、ツールバーの Unity > Preferences > External Tools から External Script Editor を Visual Studio Code に指定します。
この設定により、Unity から C# スクリプトを開くと VSCode で起動されるようになります。
これで一通りの準備が整いました。
VSCode の設定 🔗
結論から書くと、ここまでの設定に加えて、setting.json に omnisharp に関する以下の設定を追記することで、UnityEngine も含めた補完が効くようになります。
"omnisharp.path": "latest",
"omnisharp.monoPath": "/Library/Frameworks/Mono.framework/Versions/Current",
"omnisharp.useModernNet": false,
ポイントとしては Mono をインストールした上で、"omnisharp.useModernNet": false を指定することです。
true にすると、.NET6 を使うようになりますが、
OmniSharpのAnnouncement
にも書かれている通り、
If you still need Unity or .NET Framework support, you can set omnisharp.useModernNet to false in your VS Code settings and restart OmniSharp. Please see the Requirements section above to ensure necessary tooling is installed.
とのことなので、上記のように設定する必要があります。
Unity の C# コンパイラー が、スクリプトランタイムのバージョンに .NET 4.6 相当を要求していることからも、.NET 6 以上が必要な useModernNet は使えなさそうなことがわかります。
おまけ1: web から落としてきた .NET SDK バイナリを M1 Mac で動かす 🔗
準備のところで、.NET SDK のバイナリを落としてきてホームディレクトリに展開する形でインストールしたと書きました。
単純に展開しただけで dotnet を使おうとすると、
“Microsoft.NETCore.App.app”は壊れているため開けません。 ゴミ箱に入れる必要があります。
Failed to load /path/to/dotnet/dotnet-sdk-6.0.300-osx-arm64/shared/Microsoft.NETCore.App/6.0.5/libhostpolicy.dylib, error: dlopen(/path/to/dotnet/dotnet-sdk-6.0.300-osx-arm64/shared/Microsoft.NETCore.App/6.0.5/libhostpolicy.dylib, 1): no suitable image found. Did find:
/path/to/dotnet/dotnet-sdk-6.0.300-osx-arm64/shared/Microsoft.NETCore.App/6.0.5/libhostpolicy.dylib: code signature in (/path/to/dotnet/dotnet-sdk-6.0.300-osx-arm64/shared/Microsoft.NETCore.App/6.0.5/libhostpolicy.dylib) not valid for use in process using Library Validation: library load disallowed by system policy
An error occurred while loading required library libhostpolicy.dylib from [/path/to/dotnet/dotnet-sdk-6.0.300-osx-arm64/shared/Microsoft.NETCore.App/6.0.5]
と怒られて、使わせてくれません。
MacOS は、特に M1 の方はアプリケーションの検証が厳格に行われているらしく、インターネットから落としてきたバイナリをそのままでは実行させてくれないみたいです。
具体的には、インターネットから落としてきたファイルには、com.apple.quarantine という
拡張ファイル属性
が付与され、ライブラリの読み込みなどは実行が制限されるようです。
ls -l した時に、@ がついていると、拡張ファイル属性が付与されている目印です。
-rw-r--r--@ 1 <xxx> <xxx> 1116 4 14 02:47 LICENSE.txt
-rw-r--r--@ 1 <xxx> <xxx> 78479 4 14 02:48 ThirdPartyNotices.txt
-rwxr-xr-x@ 1 <xxx> <xxx> 145632 4 27 00:56 dotnet
drwxr-xr-x@ 3 <xxx> <xxx> 96 4 14 03:09 host
drwxr-xr-x@ 6 <xxx> <xxx> 192 4 22 00:39 packs
drwxr-xr-x@ 3 <xxx> <xxx> 96 4 22 00:39 sdk
drwxr-xr-x@ 3 <xxx> <xxx> 96 4 22 00:39 sdk-manifests
drwxr-xr-x@ 4 <xxx> <xxx> 128 4 22 00:39 shared
drwxr-xr-x@ 3 <xxx> <xxx> 96 4 22 00:39 templates
具体的にどんな属性が付与されているのかは、xattr コマンドで確認できます。
> xattr dotnet
com.apple.quarantine
この com.apple.quarantine (quarantine: 検疫) がインターネットから落としてきたファイルであることの目印です。
この属性を外してあげることで、tarball で落としてきた arm64 の .NET SDK を使うことができます。
> xattr -rd com.apple.quarantine /path/to/dotnet
※ 基本的にはセキュリティのための機能なので、十分に安全性が確認できているものに対してだけ使うようにします。
おまけ2: .NET Framework について 🔗
基本的には C#のドキュメント に詳しく書かれているのでざっくりとだけまとめます。
共通言語基盤(common language infrastructure; CLI)という、特定のプログラミング言語やコンピュータアーキテクチャに依存しない実行環境の国際的な仕様があります。
各種言語で記述されたコードは、たいおするコンパイラによって CLI に準拠した共通中間言語に変換し、共通言語ランタイムの実装と合わせて最終的に機械語に翻訳することで、特定の言語や環境に依存しない開発を実現できる、というのが .NET Framework の中心的なコンセプトになっているようです。
.NET Framework に含まれる .NET Core ランタイムは、共通言語ランタイム(common language runtime; CLR)の Microsoft の実装です。
C# で記述したコードは、CLI に準拠する中間言語(IL)にコンパイルされます。これらの中間言語とメタデータなどがアセンブリ(*.dll)として保存される形になります。
IL は C# 以外からも Fsharp, VB, .NET C++ などの言語からも生成され、いずれも CLI に準拠しています。
つまり、VB で書いたライブラリを C# で読み込んで使う、と言ったことも可能になっています。
.NET SDK が .NET Framework の Microsoft の実装だったのに対し、Mono は .NET Framework のオープンソースの実装になります。
(OracleJDK と OpenJDK みたいなもの?)
ただし、Mono は .NET Framework の基本クラスライブラリ(BCL) 以上に独自のクラスが拡張実装されています。
Unity も .NET Framework ではなく、Mono に依存しているようです。
※ Unity が機械語に翻訳されるまでの流れは ここ がイメージを掴みやすい。
感想 🔗
まだまだ Unity を触り始めたばかりなのですが、Unity の API に先立って .NET Framework 周りの知識を仕入れることができました。
実務であれば、時間的な制約もありなかなか気の向くままに調べたりすることはできないのですが、プライベートだと気の済むまで調べられるのがいいですね。