はじめに
この記事は Unity Advent Calendar 2022 (その1) 16日目の記事になります。
前日の記事は @anidomanta さんの 「Tilemapを使ってキャラクターを歩かせたりジャンプさせたりする」 でした。
本稿では自分が個人で開発している「Unityのレイヤーを実質無限に使えるようにする」ライブラリを紹介します。
まだ開発途中の v0.1.0
で今後破壊的な変更あり&実践未投入なので、不具合など見つけたらTwitter(@su10_dev)かGitHubリポジトリのIssueまでお願いします🙏
モチベーション
Unityにはレイヤーの機能があり、レイヤーを使用することで以下のようなことができます。
- 当たり判定の設定・管理
- オブジェクトを描画する/しないの切り替え(
Camera
の設定)およびグループ化 - ポストプロセシングを適用するオブジェクトの切り替えおよびグループ化
少なくともUnity2021.3で利用可能なレイヤーは最大32個で、そのうち5個( Default
, TransparentFX
, Ignore Raycast
, Water
, UI
)がUnityによって予約・使用されています。
Unityのレイヤー名設定画面とPhysicsのコリジョン設定
この制限は小規模な開発であれば問題ありませんが、中規模以上の開発やミニゲーム集のようなゲームでレイヤーを使おうとしたときに大きな障害となります。
例えば「6~20は演出(デザイナー)、21〜30は当たり判定(エンジニア)で使用する」みたいなルールで辛い経験をした結果、「今後はレイヤーを使用しない」という判断をするのも割とよくあることだと思います。
また、なるべくレイヤーを使わないために使えるAPIとして Physics.IgnoreCollision() というものもありますが、いちいちすべてのコリジョンに対して呼び出すのは現実的ではありません(参考:レイヤーを使わずに衝突判定をなくす方法)。
Layer2は
- 個別のアセットとしてレイヤー設定(レイヤー名・コリジョンマトリクス)をまとめる
- コンテキストに応じて複数のレイヤー設定を切り替える
ことで32個の上限を取り払い、レイヤーを実質無限に使えるようにします。
Layer2のレイヤー設定アセット
イメージとしてはUnityのレイヤー設定の上に一つ間接化のレイヤーを敷く感じです。
レイヤー設定を間接化することは単にレイヤー数の制限を取り払うだけでなく、設定への依存をコンテキスト内に局所化することでレイヤーの負債化・硬直化を緩和する効果があります。
簡単な実装解説
コリジョンマトリクスの設定切り替えは通常のUnityのAPI呼び出しになっていて、
- 3Dの場合: Physics.IgnoreLayerCollision() をコール
- 2Dの場合: Physics2D.IgnoreLayerCollision() をコール
しているだけです。
レイヤー名は動的に変更するAPIが提供されていないので、レイヤー名を参照したい場合は LayerMask
の代わりに Layer2Mask
を使用する必要があります。
インストール
- 対応バージョン:Unity2021.3以降
- Package Managerを開く
- [+▼] ボタンを押して
Add package from git URL...
を選択 - 以下を入力してEnter
- https://github.com/su10/Layer2.git#upm
- 個別のバージョンを指定する場合は https://github.com/su10/Layer2.git#upm/v0.1.0 のようにする
使い方
設定ファイルを作成する
デフォルトの状態だと設定ファイルを作成できないので、必要に応じて Samples
の Create Asset Menu
をインポートします。
インポートが完了したら、
Assets
→ Create
→ Layer2
→ Layer Settings
で設定ファイルが生成されます。
Layer2のレイヤー設定アセット
ちなみに
Create Asset Menu
でインポートされるものは以下の小さなスクリプト一つです。
using UnityEngine;
namespace Jagapippi.Layer2
{
[CreateAssetMenu(menuName = "Layer2/Layer Setting")]
public partial class LayerSettingAsset
{
}
}
設定アセットを作成するメニューのパスを変更したい場合は "Layer2/Layer Setting"
のところを適宜変更してください。
レイヤーは設定アセット一つにつき32個まで定義できます。
デフォルトの状態だと自身で名前を決められるのは6~31までの25個までですが、編集不可になっている Builtin Layer
はInspectorをDebugモードにすると強制的に変更できます(使用は自己責任で)。
Collision Matrixの設定は3D/2D両方対応していますが、UnityのAPIとの兼ね合いで一つの設定に3Dと2Dの設定がどちらも含まれる形になっています。
シーンやミニゲーム毎といった適当なコンテキストにつき一つの設定を作って使うイメージです。
レイヤーは並び替え可能ですが、並び替えてもシーンやプレハブにシリアライズされているレイヤーの値は変更されないので、すでに使用されているレイヤーの並び順を変更するともろもろ壊れてしまうことに注意してください。
レイヤー設定を切り替える
作成したレイヤー設定は LayerSettingSelection
クラスから適用できます。
現状 LayerSettingSelection
クラスは internal
なので、Samplesの LayerManager
プレハブを使用することを強くおすすめします。
また、Unityエディタ上では設定ファイルを選択したときのInspectorのヘッダーから以下の操作が行えます。
- 現在適用されているレイヤー設定の確認
- 設定を選択(エディタ用,非再生時のみ)
- 設定を適用
- 設定をコピー/ペースト
- 設定をProject Settingsからロード
ボタンのツールチップにも説明が表示されますが、非再生時にレイヤー設定を適用( Apply
ボタン)すると以下のファイルに変更が走ります。
- DynamicsManager.asset
- Physics2DSettings.asset
- TagManager.asset
レイヤー設定を切り替えるたびにファイルが変更されてほしくない場合は選択( Select
ボタン)を使用してください。
選択/適用されているレイヤー設定は GameObject
を選択したときのInspectorのヘッダーのレイヤー表示に反映されます(Layer2のドロップダウンが追加される)。
その他の機能
デフォルトのGUIシステムをUI Toolkitに変更
2022以前のUnityエディタにLayer2を導入すると、Inspectorの表示に使われるデフォルトのGUIシステムがIMGUIからUI Toolkitに切り替わります。
これによって既存のカスタムエディタに問題が起きた場合、Scripting Define Symbolsに LAYER2_DISABLE_DEFAULT_CUSTOM_EDITOR
を追加することでデフォルトのGUIシステムをIMGUIに戻すことができます。
その場合はLayer2のクラス・コンポーネントが正しく表示されなくなるので、自分でGUIの描画処理を書く必要があります。
Unity2022からはそもそもデフォルトでUI Toolkitが使用されるので、Unity2022を使用していれば問題は起きないはずです。
LayerMask
から Layer2Mask
への移行
Layer2を導入した場合、 LayerMask
は使わずに Layer2Mask
を使う必要があります。
プロジェクトの途中でLayer2を導入した場合は LayerMask
記述部分を機械的に Layer2Mask
で置き換えればOKです。
Camera
のInspector表示の拡張
Camera
コンポーネントの最上部にLayer2用のレイヤー選択ドロップボックスが追加されます。
既存のカスタムエディタとコンフリクトする場合、Scripting Define Symbolsに LAYER2_DISABLE_CAMERA_EDITOR_OVERRIDE
を追加することで処理を無効化できます。
TODO
- サンプルを充実させる
- Harmonyを導入してUIをUnityエディタと統合する
-
GameObject
選択時のヘッダーを簡素化 -
Camera
のレイヤー表示を簡素化 -
Layer2Mask
をstatic
化
-
- 配布形態の追加
- OpenUPM対応
- unitypackage生成&リリースページ作成
- GitHub Actionsでリリースの自動化
さいごに
私事で恐縮ですが、最近父親になりました。
育児って難しいですね。エンジニア的にいろいろ自動化・楽していきたいです。
◆ ◆ ◆
明日の Unity Advent Calendar 2022 は @yahagi_day さんの 「UnityをGithubActionsでビルドする」 です。