Unityプロジェクトにおける色や文字スタイルを一元的に管理するためのシステムです。
アプリケーション開発では一般的に、一つの色を複数の箇所に適用します。
以下はボタンの背景色やアイコンの色、アウトラインに同じ青色を適用している例です。
次に、この色を青色から緑色に変更することを考えます。
Unityでは色の値はPrefabやSceneにシリアライズされるので、これらすべての値を一つ一つ変更する必要があります。
当然ながら、この作業量はプロジェクトの規模に応じて増加します。
uPaletteを使えば色を一元管理することでこのような変更を一括で適用することができます。
またuPaletteでは、色だけではなく文字スタイルやグラデーションを管理することもできます。
さらにテーマ機能を使えば、色や文字スタイルのセットをテーマとして保存できます。
アクティブなテーマを切り替えることでそのテーマに応じた色や文字スタイルが反映されます。
Unity2020.1 以上
インストールは以下の手順で行います。
- Window > Package Manager を選択
- 「+」ボタン > Add package from git URL を選択
- 以下のURLを入力してインストール
バージョンを指定したい場合には以下のようにURLの末尾にバージョンを付与します。
バージョンの更新もインストールと同様の手順で実行できます。
No 'git' executable was found. Please install Git on your system and restart Unity
のようなメッセージが出た場合、マシンにGitをセットアップする必要がある点にご注意ください。
uPaletteを使うにはまずWindow > uPalette > Palette Editor
からPalette Editorを開きます。
Palette Editorを開くと下図のようなウィンドウが表示されます。
次に、中央のCreate Palette Store
ボタンを押下することでPalette Storeアセットを作成します。
Palette StoreはuPaletteで扱うデータを保持するためのアセットです。
プロジェクト内の任意の場所に配置できますが、ランタイムで使うアセットなのでEditorフォルダやStreamingAssetsフォルダ配下には置かないよう注意してください。
Palette Storeアセットを作成するとPalette Editorは以下のような表示に切り替わります。
uPaletteでは、色や文字スタイルの設定のことをエントリと呼びます。
Palette Editorの右上にある「+」ボタンを押下することで、エントリを追加することができます。
エントリ名をクリックすることでリネームすることができます。
また、エントリの削除は右クリックから行えます。
要素をドラッグすると順番を並び替えることもできます。
作成した色や文字スタイルをコンポーネントに反映するには、対象のGameObjectを選択した状態で対象のエントリのApplyボタンを押下します。
すると適用可能なコンポーネントとプロパティの名前がリストアップされるので、適用したいものを選択します。
これで、エントリとプロパティが同期されます。
同期されているエントリの値が変化するとプロパティが自動的に書き変わります。
この時、対象のGameObjectにはSynchronizerと呼ばれるコンポーネントがアタッチされています。
このコンポーネントのInspectorからエントリを切り替えることもできます。
またこのコンポーネントをデタッチすると、エントリとの同期が解除されます。
なお、Prefabに対してエントリを適用した場合には、通常のPrefabワークフローと同様、Prefabにはシリアライズされていない状態となります。
シリアライズを行うには右クリックメニューなどからApplyしてください。
エントリの右クリックメニューからHighlightを選択すると、同期中のGameObjectをハイライト(選択)できます。
ここまで、uPaletteで色を管理する方法について説明しました。
uPaletteには色の他にも文字スタイルやグラデーションといったパレットの種類が存在します。
PaletteEditorの左上のドロップダウンメニューから、パレットの種類を切り替えることができます。
各ドロップダウンメニューの説明は以下の通りです。
名前 | 説明 |
---|---|
Color | 色を管理するために使用します。 |
Gradient | グラデーションを管理するために使用します。 |
Character Style | uGUI Textの文字スタイルを管理するために使用します。 |
Character Style TMP | Text Mesh Proの文字スタイルを管理するために使用します。 |
エントリ名をスラッシュで区切ると、エントリをフォルダ分けすることができます。
フォルダ分けされたエントリはPalette Editor上で下図のように階層表示されます。
フォルダ分けするかどうかの設定は、以下のメニューから変更することができます。
- Project Settings > uPalette > Use Folder View in Palette Editor
フォルダ分けをしない場合には全ての要素がフラットに表示され、ドラッグ&ドロップで並び替えられます。
フォルダ分けをする場合には名前順に並び替えられます。
テーマ機能を使うと、エントリのセットを「テーマ」として保存できます。
テーマは複数保存でき、それを切り替えることでテーマに応じた色や文字スタイルを反映することができます。
テーマを作成するには、Window > uPalette > Theme Editor
からTheme Editorを開きます。
デフォルトでは、Defaultという名前のテーマが存在しており、左上の「+」ボタンを押下することで新しいテーマを作成できます。
Entry Editorと同様の操作でリネーム、削除、並び替えなどができます。
テーマを追加すると、Palette Editorにそのテーマのエントリを設定するためのカラムが追加されます。
これを編集することでそのテーマに応じた値を設定できます。
なおテーマはパレットの種類ごとに設定できます。
パレットの種類はTheme Editor左上のドロップダウンから変更できます。
Theme EditorからActivateボタンを押下することでテーマを切り替えることができます。
テーマを切り替えると、そのテーマのエントリの値が即座に反映されます。
ランタイムにおけるテーマの切り替えにはPalette
クラスのSetActiveTheme()
を使用します。
以下は自動生成したテーマのEnumを使用して、ColorPalette
のテーマを切り替えるスクリプトの例です。
using System;
using UnityEngine;
using uPalette.Generated;
using uPalette.Runtime.Core;
public class Example : MonoBehaviour
{
public void OnGUI()
{
foreach (ColorTheme colorTheme in Enum.GetValues(typeof(ColorTheme)))
if (GUILayout.Button(colorTheme.ToString()))
{
var colorPalette = PaletteStore.Instance.ColorPalette;
colorPalette.SetActiveTheme(colorTheme.ToThemeId());
}
}
}
これを適当なGameObjectにアタッチして再生すると、以下のようにテーマを切り替えることができます。
上述の通り、Synchronizerコンポーネントは指定したエントリの値が変更されたときに対象のプロパティにその値を反映します。
これに対し、以下のSynchronize Eventコンポーネントを使用すると、値の変更通知だけをイベントとして受け取ることができます。
- Color Synchronize Event
- Gradient Synchronize Event
- Character Style Synchronize Event
- Character Style TMP Synchronize Event
使用するには上記のコンポーネントをアタッチし、値が変わったときの処理をUnityEventに設定します。
スクリプトからuPaletteを操作する場合、テーマやエントリの情報にアクセスするためのスクリプトを自動生成しておくと便利です。
Project Settings > uPalette > Name Enums File Generation
をWhen Window Loses Focus
に設定すると、Palette EditorやTheme Editorからフォーカスが外れた際にこのファイルが自動生成されます。
Name Enums File Location
にフォルダを指定するとそのフォルダに生成されます。未指定の場合にはAssetsフォルダ直下に生成されます。
以下のようなEnumが生成されます。
using System;
namespace uPalette.Generated
{
public enum ColorEntry
{
Red,
Green,
Blue,
}
}
またこのEnumの拡張メソッドとして定義されているToEntryId()
を使用すると、当該エントリのIDを取得することができます。
using uPalette.Generated;
public class Example
{
private void Foo()
{
ColorEntry.Red.ToEntryId();
}
}
他の種類のエントリやテーマについても同様にして使用できます。
なお、プロジェクト設定のContains Folder Name to Name Enums
にチェックを入れると、フォルダ名もEnumに含められます。
このチェックを外すと、フォルダ名を除外した名前がEnumに使用されます。
スクリプトからエントリの値を取得したり監視するには、以下のように各PaletteのGetActiveValue()
を使います。
IReadOnlyObservableProperty<T>
が返されるので、現在の値を取得する場合にはこれのValue
プロパティを使用します。
テーマが変更された時など、値の変更を監視したい場合にはSubscribe()
を使用して値の変更を監視することもできます。
using System;
using UnityEngine;
using uPalette.Generated;
using uPalette.Runtime.Core;
public class Example : MonoBehaviour
{
private void Start()
{
// Get the color palette.
var colorPalette = PaletteStore.Instance.ColorPalette;
// Get the color entry id from the auto-generated ColorEntry enum.
var targetColorEntryId = ColorEntry.KeyColor1.ToEntryId();
var colorProperty = colorPalette.GetActiveValue(targetColorEntryId);
// If you want to get the current value, use the Value property.
var targetValue = colorProperty.Value;
// If you want to get the value when the theme is changed, subscribe the property.
IObserver<Color> observer;
var disposable = colorProperty.Subscribe(observer);
}
}
デフォルトでは uPalette のパレットデータは PreloadedAssets に登録され、ランタイムで自動的に読み込まれます。
これはパレットのデータがアプリ内に組み込まれることを意味します。
パレットデータをアセットバンドル化する場合など、PreloadedAssets に登録したくない場合には以下の設定を行います。
- Project Settings > uPalette > Automatic Runtime Data Loading のチェックを外す
この設定を行うと、uPalette のパレットデータは PreloadedAssets から削除されます。
この場合 PaletteStore のロードを手動で行う必要があります。
ロードされた PaletteStore は PaletteStore.Instance に自動的に登録されます。
uPalette を使用する GUI を読み込む前にロードする必要がある点に注意してください。
// You must load the PaletteStore manually before loading GUIs that use uPalette.
var _ = Resources.Load<PaletteStore>("PaletteStore");
なお、エディタでは常に AssetDatabase を通してロードされた PaletteStore が使用されます。
以下のようにPaletteStoreから各パレットを取得することで、uPaletteのデータをスクリプトから編集することができます。
PaletteStoreはScriptableObject
なので、編集した後には必ずDirtyフラグを立ててUnityに編集したことを知らせる必要がある点にご注意ください。
// Get PaletteStore.
var paletteStore = PaletteStore.Instance;
// Get each palette.
var colorPalette = PaletteStore.Instance.ColorPalette;
var gradientPalette = PaletteStore.Instance.GradientPalette;
var characterStylePalette = PaletteStore.Instance.CharacterStylePalette;
var characterStyleTMPPalette = PaletteStore.Instance.CharacterStyleTMPPalette;
// Set the dirty flag after editing.
EditorUtility.SetDirty(paletteStore);
// Save assets if you need.
AssetDatabase.SaveAssets();
uPaletteには標準的なコンポーネントのプロパティに値を反映するためのSynchronizerがあらかじめ用意されています。
これとは別に、独自のコンポーネントに値を反映するためのSynchronizerを作成することもできます。
例として、グラデーションをプロパティとして持つ独自のコンポーネントを考えます。
using UnityEngine;
public class SampleGradient : MonoBehaviour
{
[SerializeField] private Gradient _gradient;
public Gradient Gradient
{
get => _gradient;
set => _gradient = value;
}
}
このプロパティに値を反映するためのSynchronizerは以下のように作成できます。
using UnityEngine;
using uPalette.Runtime.Core.Synchronizer.Gradient;
[AddComponentMenu("")]
[DisallowMultipleComponent]
[RequireComponent(typeof(SampleGradient))]
[GradientSynchronizer(typeof(SampleGradient), "Gradient")]
public sealed class GraphicColorSynchronizer : GradientSynchronizer<SampleGradient>
{
protected override Gradient GetValue()
{
return _component.Gradient;
}
protected override void SetValue(Gradient value)
{
_component.Gradient = value;
}
}
対象のエントリが見つからなかった場合、エラーログを出したい場合もあれば、それを無視したい場合もあるでしょう。
Project Settings > uPalette > Missing Entry Error
から、エントリが見つからなかった時の挙動を設定できます。
選択肢は以下の通りです。
名前 | 説明 |
---|---|
None | 何もしない。 |
Warning | 警告ログを出力する。 |
Error | エラーログを出力する。 |
Exception | 例外をスローする。 |
uPaletteに標準で実装されているSynchronizerは以下の通りです。
エントリの種類 | 対象クラス名 | 対象プロパティ名 |
---|---|---|
Color | UnityEngine.UI.Graphic | color |
Color | UnityEngine.UI.Outline | effectColor |
Color | UnityEngine.UI.Selectable | colors.normalColor |
Color | UnityEngine.UI.Selectable | colors.selectedColor |
Color | UnityEngine.UI.Selectable | colors.pressedColor |
Color | UnityEngine.UI.Selectable | colors.disabledColor |
Color | UnityEngine.UI.Selectable | colors.highlightedColor |
Color | UnityEngine.UI.InputField | caretColor |
Color | UnityEngine.UI.InputField | selectionColor |
Color | TMPro.TMP_InputField | caretColor |
Color | TMPro.TMP_InputField | selectionColor |
CharacterStyle | UnityEngine.UI.Text | font / fontStyle / fontSize / lineSpacing |
CharacterStyleTMP | TMPro.TextMeshProUGUI | font / fontStyle / fontSize / enableAutoSizing / characterSpacing / wordSpacing / lineSpacing / paragraphSpacing |
Unityでは、各コンポーネントに設定されている色やテキストスタイルなどの情報はそのまま値としてシリアライズされます。
したがって、これら変更したときにはこのシリアライズされた値を書き換えるべきです。
しかしこれでは、エントリを変更した際に多くのSceneやPrefabに変更が加わってしまいます。
そこでuPaletteでは以下のルールに従って色を反映しています。
- uPaletteのエントリは値ではなくIDとしてシリアライズ
- Edit ModeではOnEnable時にこのエントリを反映・変更を監視する
- Play ModeではStart()のタイミングでエントリを反映する
また、Edit ModeでSceneを開いたときに変更が加わらないよう、シリアライズされたIDのエントリを反映するときにはDirtyフラグを立てない実装にしています。
uPaletteをバージョン1からバージョン2にバージョンアップする上で、データ構造やデータの置き場所を大きく変更しました。
バージョン1を使用していた方は、Palette Storeを作成する前にProject Settingsから以下のボタンを押下することでバージョン2にデータを移行できます。
ボタンを押下するとPalette Storeアセットの保存パネルが表示されるので、任意の場所に保存してください。
ただしこのアセットはランタイムで使うアセットなので、EditorフォルダやStreamingAssetsフォルダ配下には置かないよう注意してください。
デモシーンは以下の手順で再生できます。
- リポジトリをクローンする
- 以下のシーンを開いて再生
本ソフトウェアはMITライセンスで公開しています。ライセンスの範囲内で自由に使っていただけますが、使用の際は以下の著作権表示とライセンス表示が必須となります。
また、本ドキュメントの目次は以下のソフトウェアを使用して作成されています。
toc-generatorのライセンスの詳細は Third Party Notices.md を参照してください。