これは Unity #2 Advent Calendar 2017 の12日目の記事です。
昨日は @orangesuzuki さんの Unityのアニメーションデータを外部プログラムで利用するはじめの一歩 と
@Kan_Kikuchi さんの 日本語から変数や関数名を生成するエディタ拡張 でした。
今日は @Takaaki_Ichijo さんの Unityでフレンドとアイテム交換とかする機能をサーバーレスで作る その1 です。あわせてご覧ください!
Unityで何かを作っていると使い回しのできる便利なコードが溜まってくると思います。
普段はAssetsの中に入れてあるだけだと思いますが、その状態だとある一つの問題が・・・。
コンパイル時間が延びる
Assetsに存在しているC#のコードはRefresh1の度にコンパイルされています。
何かを更新する度に変更していないはずのコードをコンパイルする時間。その時間は無駄だと断言できます。
もちろん、修正が度々入るような出来たてのコードなら必要であるかもしれません。
しかしドッグフーディングも終わってバグも取れたようなライブラリコードや
AssetStoreやGithubなどからダウンロードしてきたコードなどを毎回コンパイルするのはすごく勿体無い!
(消極的な理由として、ダウンロードしてきたコードの警告を見たくないということもありますが)
その問題を解決するのがDLL化なのです!
DLL化する手順
主に以下のような手順で進めていきます。
Windows上で行うため、VisualStudioを例に出していますが
MacやLinuxなどであればXamarinStudioやMonoDevelopment、dotnetコマンドでも可能だと思います。
- VisualStudioなどでDLLプロジェクトを作成する。
- DLLプロジェクトファイルをUnity用に編集する
- DLLプロジェクトにライブラリコードを追加する。
- DLLプロジェクトをビルドする
- DLLをAssetsの中にコピーする
- UnityEditorをRefreshする
VisualStudioなどでDLLプロジェクトを作成する
VisualStudio上でプロジェクトを作成します。
この時、Class Library (.NET Core)
を選ぶと新しいcsproj形式2になるためそれを選択してください。
(今回は便宜上ClassLibrary1.csproj
という名前で作成しています)
DLLプロジェクトファイルをUnity用に編集する
-
ソリューションエクスプローラ上のプロジェクトを右クリックして
Edit ClassLibrary1.csproj
を選択します。
-
開いたcsprojにある
<TargetFramework>netcoreapp2.0</TargetFramework>
となっている部分を
<TargetFramework>net35</TargetFramework>
に書き換えてください。
(.NET Framework 4.6を使用する場合はnet46
) -
自動で作成されている
Class1.cs
は必要ないので削除してください。
using UnityEngine;
をしているコードを含む場合に必要な対応
- ソリューションエクスプローラ上のプロジェクト内にある
Dependencies
を右クリックしてAdd Reference
を選択します。
-
Browse
を選択して、以下の2つを参照に追加します。
相対パスで設定されてしまうため、gitなどで管理する場合はレポジトリ内に配置するなどの対策が必要です。
- C:\Program Files\Unity\Editor\Data\Managed\UnityEngine.dll
- c:\Program Files\Unity\Editor\Data\UnityExtensions\Unity\GUISystem\UnityEngine.UI.dll
DLLプロジェクトにライブラリコードを追加する
ソリューションエクスプローラ上のプロジェクトを右クリックしてOpen Folder in File Explorer
を選ぶと
プロジェクトファイルのあるディレクトリがエクスプローラによって開かれます。
対象のcsファイルをこのディレクトリにコピーしてください。(Editor拡張の場合は後述)
新しいcsproj形式の場合は自動で読み込まれます。(古い形式の場合は別途手動でプロジェクトへ追加してください)
DLLプロジェクトをビルドする
Build - Build Solution を選択するとDLLがビルドされます。
エラーが出る場合などは適時修正してください。
DLLをAssetsの中にコピーする
ClassLibrary1.csprojのパス\bin\Debug\net35\
にDLLが作成されているのでAssets内にコピーします。
毎回手動でコピーするのは面倒なのでCopyDllsAfterBuildを使って
ビルド時に自動でコピーされるようにする方法を紹介します。
CopyDllsAfterBuildを使用する
-
ClassLibrary1.csproj
のあるソリューションにConsole App (.NET Core)
のプロジェクトを追加します。
(今回は便宜上CopyDlls
という名前で作成しました。)
-
DLLプロジェクトと同様に
TargetFramework
をnet35
に変更します。 -
CopyDlls.csproj
のDependencies
を右クリックしてManage Nuget Packages
を選択します。
-
CopyDlls.csproj
にCopySettings.json
という名前のファイルを作成し、以下のように記述します。{ "destination": "UnityのAssetsまでのパス/DLLを配置するパス", "pattern": "*", "excludes": [ "UnityEngine", "UnityEditor", "CopyDlls" ] }
-
先と同様にビルドすると、
ClassLibrary1.dll
が所定に位置へコピーされているはずです。
エラーが発生した場合
もし以下のようなエラーが出た場合はPowerShellの実行に制限があるため、制限を解除します。
2>このシステムではスクリプトの実行が無効になっているため、ファイル C:\Users\ユーザー名\.nuget\packages\copydllsafterbuild\3.1.
2>2\tools\postbuild.ps1 を読み込むことができません。詳細については、「about_Execution_Policies」(https://go.microsoft.com/fwl
2>ink/?LinkID=135170) を参照してください。
2> + CategoryInfo : セキュリティ エラー: (: ) []、ParentContainsErrorRecordException
2> + FullyQualifiedErrorId : UnauthorizedAccess
コマンド プロンプト
又はbatchファイル
にて、以下のコマンドを実行します。
PowerShellの実行制限を解くことになるため、自己責任でお願いします
%WinDir%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -Command "Set-ExecutionPolicy RemoteSigned"
%WinDir%\System32\WindowsPowerShell\v1.0\powershell.exe -Command "Set-ExecutionPolicy RemoteSigned"
Rebuild Solution すればエラーがない状態でコピーされているはずです。
UnityEditorをRefreshする
UnityEditorへ戻りRefreshされればこれまで通りライブラリコードが使用できます!
ライブラリコードをデバッグしたくなった場合
DLL化したライブラリコードをデバッグしたくなった場合、
Assetsの中にcsファイルを戻すことでも対応することはできますが、
UnitTestを作成しデバッグすることをおすすめします。
Editor拡張コードの場合
Editor拡張コードの場合は以下の点が異なります。
-
UnityEditor.dll
への参照が必要-
C:\Program Files\Unity\Editor\Data\Managed\UnityEditor.dll
を参照に追加してください
-
- Editorディレクトリに配置することが必要(不要かも?要検証)
- Editor用の
CopyDlls
を作成し、Editorディレクトリ内へコピーするよう設定します
- Editor用の
VisualStudio 15.5 以降の場合
unsafeを含んだコードをDLL化した場合、UnityEditorが落ちるという現象を確認しています。
(unsafeコードのコンパイル結果が変わったため?)
その場合はDLLプロジェクト(ClassLibrary1.csproj)にNugetで
Microsoft.Net.Compilers
の2.4.0
を入れることで解消できます。
(コンパイラを古いものに戻す対応)
詳しくは @ufcpp さんのブログを読んでみてください。
最後に
これにより、コンパイル時間が短くなっていると同時に、
DLLファイルにまとまったお陰でライブラリを他のプロジェクトへ共有しやすくなっていると思います!
ぜひお試しください!
明日は @kido0617 さんの フリーのビジュアルノベルアセットFungusを使ってRPGのイベントを作る と
@keidroid さんの ScriptableObjectをマスターデータとして扱うあれこれ です。