【Unity】Package Manager活用術


こんにちは。Annulus Gamesです。

先日、unity1week共有会#10に「Package Manager活用術」というテーマで登壇させていただきました。内容としては、自作ライブラリをPackage Managerを使って管理する方法や、OSSを活用して開発を効率化しようといったものになっています。

今回の記事では、共有会では時間の都合で説明を省略した部分も含めて、Package Managerの活用方法についてをより細かく解説していきたいと思います。


共有会のアーカイブはこちらから。サウンドについての話など、色々参考になる話題が詰まっているので是非。


Package Managerとは

Package Managerとは、Unityにおけるプロジェクト内のパッケージ管理を行うシステムのことです。CinemachineやPost-processing Stackなど、Unityの機能を追加する際に使うことが多いかと思います。

また、購入したアセットのインポートやgitリポジトリにあるパッケージの追加を行うことも可能です。

さて、このPackage Managerですが、なんと自作パッケージを扱うことも可能です。Package Managerから導入したパッケージはPacakgesフォルダ以下に参照が追加される形になっているので、パッケージの管理が非常に楽になります。

「ライブラリを自作したは良いものの、結局プロジェクト毎にコピペしてる...」

なんて方は、今すぐPackage Managerを導入しましょう。


パッケージ作成の手順

パッケージ作成の手順については、こちらに記載されています。

ただし、これだけでは少々わかりづらいので、この記事では実際にパッケージを作成する手順についてを詳しく説明していきたいと思います。


1. 新規プロジェクトを作成

それでは、実際にパッケージを作っていきましょう。

まずは、新規プロジェクトを作成します。


プロジェクト名がパッケージの名前と一致する必要はありませんが、同じであることが一般的です。

また、1つのプロジェクト内に複数のパッケージを作成することも可能ですが、基本的にはパッケージ1つにつきプロジェクト1つで管理する形になります。


2. ディレクトリ構成を変更

普段のプロジェクトではScriptsやPrefabsなどでフォルダを分けることが多いかと思います。しかし、Package Managerに対応させる際には、Unity公式の推奨するディレクトリ構成に沿ってプロジェクト内のフォルダを配置し直す必要があります。

以下が、推奨されるディレクトリ構成になります。 
 <root> 
├── package.json 
├── README.md 
├── CHANGELOG.md 
├── LICENSE.md 
├── Third Party Notices.md 
├── Editor 
│ ├── [company-name].[package-name].Editor.asmdef
│ └── EditorExample.cs 
├── Runtime 
│ ├── [company-name].[package-name].asmdef 
│ └── RuntimeExample.cs
├── Tests
│ ├── Editor 
│ │ ├── [company-name].[package-name].Editor.Tests.asmdef 
│ │ └── EditorExampleTest.cs
│ └── Runtime 
│ ├── [company-name].[package-name].Tests.asmdef 
│ └── RuntimeExampleTest.cs 
├── Samples~ 
│ ├── SampleFolder1
│ ├── SampleFolder2
│ └── ... 
└── Documentation~ 
    └── [package-name].md

やたら項目が多くて大変そうですが、あくまでこれは配布用の場合です。自分で使う分にはサンプルコードやREADMEなどは必要ないので、省略してしまいましょう。

<root> 
├── package.json 
├── Editor 
│ ├── [company-name].[package-name].Editor.asmdef
│ └── EditorExample.cs 
├── Runtime 
│ ├── [company-name].[package-name].asmdef 
│ └── RuntimeExample.cs

というわけで、最低限必要な構成はこんな感じになります。(エディタ拡張をしないのであればEditorフォルダも不要です。)

パッケージに含めるScriptについては、エディタ上のみで動作するものはEditorフォルダに、実行時に動作するものはRuntimeフォルダに入れていく形になります。


3. package.jsonを作成

次にpackage.jsonという名前でファイルを作成し、パッケージに関する情報をJSON形式で書き込んでいきます。

以下のような情報を記入します。

{
  "name": "com.[company-name].[package-name]",
  "version": "1.2.3",
  "displayName": "Package Example",
  "description": "This is an example package",
  "unity": "2019.1",
  "unityRelease": "0b5",
  "documentationUrl": "https://example.com/",
  "changelogUrl": "https://example.com/changelog.html",
  "licensesUrl": "https://example.com/licensing.html",
  "dependencies": {
    "com.[company-name].some-package": "1.0.0",
    "com.[company-name].other-package": "2.0.0"
 },
 "keywords": [
    "keyword1",
    "keyword2",
    "keyword3"
  ],
  "author": {
    "name": "Unity",
    "email": "unity@example.com",
    "url": "https://www.unity3d.com"
  }
}

最低限必要な項目はnameとversionのみですが、パッケージの内容を把握しやすくするためにもdisplayNameやdescriptionは記入しておきましょう。

