ScriptableObjectの基礎
目的
このページでは、UnityにおけるScriptableObjectの基礎概念を説明します。これらの概念を理解することで、Reactive SOがなぜこのように設計されているかがわかります。
ScriptableObjectとは
ScriptableObjectは、プロジェクト内のアセットとして存在するUnityのデータコンテナです。GameObjectにアタッチされるMonoBehaviourとは異なり、ScriptableObjectはシーンから独立して存在します。
[CreateAssetMenu(fileName = "PlayerStats", menuName = "Game/Player Stats")]
public class PlayerStats : ScriptableObject
{
public int maxHealth = 100;
public float moveSpeed = 5f;
}
| 特性 | 説明 |
|---|---|
| アセットベース | Projectウィンドウで作成、.assetファイルとして保存 |
| 永続的 | シーンの外に存在し、シーンロードで破棄されない |
| 共有 | 複数のスクリプトが同じアセットを参照可能 |
| シリアライズ可能 | データがInspectorで保存・表示される |
なぜScriptableObjectを使うのか
1. メモリ効率
ScriptableObjectを使用すると、すべての参照が同じインスタンスを指します。MonoBehaviourのデータと比較してみましょう。
従来方式: 100体の敵 × 10 KBのデータ = 1 MBのメモリ
ScriptableObject: 100体の敵 × 1つの共有アセット = 10 KBのメモリ
2. シーン非依存
ScriptableObjectのデータはシーンロードを跨いで永続します。
| コンポーネント | シーンロード時の動作 |
|---|---|
| GameObject | 破棄(DontDestroyOnLoad以外) |
| MonoBehaviour | GameObjectと共に破棄 |
| ScriptableObjectデータ | 永続(条件付き、下記注意参照) |
重要な注意: SOのアンロードについて ScriptableObjectはシーン遷移時にアクティブなオブジェクトから参照されていない場合、Unityによってメモリからアンロードされる可能性があります。アンロードされると、すべてのランタイムデータが失われます。これを防ぐには、
DontDestroyOnLoadマネージャーなどの永続オブジェクトからSOアセットを参照するようにしてください。
sequenceDiagram
participant SO as ScriptableObject<br/>(プロジェクトアセット)
participant S1 as Scene 1
participant S2 as Scene 2
Note over SO: アプリ起動時にロード
rect rgb(200, 230, 200)
Note over S1: Scene 1 アクティブ
S1->>SO: 値を更新 (Health = 80)
SO-->>S1: 値を提供
end
S1->>S1: シーン破棄
Note over SO: データは永続 ✓<br/>Health = 80
rect rgb(200, 200, 230)
Note over S2: Scene 2 アクティブ
S2->>SO: 値を読み取り
SO-->>S2: Health = 80 (維持)
end
3. 疎結合アーキテクチャ
システムは直接参照ではなく、ScriptableObjectアセットを通じて通信します。
flowchart LR
subgraph Project["プロジェクトアセット"]
SO[("PlayerHealth<br>(ScriptableObject)")]
end
subgraph Scene["シーンオブジェクト"]
A[Player]
B[HealthBar UI]
C[Enemy AI]
end
A -->|読み書き| SO
B -->|読み取り| SO
C -->|読み取り| SO
PlayerスクリプトがPlayerHealth.Valueを変更すると、HealthBar UIとEnemy AIは即座に新しい値を参照できます。互いへの直接参照は不要です。
原点 - Unite Austin 2017
Reactive SOは、Ryan HippleがUnite Austin 2017で発表した講演「Game Architecture with Scriptable Objects」に着想を得ています。
講演で示された核心原則
| 原則 | 説明 |
|---|---|
| モジュール性 | システムが互いに直接依存しない |
| 編集容易性 | デザイナーがランタイムで値を調整可能 |
| デバッグ容易性 | 各部品を独立してテスト可能 |
導入されたパターン
この講演では、Reactive SOの基盤となるいくつかのパターンが紹介されました。
- Variables - ScriptableObjectアセットとしての共有データ(FloatVariable、IntVariableなど)
- Events - GameEventアセットによる疎結合通信
- Runtime Sets - シングルトンを使わないオブジェクト追跡
この講演は、UnityのYouTubeチャンネルで最も視聴されたUniteカンファレンス動画です。
リソース
ScriptableObjectのライフサイクル
エディタ内
| 操作 | ディスクに保存されるか |
|---|---|
| Inspectorでの変更 | はい(自動) |
| スクリプトでの変更 | いいえ(EditorUtility.SetDirty()の呼び出しが必要) |
| Play Mode中の変更 | いいえ(メモリ内のみ、Play Mode終了時に失われる) |
ビルド内
ScriptableObjectアセットはランタイムでは読み取り専用です。ゲームプレイ中の変更はアプリケーション終了時に失われます。
永続的なデータ保存には、PlayerPrefs、JSONファイル、またはデータベースへのシリアライズを使用してください。
Unity公式リソース
ドキュメント
チュートリアル
- Unity Learn:Introduction to Scriptable Objects(65分)
- Three ways to architect your game with ScriptableObjects
- Separate Game Data and Logic with ScriptableObjects
関連オープンソースプロジェクト
| プロジェクト | 説明 |
|---|---|
| Unity Atoms | Variables、Eventsなどを含むScriptableObjectアーキテクチャのフル実装 |
| ScriptableObject-Architecture | Ryan Hippleのパターンに基づく別の実装 |
まとめ
| 概念 | ポイント |
|---|---|
| ScriptableObject | プロジェクトアセットとして存在するデータコンテナ |
| 共有インスタンス | すべての参照が同じオブジェクトを指す |
| シーン永続性 | データがシーンロードを跨いで残る |
| 疎結合 | システムがアセットを通じて通信、直接参照不要 |
次のステップ
- アーキテクチャパターン - 各Reactive SOツールの使い分けを学ぶ
- Event Channelsガイド - イベントの使用を開始
- Variablesガイド - システム間で状態を共有