UnityPackageManagerを触ってみる
はじめに
この記事ではUnityの新しいアセット管理につかうUnity Package Managerについて見ていきます。 ローカルでパッケージを作成しインストールする方法についても解説します。
Unityのバージョン: 2018.2.7f1
Unity Package Manager
Unity Package Manager(以降UPMと省略する)はUnity 2017から導入された パッケージ管理のシステムです。 公式のドキュメントはこちらです。
Unityの一部機能はこのUPM経由で提供されています。 Unityの2018からはUPM用のGUIが提供されるようになり、Unity2018.2からは ProjectビューにPackagesが表示されるようになりました。
以前のUnityでは.unitypackage
ファイルを利用してアセットのやり取りをしていました。
こちらはシンプルでわかりやすいのですが、Projectビューを散らかしてしまうので
アンインストールしたくなったときなどに面倒でした。
また、依存しているパッケージについては、まとめてパッケージにするか
手作業で配置するかしなければなりませんでした。
UPMではアセットはプロジェクトのAssets
ディレクトリとは
別に管理されるためProjectビューが散らかることはありません。
また、バージョン管理や依存関係の解決も行ってくれます。
依存関係の解決とは、あるパッケージをインストールしたときに依存するパッケージも
自動でインストールしてくれるものです。
aptやnpm、NuGetなどプラットフォームや言語、エコシステムごとに
さまざまなパッケージマネージャーが存在します。
UPMもそういったパッケージマネージャーのひとつです。
UPMの内部ではnpmを利用しているようです。
npmのpackage.jsonと共通する要素がいくつか見られます。
Unity 2018からはUPM用のGUIが用意されています。 Unityのメニューから「Window > Package Manager」を選ぶと UPMのウィンドウが開きます。
このプロジェクトにインストールされているパッケージの一覧と、 リポジトリに登録されているパッケージの一覧を見ることができます。
インストールされたパッケージの情報はプロジェクトルート/Packages/manifest.json
に
記録されています。
プロジェクト生成時にデフォルトでいくつかのパッケージはインストールされます。
manifest.json
の中身は次のようになっています。
{
"dependencies": {
"com.unity.ads": "2.0.8",
"com.unity.analytics": "2.0.16",
"com.unity.package-manager-ui": "1.9.11",
"com.unity.purchasing": "2.0.3",
"com.unity.textmeshpro": "1.2.4",
"com.unity.modules.ai": "1.0.0",
"com.unity.modules.animation": "1.0.0",
"com.unity.modules.assetbundle": "1.0.0",
"com.unity.modules.audio": "1.0.0",
"com.unity.modules.cloth": "1.0.0",
"com.unity.modules.director": "1.0.0",
"com.unity.modules.imageconversion": "1.0.0",
"com.unity.modules.imgui": "1.0.0",
"com.unity.modules.jsonserialize": "1.0.0",
"com.unity.modules.particlesystem": "1.0.0",
"com.unity.modules.physics": "1.0.0",
"com.unity.modules.physics2d": "1.0.0",
"com.unity.modules.screencapture": "1.0.0",
"com.unity.modules.terrain": "1.0.0",
"com.unity.modules.terrainphysics": "1.0.0",
"com.unity.modules.tilemap": "1.0.0",
"com.unity.modules.ui": "1.0.0",
"com.unity.modules.uielements": "1.0.0",
"com.unity.modules.umbra": "1.0.0",
"com.unity.modules.unityanalytics": "1.0.0",
"com.unity.modules.unitywebrequest": "1.0.0",
"com.unity.modules.unitywebrequestassetbundle": "1.0.0",
"com.unity.modules.unitywebrequestaudio": "1.0.0",
"com.unity.modules.unitywebrequesttexture": "1.0.0",
"com.unity.modules.unitywebrequestwww": "1.0.0",
"com.unity.modules.vehicles": "1.0.0",
"com.unity.modules.video": "1.0.0",
"com.unity.modules.vr": "1.0.0",
"com.unity.modules.wind": "1.0.0",
"com.unity.modules.xr": "1.0.0"
}
}
com.unity
で始まるのはUnity公式の提供するパッケージです。
Unityを構成するさまざまなパッケージがUPM経由でインストールされていることがわかります。
余談になりますが、Unityのアセットをnpmで管理しようという考え方は UPMより以前からあったようです。
unity-package-template/npm.md at master · shadowmint/unity-package-template
UPMができた今はわざわざnpmを使わなくてもUPMを使えばよいですね。
UPMのパッケージをインストールしてみる
試しにUnity公式のUPMのパッケージをインストールしてみましょう。
インストールにはGUIを利用する方法とmanifest.json
を編集する方法の2種類があります。
まずはGUI経由でインストールしてみます。 今回は「ProBuilder」をインストールしてみます。
「Window > Package Manager」でUPMのウィンドウを開きます。
「All」から「ProBuilder」を選択して「Install」ボタンを押します。
しばらくするとインストールが完了します。
「Tools > ProBuilder > Probuilder Window」でProBuilderのウィンドウを表示できます。
インストールをするとmanifest.json
が書き換えられます。
をインストールした後のプロジェクトルート/Packages/manifest.json
は
次のようになります。
{
"dependencies": {
"com.unity.ads": "2.0.8",
"com.unity.analytics": "2.0.16",
"com.unity.package-manager-ui": "1.9.11",
+ "com.unity.probuilder": "3.0.9",
"com.unity.purchasing": "2.0.3",
"com.unity.textmeshpro": "1.2.4",
"com.unity.modules.ai": "1.0.0",
"com.unity.modules.animation": "1.0.0",
"com.unity.modules.assetbundle": "1.0.0",
"com.unity.modules.audio": "1.0.0",
"com.unity.modules.cloth": "1.0.0",
"com.unity.modules.director": "1.0.0",
"com.unity.modules.imageconversion": "1.0.0",
"com.unity.modules.imgui": "1.0.0",
"com.unity.modules.jsonserialize": "1.0.0",
"com.unity.modules.particlesystem": "1.0.0",
"com.unity.modules.physics": "1.0.0",
"com.unity.modules.physics2d": "1.0.0",
"com.unity.modules.screencapture": "1.0.0",
"com.unity.modules.terrain": "1.0.0",
"com.unity.modules.terrainphysics": "1.0.0",
"com.unity.modules.tilemap": "1.0.0",
"com.unity.modules.ui": "1.0.0",
"com.unity.modules.uielements": "1.0.0",
"com.unity.modules.umbra": "1.0.0",
"com.unity.modules.unityanalytics": "1.0.0",
"com.unity.modules.unitywebrequest": "1.0.0",
"com.unity.modules.unitywebrequestassetbundle": "1.0.0",
"com.unity.modules.unitywebrequestaudio": "1.0.0",
"com.unity.modules.unitywebrequesttexture": "1.0.0",
"com.unity.modules.unitywebrequestwww": "1.0.0",
"com.unity.modules.vehicles": "1.0.0",
"com.unity.modules.video": "1.0.0",
"com.unity.modules.vr": "1.0.0",
"com.unity.modules.wind": "1.0.0",
"com.unity.modules.xr": "1.0.0"
}
}
さきほど追加した"com.unity.probuilder"
が載っています。
次にmanifest.json
を編集してインストールしてみます。
今度は「Post Processing」をインストールしてみます。
manifest.json
にを追加します。
{
"dependencies": {
"com.unity.ads": "2.0.8",
"com.unity.analytics": "2.0.16",
"com.unity.package-manager-ui": "1.9.11",
"com.unity.probuilder": "3.0.9",
"com.unity.purchasing": "2.0.3",
"com.unity.textmeshpro": "1.2.4",
"com.unity.modules.ai": "1.0.0",
"com.unity.modules.animation": "1.0.0",
"com.unity.modules.assetbundle": "1.0.0",
"com.unity.modules.audio": "1.0.0",
"com.unity.modules.cloth": "1.0.0",
"com.unity.modules.director": "1.0.0",
"com.unity.modules.imageconversion": "1.0.0",
"com.unity.modules.imgui": "1.0.0",
"com.unity.modules.jsonserialize": "1.0.0",
"com.unity.modules.particlesystem": "1.0.0",
"com.unity.modules.physics": "1.0.0",
"com.unity.modules.physics2d": "1.0.0",
"com.unity.modules.screencapture": "1.0.0",
"com.unity.modules.terrain": "1.0.0",
"com.unity.modules.terrainphysics": "1.0.0",
"com.unity.modules.tilemap": "1.0.0",
"com.unity.modules.ui": "1.0.0",
"com.unity.modules.uielements": "1.0.0",
"com.unity.modules.umbra": "1.0.0",
"com.unity.modules.unityanalytics": "1.0.0",
"com.unity.modules.unitywebrequest": "1.0.0",
"com.unity.modules.unitywebrequestassetbundle": "1.0.0",
"com.unity.modules.unitywebrequestaudio": "1.0.0",
"com.unity.modules.unitywebrequesttexture": "1.0.0",
"com.unity.modules.unitywebrequestwww": "1.0.0",
"com.unity.modules.vehicles": "1.0.0",
"com.unity.modules.video": "1.0.0",
"com.unity.modules.vr": "1.0.0",
"com.unity.modules.wind": "1.0.0",
- "com.unity.modules.xr": "1.0.0"
+ "com.unity.modules.xr": "1.0.0",
+ "com.unity.postprocessing": "2.0.12-preview"
}
}
manifest.json
を保存した後、UnityのPackage Managerのウィンドウを開きます。
無事インストールされました。
UPM向けのパッケージを作成する
この記事執筆時にはUPMの公式リポジトリへ個人のパッケージを登録する方法は用意されていません。 しかし、UPMではnpmと同様にローカルにパッケージを配置できます。
Hello Worldのパッケージの作成
まずはHello Worldを表示するスクリプトのパッケージを作ってみます。
パッケージは特定のファイルを置いたディレクトリになります。 今回のパッケージのディレクトリ構造は次のとおりです。
<root>
├── package.json
├── net.matcha-choco010.helloworld.asmdef
└── HelloWorld.cs
ここには書いていませんが、実際には.meta
ファイルも存在します。
適当なプロジェクトのAssets/
に適当なサブディレクトリを作って、
そこをパッケージのルートとしています。
package.json
に次のとおりに記述をして保存をします。
{
"name": "net.matcha-choco010.helloworld",
"displayName": "Hello World",
"version": "0.0.1",
"unity": "2018.2",
"description": "Hello World!"
}
name
はパッケージの名前です。
公式パッケージでドメイン名の逆順が使われているのでそれに倣います。
displayName
はPackage Managerウィンドウなどで表示される名前です。
version
はパッケージのバージョンです。
セマンティックバージョニングに従います。
unity
はパッケージのサポートするUnityのバージョンです。
description
はパッケージの簡単な説明になります。
HelloWorld.cs
には次のように記述します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace net.matcha_choco010.HelloWorld {
public class HelloWorld : MonoBehaviour {
void Start () {
Debug.Log ("Hello World!");
}
}
}
単純にコンソールに「Hello World」と表示するだけのスクリプトです。
ドメイン名を逆順にしたもので名前空間を切っています。 ハイフンの代わりにアンダースコアを使っています。
net.matcha-choco010.helloworld.asmdef
はAssembly Definitionファイルです。
「Create」から作成をします。
名前にはパッケージ名と同じドメイン名の逆順を使います。
これでHelloWorld.cs
はnet.matcha-choco010.helloworld.dll
に属します。
新しいUnityのプロジェクトを作り、このパッケージをインストールしてみます。
GUIでのインストールはローカルのパッケージのインストールに対応していないため、
manifest.json
を直接編集します。
2018/09/12追記:Unity 2018.3.0b1でGUIからのローカルパッケージのインストールに対応しました。
追記ここまで。
{
"dependencies": {
"com.unity.ads": "2.0.8",
"com.unity.analytics": "2.0.16",
"com.unity.package-manager-ui": "1.9.11",
"com.unity.purchasing": "2.0.3",
"com.unity.textmeshpro": "1.2.4",
"com.unity.modules.ai": "1.0.0",
"com.unity.modules.animation": "1.0.0",
"com.unity.modules.assetbundle": "1.0.0",
"com.unity.modules.audio": "1.0.0",
"com.unity.modules.cloth": "1.0.0",
"com.unity.modules.director": "1.0.0",
"com.unity.modules.imageconversion": "1.0.0",
"com.unity.modules.imgui": "1.0.0",
"com.unity.modules.jsonserialize": "1.0.0",
"com.unity.modules.particlesystem": "1.0.0",
"com.unity.modules.physics": "1.0.0",
"com.unity.modules.physics2d": "1.0.0",
"com.unity.modules.screencapture": "1.0.0",
"com.unity.modules.terrain": "1.0.0",
"com.unity.modules.terrainphysics": "1.0.0",
"com.unity.modules.tilemap": "1.0.0",
"com.unity.modules.ui": "1.0.0",
"com.unity.modules.uielements": "1.0.0",
"com.unity.modules.umbra": "1.0.0",
"com.unity.modules.unityanalytics": "1.0.0",
"com.unity.modules.unitywebrequest": "1.0.0",
"com.unity.modules.unitywebrequestassetbundle": "1.0.0",
"com.unity.modules.unitywebrequestaudio": "1.0.0",
"com.unity.modules.unitywebrequesttexture": "1.0.0",
"com.unity.modules.unitywebrequestwww": "1.0.0",
"com.unity.modules.vehicles": "1.0.0",
"com.unity.modules.video": "1.0.0",
"com.unity.modules.vr": "1.0.0",
"com.unity.modules.wind": "1.0.0",
- "com.unity.modules.xr": "1.0.0"
+ "com.unity.modules.xr": "1.0.0",
+ "net.matcha-choco010.helloworld": "file:/path/to/package"
}
}
"net.matcha-choco010.helloworld": "file:path/to/package"
が追加してあります。
file:
に続けてパスを記述することでローカルのパッケージをインストールできます。
manifest.json
に追記をして保存をし、Package Managerウィンドウを表示することで
インストールされます。
インストールしたスクリプトを使ってみます。 ProjectビューのPackagesから「Hello World > HelloWorld」を選び、適当なGameObjectにつけて実行します。
無事に実行できました。
依存パッケージのあるパッケージの作成
次は依存するパッケージのあるパッケージの作成を試してみます。 今回は「Post Processing」に依存したパッケージを作ります。
パッケージのディレクトリ構成は次のとおりです。
<root>
├── package.json
├── MyProfile1.asset
├── MyProfile2.asset
├── PostProcessCamera.prefab
└── PostProcessVolume.prefab
package.json
には次のとおりに記述します。
{
"name": "net.matcha-choco010.mypostprocessingprofiles",
"displayName": "My Post Processing Profiles",
"version": "0.0.1",
"unity": "2018.2",
"description": "My Post-processing profiles",
"dependencies": {
"com.unity.postprocessing": "2.0.12-preview"
}
}
name
がやたらと長いですね。
dependencies
に"com.unity.postprocessing": "2.0.12-preview"
を記述しています。
これでこのパッケージがPost Processingの2.0.12-preview
に依存することになりました。
Post Processingのプロファイルをパッケージに含めます。 Post Processingのプロファイルを作成し「MyProfile1」 「MyProfile2」という名前で保存します。
Post Process Layerを付けたカメラとPost Process Volumeをつけて設定を終えたGameObjectを prefab化してパッケージに格納します。
このパッケージを新しいプロジェクトから読み込んでみます。 このプロジェクトではまだPost Processingはインストールされていません。
manifest.json
に"net.matcha-choco010.mypostprocessingprofiles"
を追記します。
{
"dependencies": {
"com.unity.ads": "2.0.8",
"com.unity.analytics": "2.0.16",
"com.unity.package-manager-ui": "1.9.11",
"com.unity.purchasing": "2.0.3",
"com.unity.textmeshpro": "1.2.4",
"com.unity.modules.ai": "1.0.0",
"com.unity.modules.animation": "1.0.0",
"com.unity.modules.assetbundle": "1.0.0",
"com.unity.modules.audio": "1.0.0",
"com.unity.modules.cloth": "1.0.0",
"com.unity.modules.director": "1.0.0",
"com.unity.modules.imageconversion": "1.0.0",
"com.unity.modules.imgui": "1.0.0",
"com.unity.modules.jsonserialize": "1.0.0",
"com.unity.modules.particlesystem": "1.0.0",
"com.unity.modules.physics": "1.0.0",
"com.unity.modules.physics2d": "1.0.0",
"com.unity.modules.screencapture": "1.0.0",
"com.unity.modules.terrain": "1.0.0",
"com.unity.modules.terrainphysics": "1.0.0",
"com.unity.modules.tilemap": "1.0.0",
"com.unity.modules.ui": "1.0.0",
"com.unity.modules.uielements": "1.0.0",
"com.unity.modules.umbra": "1.0.0",
"com.unity.modules.unityanalytics": "1.0.0",
"com.unity.modules.unitywebrequest": "1.0.0",
"com.unity.modules.unitywebrequestassetbundle": "1.0.0",
"com.unity.modules.unitywebrequestaudio": "1.0.0",
"com.unity.modules.unitywebrequesttexture": "1.0.0",
"com.unity.modules.unitywebrequestwww": "1.0.0",
"com.unity.modules.vehicles": "1.0.0",
"com.unity.modules.video": "1.0.0",
"com.unity.modules.vr": "1.0.0",
"com.unity.modules.wind": "1.0.0",
"com.unity.modules.xr": "1.0.0",
- "net.matcha-choco010.helloworld": "file:/path/to/package"
+ "net.matcha-choco010.helloworld": "file:/path/to/package",
+ "net.matcha-choco010.mypostprocessingprofiles": "file:/path/to/package"
}
}
Package Managerウィンドウを最読み込みしてインストールを走らせます。
manifest.json
には"net.matcha-choco010.mypostprocessingprofiles"
しか
追加していませんが、裏で自動的にPost Processingがインストールされています。
一見するとPackage ManagerウィンドウにもProjectビューのPackagesにも PostProcessingは追加されていないように見えます。
試しにprefabを使ってみましょう。 「Packages > My Post Processing Profiles」から「PostProcessCamera」と 「PostProcessVolume」のprefabをシーンにドラッグしてインスタンス化します。
すると問題なく実行できることが確認できます。
どうやらdependencies
に追加したパッケージは直接見えないところに配置されているようです。
シングルトンのMonoBehaviourのパッケージの作成
npmでは非常に小さなライブラリと呼べないくらいのサイズのプログラムが リポジトリにパッケージとして登録されています。 たとえば、文字列を指定長になるまで左側にスペースを詰める関数だけのパッケージなど。 このくらいのプログラムならばプログラマは誰でも書けます。 しかしnpmコミュニティの人間は、車輪の再発明を嫌い、 また自分の実装よりもOSSで広く検証されている実装を使うために このような小さなパッケージを大量に利用します。
依存関係を自動で解決してくれるパッケージマネージャーがUnityに搭載されたことで、 Unityでもより小さなアセットが広く使われるようになるかもしれません。 たとえば、多くの人が一度は実装したことがあるだろうシングルトンのMonoBehaviourを ひとつだけ含むパッケージ等は便利でしょう。 というわけで上述のパッケージを作ってみます。
余談ですが上に書いたライブラリはleft-padというライブラリで、 作者によって削除されて依存していた大量のパッケージが壊れて問題になりました。 Unityのリポジトリではそういった問題が起きないように運用されていくのだと思いますが……。
パッケージのディレクトリ構成は次のようにします。
<root>
├── package.json
├── net.matcha-choco010.singletonmonobehaviour.asmdef
└── SingletonMonoBehaviour.cs
package.json
は次のように記述します。
{
"name": "net.matcha-choco010.singletonmonobehaviour",
"displayName": "Singleton MonoBehavior",
"version": "0.0.1",
"unity": "2018.2",
"description": "base class for singleton MonoBehaviour"
}
Assets/SingletonMonoBehaviour.cs
には次のとおりに記述します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace net.matcha_choco010.SingletonMonoBehaviour {
public class SingletonMonoBehaviour<T> : MonoBehaviour where T : SingletonMonoBehaviour<T> {
private static T instance;
public static T Instance {
get {
if (instance == null) {
instance = (T) FindObjectOfType (typeof (T));
if (instance == null) {
Debug.LogError ($"{typeof(T)} is nothing");
}
}
return instance;
}
}
protected void Awake () {
if (this != Instance) {
Debug.LogError ($"{typeof(T)} is duplicated");
}
}
}
}
C# 6の機能を利用しているので、このパッケージを利用するには.Net 4.xにする必要があります。
このパッケージをインストールして使ってみます。
インストールする側のmanifest.json
を次のように編集します。
{
"dependencies": {
"com.unity.ads": "2.0.8",
"com.unity.analytics": "2.0.16",
"com.unity.package-manager-ui": "1.9.11",
"com.unity.purchasing": "2.0.3",
"com.unity.textmeshpro": "1.2.4",
"com.unity.modules.ai": "1.0.0",
"com.unity.modules.animation": "1.0.0",
"com.unity.modules.assetbundle": "1.0.0",
"com.unity.modules.audio": "1.0.0",
"com.unity.modules.cloth": "1.0.0",
"com.unity.modules.director": "1.0.0",
"com.unity.modules.imageconversion": "1.0.0",
"com.unity.modules.imgui": "1.0.0",
"com.unity.modules.jsonserialize": "1.0.0",
"com.unity.modules.particlesystem": "1.0.0",
"com.unity.modules.physics": "1.0.0",
"com.unity.modules.physics2d": "1.0.0",
"com.unity.modules.screencapture": "1.0.0",
"com.unity.modules.terrain": "1.0.0",
"com.unity.modules.terrainphysics": "1.0.0",
"com.unity.modules.tilemap": "1.0.0",
"com.unity.modules.ui": "1.0.0",
"com.unity.modules.uielements": "1.0.0",
"com.unity.modules.umbra": "1.0.0",
"com.unity.modules.unityanalytics": "1.0.0",
"com.unity.modules.unitywebrequest": "1.0.0",
"com.unity.modules.unitywebrequestassetbundle": "1.0.0",
"com.unity.modules.unitywebrequestaudio": "1.0.0",
"com.unity.modules.unitywebrequesttexture": "1.0.0",
"com.unity.modules.unitywebrequestwww": "1.0.0",
"com.unity.modules.vehicles": "1.0.0",
"com.unity.modules.video": "1.0.0",
"com.unity.modules.vr": "1.0.0",
"com.unity.modules.wind": "1.0.0",
- "com.unity.modules.xr": "1.0.0"
+ "com.unity.modules.xr": "1.0.0",
+ "net.matcha-choco010.singletonmonobehaviour": "file:/path/to/package"
}
}
シングルトンにしたいスクリプトでSingletonMonoBehaviour
を継承して使います。
using net.matcha_choco010.SingletonMonoBehaviour;
public class SingletonTest : SingletonMonoBehaviour<SingletonTest>
{
...
}
このスクリプトをアタッチしたオブジェクトをシーンにひとつ配置します。 シーンに存在しないときやシーンに2つ以上存在するときは コンソールウィンドウにエラーログを出します。 自動で配置したり削除したりは行いません。 また、シーンをまたぐことも考えていません。
継承した先でAwake
を使いたいときはbase
を呼び出すのを忘れないようにします。
using net.matcha_choco010.SingletonMonoBehaviour;
public class SingletonTest : SingletonMonoBehaviour<SingletonTest>
{
void Awake()
{
base.Awake();
...
}
}
Git URL
npmではパッケージのURLにGitを指定できました。 UPMではまだこの機能は使えないようですが、将来的にGit URLのサポートも予定されているようです。 GitのURLからパッケージの読み込みができるようになれば、 GitHubにパッケージを配置するだけで使えるようになるので便利ですね。
UnityのGitリポジトリはプロジェクト全体が入っているので、
Assets
内のサブディレクトリのパッケージを指定して
インストールとかもできるようになっていると嬉しいのですが。
おわりに
Unity Package Managerを触ってみました。 公式リポジトリはまだユーザのパッケージのアップロードはできないようですが、 ローカルのパッケージのインストールは現時点でも可能です。 また将来的にはGitサーバーからのインストールもできるようになるようです。 Gitからのインストールができるようになったら、今回作ったSingletonMonoBehaviourのような よく使うプログラムをパッケージ化してGitHubにでも上げておくと便利になってよいですね。
この記事を書く上で参考にしたWebページを挙げておきます。