トラブルシューティング
目的
このページでは、Reactive SOに関するよくある問題、既知の制限事項、よくある質問について説明します。
よくある問題
イベントが発火しない
症状: RaiseEvent()を呼び出しても何も起きない。
診断フローチャート
graph TB
A["イベントが発火しない"] --> B{"Event Channel<br/>割り当て済み?"}
B -->|NO| C["Inspectorで<br/>アセットを設定"]
B -->|YES| D{"?.RaiseEvent()<br/>を使用?"}
D -->|NO| E["null条件演算子<br/>を追加"]
D -->|YES| F["Event Monitorを開く"]
F --> G{"イベントが<br/>表示される?"}
G -->|NO| H["Publisher側の問題<br/>RaiseEvent呼び出しを確認"]
G -->|YES| I{"#L列に<br/>購読者がいる?"}
I -->|NO| J["購読者が未登録<br/>OnEnableを確認"]
I -->|YES| K["Subscriber側の問題<br/>ハンドラを確認"]
チェックリスト
- イベントチャンネルは割り当てられていますか?
- Inspectorで
Noneになっていないか確認 - 正しいScriptableObjectアセットをドラッグ
- Inspectorで
- null条件演算子を使用していますか?
// Good eventChannel?.RaiseEvent(); // Bad - 割り当てられていない場合NullReferenceExceptionが発生 eventChannel.RaiseEvent(); - 誰かが購読していますか?
- Event Monitorを開いて#L列を確認
- Subscribers Listでリスナーを確認
- 購読者のGameObjectがアクティブか確認
- イベントは実際に発火していますか?
- Event Monitorを開く
- イベントが表示される場合、問題は購読者側にある
- イベントが表示されない場合、発行者のコードを確認
メモリリーク / イベントの重複
症状: イベントが複数回発火したり、シーン遷移後にメモリが増加する。
原因: OnDisableでの購読解除を忘れている。
修正
private void OnEnable()
{
eventChannel.OnEventRaised += HandleEvent;
}
private void OnDisable()
{
eventChannel.OnEventRaised -= HandleEvent; // 必須!
}
診断: シーン遷移の前後でSubscribers Listを確認。破棄されたオブジェクトがリストに残っている場合、リークが発生しています。
イベントが早すぎるタイミングで発火する
症状: イベント発火時に購読者のStart()がまだ実行されていない。
解決策:
オプション1 - イベントを遅延させる
private IEnumerator Start()
{
yield return null; // 1フレーム待つ
onGameStarted?.RaiseEvent();
}
オプション2 - より早く購読する
private void Awake()
{
eventChannel.OnEventRaised += HandleEvent;
}
private void OnDisable()
{
eventChannel.OnEventRaised -= HandleEvent;
}
間違ったイベントチャンネルを参照している
症状: 複数のイベントチャンネルが似た名前を持っており、間違ったものを参照している。
修正 明確な名前を使用し、フォルダで整理しましょう。
ScriptableObjects/Events/
├── Player/
│ ├── OnPlayerDeath.asset
│ └── OnPlayerHealthChanged.asset
├── UI/
│ └── OnMenuOpened.asset
└── Game/
└── OnGamePaused.asset
購読者が更新されない
症状: イベントは発火するが購読者が反応しない。
チェックリスト
- GameObjectはアクティブですか?
- MonoBehaviourは有効ですか?
OnEnable()は実行されましたか?- 購読は正しいですか?
// Correct eventChannel.OnEventRaised += HandleEvent; // Wrong - 他の購読者を上書きする eventChannel.OnEventRaised = HandleEvent; - メソッドシグネチャは一致していますか?
// IntEventChannelSOの場合 void HandleEvent(int value) { } // Correct void HandleEvent() { } // Wrong signature
既知の制限事項
UnityEventsでの呼び出し元情報
呼び出し元情報は、直接コードから呼び出す場合にのみ機能します。UnityEvent経由でイベントを発生させた場合(例:InspectorのButton.OnClick)は機能しません。
機能する
public void OnButtonClick()
{
onButtonPressed?.RaiseEvent(); // Caller: "OnButtonClick"
}
機能しない
Inspector: Button.OnClick → EventChannel.RaiseEvent
Caller shows: "-"
回避策: InspectorからRaiseEventを直接呼び出すのではなく、ラッパーメソッドを作成してください。
Manual Triggerのカスタム型
Manual Triggerは12種類の組み込みイベント型のみをサポートしています。カスタム型の場合、トリガーボタンの代わりにヘルプメッセージが表示されます。
Subscribers Listのスコープ
Subscribers ListにはMonoBehaviourの購読者のみが表示されます。その他の購読者(ScriptableObject、静的クラス)は#Lカウントには含まれますが、リストには表示されません。
カスタム型のシリアライズ不可フィールド
VariablesやEvent Channelsでカスタム型を使用する場合、シリアライズ可能なフィールドのみがシーン遷移やドメインリロード後に保持されます。
カスタム構造体/クラスでサポートされない型
| 型 | ステータス |
|---|---|
Dictionary<K,V> | シリアライズされない |
多次元配列(int[,]) | シリアライズされない |
| デリゲート / イベント | シリアライズされない |
| インターフェース | シリアライズされない |
HashSet<T>, Queue<T>, Stack<T> | シリアライズされない |
問題のあるカスタム型の例
[System.Serializable]
public struct GameProgress
{
public int level; // OK
public Dictionary<string, bool> achievements; // シリアライズされない!
}
// VariableSO<GameProgress>はachievementsデータを失う
解決策: シリアライズ可能な代替手段を使用
[System.Serializable]
public struct GameProgress
{
public int level;
public List<string> achievementKeys; // OK
public List<bool> achievementValues; // OK
}
シーン遷移時のScriptableObjectデータ消失
ScriptableObjectがメモリからアンロードされると、ランタイムデータが失われる可能性があります。以下の場合に発生します。
- エディタ: シーン遷移時にSOがInspectorで選択されていない
- ビルド: SOがどのロード中のシーンからも参照されていない
影響を受けるコンポーネント
- ReactiveEntitySetSOのランタイムデータ(エンティティ)
- RuntimeSetSOのアイテム
- カスタムの非シリアライズフィールド
影響を受けないもの
- VariableSOの値(デフォルトでシリアライズされる)
- Event Channelの購読(
OnEnableで再購読するのが前提)
回避策: 重要なSOが永続的なオブジェクト(例:DontDestroyOnLoadマネージャー)から参照されていることを確認。
FAQ
Reactive SOはビルドで使用できますか?
はい。すべての機能がビルドで動作し、オーバーヘッドはゼロです。デバッグツール(Event Monitor、Manual Trigger、Subscribers List、Caller Info)はEditorのみで動作し、ビルドから自動的に削除されます。
パフォーマンスコストは?
ほぼゼロです。イベントチャンネルは内部的に標準的なC#イベントを使用しています。デバッグ機能はビルドから完全に削除されます。
イベントチャンネルをコルーチンと一緒に使用できますか?
はい、使用できます。
private void OnEnable()
{
eventChannel.OnEventRaised += HandleEvent;
}
private void HandleEvent()
{
StartCoroutine(HandleEventCoroutine());
}
private IEnumerator HandleEventCoroutine()
{
// Your coroutine logic
}
1つのイベントで複数の値を渡せますか?
直接的には不可能です。以下のアプローチのいずれかを使用してください:
オプション1 - 構造体を使用する
[System.Serializable]
public struct PlayerDeathData
{
public Vector3 position;
public string killerName;
public int score;
}
public class PlayerDeathEventChannelSO : EventChannelSO<PlayerDeathData> { }
オプション2 - 複数のイベントを使用する
onPlayerDeath?.RaiseEvent();
onDeathPosition?.RaiseEvent(position);
onFinalScore?.RaiseEvent(score);
ScriptableObjectから購読できますか?
はい、購読できます。
public class GameSettings : ScriptableObject
{
[SerializeField] private VoidEventChannelSO onGameStarted;
private void OnEnable()
{
onGameStarted.OnEventRaised += HandleGameStarted;
}
private void OnDisable()
{
onGameStarted.OnEventRaised -= HandleGameStarted;
}
private void HandleGameStarted()
{
// Initialize settings
}
}
注意: ScriptableObjectの購読者はSubscribers Listには表示されませんが、#L列にはカウントされます。
イベントチャンネルのユニットテストはどうすればいいですか?
using NUnit.Framework;
using Tang3cko.ReactiveSO;
public class EventChannelTests
{
[Test]
public void EventRaisesCorrectly()
{
// Arrange
var eventChannel = ScriptableObject.CreateInstance<IntEventChannelSO>();
int receivedValue = 0;
eventChannel.OnEventRaised += (value) => receivedValue = value;
// Act
eventChannel.RaiseEvent(42);
// Assert
Assert.AreEqual(42, receivedValue);
}
}
イベントチャンネルをネットワーキングに使用できますか?
イベントチャンネルは単一のUnityインスタンス内でローカルに動作します。ネットワークゲームの場合は、以下のアプローチを検討してください。
- ローカルゲームロジックにはイベントチャンネルを使用
- ネットワーク通信にはネットワーキングソリューションを使用
- ネットワークイベントに応答してイベントチャンネルを発火
以下は、ネットワークコールバックからローカルイベントを発火する例です。
[ClientRpc]
void RpcPlayerDeath()
{
// すべてのクライアントで実行
onPlayerDeath?.RaiseEvent(); // UI/オーディオ用のローカルイベント
}
まだ問題がありますか?
ここで説明されていない問題が発生している場合は、以下の手順をお試しください。
- Event Monitorを確認してイベントフローを検証
- Subscribers Listを使用して購読を検証
- Manual Triggerを試して発行者と購読者の問題を切り分け
OnEnable、OnDisable、ハンドラーにDebug.Logを追加- 基本的なセットアップについてはGetting Startedを確認
問題の報告
問題を報告する際は、以下の情報を含めてください。
- Unityバージョン
- Reactive SOバージョン
- 再現手順
- Event Monitorの出力
- Subscribers Listのスクリーンショット
サポートについては、以下のチャンネルをご利用ください。
参考資料
- Event Channels Guide - 基本的な使用方法
- Debugging - デバッグツール
- Event Monitor - リアルタイムトラッキング