nameにはパッケージの正式名をcom.company-name.package-nameのような逆ドメイン方式で記入します。大文字は使用できないので注意。

versionにはパッケージのバージョンを記入します。値はセマンティックバージョニング(メジャー.マイナー.パッチの3つの数字で表す形式)に準拠する必要があります。

displayNameやdescriptionには、Package Manager上で表示される名前や説明を記入します。また、パッケージが他のパッケージに依存している場合はdependenciesにパッケージ名とバージョンを追加します。

その他の項目については公式のマニュアルを参考に。


4. .asmdefを配置

Unityがパッケージ内のスクリプトを認識するためには、Assembly Definition(asmdef)を配置してアセンブリを分割する必要があります。

Assembly Definitionとは、C#のビルドファイル(アセンブリ)を分割するための機能になります。Package Managerを使わないのであればあまり馴染みのない機能かもしれませんが、実際にパッケージを運用する上でAssembly Definitionは必ず覚えておくべきです。

とは言っても、やることは.asmdefファイルを配置するだけなので、手っ取り早くパッケージを作成したい場合には読み飛ばしてもらって構いません。ただし、Assembly Definitionを利用することでコーディングの工程が若干変化するので、実際にどのような挙動になるのかはしっかり把握しておきましょう。


asmdefが設定されていない状態では、Unityはプロジェクト内の全てのC#スクリプトをAssembly-CSharp(Editorフォルダ内のスクリプトはAssembly-CSharp-Editor)にコンパイルします。

要するに全てのスクリプトがまとめて1つの.csprojに出力されている状態です。

小規模なプロジェクトならこれで十分ですが、規模が大きくなるにつれて次のような問題が出てきます。

僅かな変更を加えるだけで全てのスクリプトがコンパイルし直されてしまう
どのスクリプトも他のスクリプトで定義された型に直接アクセスできてしまう
全てのスクリプトが全てのプラットフォーム用にコンパイルされてしまう

そこで、.asmdefファイルを配置することによってモジュール毎に出力するファイルを分割します。

アセンブリから他のアセンブリにアクセスする場合には明示的に参照を追加する必要があります。また「Assembly-CSharpからは全てのアセンブリにアクセス可能」ですが、「分割したアセンブリからAssembly-CSharpにアクセスすることは不可能」です。

加えて、アセンブリの循環参照は許可されていません。例えば、ModuleAがModuleBを参照する場合、ModuleBがModuleAを参照することはできません。適当にアセンブリを分割していると循環参照に陥りやすくなってしまうので、依存関係を意識して分割するようにしましょう。


解説が長くなりましたが、実際にやることは単純です。

Create > Assembly Definition を選択して.asmdefファイルを作成し、RuntimeフォルダとEditorフォルダにそれぞれ配置します。


基本的にはこれだけですが、ライブラリによっては依存関係やプラットフォームの設定を行う必要があります。


依存関係の設定については、使いたいアセンブリの.asmdefファイルをAssembly Definition Referencesに突っ込めばOKです。これで、追加したアセンブリを参照できるようになります。先に書いた通り、循環参照は許可されていないので気を付けましょう。


プラットフォームの設定については、基本的にはAny Platformのままで問題ありません。ただし、エディタ拡張を使用する場合はEditor以外のチェックを外すようにしましょう。

これでパッケージは完成です!


パッケージを導入してみる

それでは、実際に作ったパッケージをPacakge Managerから読み込んでみましょう。

パッケージを導入したいプロジェクトを開き、Package Managerを開きます。

そして、左上の「+」ボタンから「Add package from disk...」を選択して、作成したパッケージのpacakge.jsonファイルを選択します。すると...

このように、自作パッケージをPackage Managerから追加することができました。


また、gitリポジトリにあるパッケージを読み込むことも可能です。こちらも実際にやってみましょう。

ただし、GithubのリポジトリをPackage Managerから導入する際には、リポジトリの可視性をpublicに設定しておく必要があります。この手順ではprivateリポジトリを読み込むことはできないので注意してください。

今度は左上の「+」ボタンから「Add package from git URL...」を選択します。


リポジトリのURLを入力することで、gitリポジトリからパッケージを追加できます。ただし、package.jsonがルートフォルダに置かれていない場合はパスを指定する必要があります。


以上で導入は完了です。リポジトリを更新した場合は、Updateボタンを押すことでパッケージを更新することができます。


まとめ

・Package Managerでライブラリを管理しよう

・自作パッケージをPackage Managerに対応させよう

・gitリポジトリからもパッケージを追加可能


Package Managerを使うことで、ライブラリの管理を簡単に行うことができます。Package Managerを使いこなし、効率的に開発を行なっていきましょう。


コメント