theone-unity-standards について
Unity 6とC# 9の開発・コードレビュー向けスキルです。コード品質、モダンなC#パターン、アーキテクチャ、パフォーマンスの基準を示し、VContainerまたはTheOne.DIの指針とレビュー項目を含みます。
主な機能
- 01Nullable型と警告対応の基準
- 02モダンなC#パターンの指針
- 03依存性注入とイベント設計の規則
- 04Controller経由のデータアクセス
- 05Unityの性能・コードレビュー項目
活用シーン
- 01Unity C#コードの作成やリファクタリング
- 02コード変更やプルリクエストのレビュー
- 03依存性注入とイベント設計の導入
- 04アセット解放やホットパスの割り当て確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ the1studio/ theone-training-skills --skill theone-unity-standardsインストール後、Claude Code で/theone-unity-standardsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/csharp/linq-patterns.mdmodern-csharp-features.mdperformance-optimizations.mdquality-hygiene.mdreferences/review/architecture-review.mdcsharp-quality.mdperformance-review.mdunity-specifics.mdreferences/unity/data-controllers.mdintegration-patterns.mdsignalbus-events.mdtheone-framework.mdunitask-patterns.mdvcontainer-di.md詳細
TheOne Studio Unity 開発標準
⚠️ Unity 6(C# 9): すべてのパターンとサンプルは、C# 9 を使用する Unity 6 に対応しています。C# 10 以降の機能は使用していません。
スキルの目的
このスキルは、コード品質を最優先に、TheOne Studio の包括的な Unity 開発標準を徹底します。
優先度 1:コード品質と健全性(最重要)
- Nullable 参照型、アクセス修飾子、すべての警告の解消
- 例外をスローする(エラーをログに記録しない)
- TheOne.Logging.ILogger(ランタイムではガード、プレフィックス、コンストラクターでのログ出力なし)と Debug.Log(エディター専用)
- readonly/const、nameof、using ディレクティブのスコープ
- インラインコメントは禁止(説明的な名前を使用)
優先度 2:モダンな C# パターン
- ループより LINQ、拡張メソッド、式形式の本体
- null 合体演算子、パターンマッチング
- モダンな C# 機能(records、init、with)
優先度 3:Unity アーキテクチャ
- VContainer + SignalBus または TheOne.DI + Publisher/Subscriber
- データコントローラーパターン(データへの直接アクセスは絶対に行わない)
- リソース管理、UniTask の非同期パターン
優先度 4:パフォーマンスとレビュー
- LINQ の最適化、アロケーションの防止
- コードレビューのガイドライン
このスキルが適用される場面
- Unity の C# コードを作成またはリファクタリングする
- 依存性注入を使用して Unity の機能を実装する
- イベントやシグナルを扱う
- ゲームデータにアクセスまたは変更する
- コード変更やプルリクエストをレビューする
- プロジェクトのアーキテクチャを設定する
クイックリファレンスガイド
何についてサポートが必要ですか?
| 優先度 | タスク | リファレンス |
|---|---|---|
| 🔴 優先度 1:コード品質(最初に確認) | ||
| 1 | Nullable 型、アクセス修飾子、警告、例外 | 品質と健全性 ⭐ |
| 1 | TheOne.Logging.ILogger(ガード、プレフィックス、コンストラクターでのログ出力なし)と Debug.Log の使い分け | 品質と健全性 ⭐ |
| 1 | readonly/const、nameof、using のスコープ、インラインコメント禁止 | 品質と健全性 ⭐ |
| 🟡 優先度 2:モダンな C# パターン | ||
| 2 | LINQ、拡張メソッド、var の使用 | LINQ パターン |
| 2 | 式形式の本体、null 合体、パターンマッチング | モダンな C# 機能 |
| 2 | Records、init、with 式 | モダンな C# 機能 |
| 🟢 優先度 3:Unity アーキテクチャ | ||
| 3 | VContainer 依存性注入 | VContainer DI |
| 3 | SignalBus イベントシステム | SignalBus イベント |
| 3 | データコントローラーパターン(データへの直接アクセスは絶対に行わない) | データコントローラー |
| 3 | Service/Bridge/Adapter の統合 | 統合パターン |
| 3 | TheOne.DI + Publisher/Subscriber の代替手段 | TheOne フレームワーク |
| 3 | UniTask の async/await パターン | UniTask パターン |
| 🔵 優先度 4:パフォーマンスとレビュー | ||
| 4 | パフォーマンス、LINQ の最適化、アロケーション | パフォーマンス |
| 4 | アーキテクチャレビュー(DI、イベント、コントローラー) | アーキテクチャレビュー |
| 4 | C# 品質レビュー(LINQ、null の処理) | C# 品質 |
| 4 | Unity 固有のレビュー(コンポーネント、ライフサイクル) | Unity 固有の項目 |
| 4 | パフォーマンスレビュー(アロケーション、ホットパス) | パフォーマンスレビュー |
🔴 重要:コード品質ルール(最初に確認!)
⚠️ 必ず守るべき品質基準
コードを書く前に、必ず以下を適用してください。
- Nullable 参照型を有効にする - Nullable に関する警告を一切出さないでください
- アクセス修飾子は必要最小限にする - デフォルトは private です
- すべての警告を修正する - コンパイラー警告は一切許容しません
- エラーには例外をスローする - エラーをログに記録してはいけません。例外をスローしてください
- ランタイムでは TheOne.Logging.ILogger を使用する - 条件付きガード(#if)やプレフィックス([prefix])を使用せず、コンストラクターでは決して使用しないでください。Debug.Log はエディタースクリプトでのみ使用してください
- フィールドには readonly を使用する - 再代入されないフィールドには readonly を付けてください
- 定数には const を使用する - 定数には readonly ではなく const を使用してください
- 文字列には nameof を使用する - プロパティ名やパラメーター名をハードコードしないでください
- using ディレクティブは最も深いスコープに置く - 可能な場合はメソッドレベルで using を使用してください
- インラインコメントを使わない - 説明的な名前を使用し、コードだけで理解できるようにしてください
例:品質を最優先する
// ✅ EXCELLENT: All quality rules enforced
#nullable enable // 1. Nullable enabled
public sealed class PlayerService
{
private readonly TheOne.Logging.ILogger logger;
private const int MaxHealth = 100;
public PlayerService(TheOne.Logging.ILogger logger)
{
this.logger = logger;
}
public Player GetPlayer(string id)
{
using System.Text.Json;
return players.TryGetValue(id, out var player)
? player
: throw new KeyNotFoundException($"Player not found: {id}");
}
private void LoadGameData()
{
this.logger.Info("Game data loaded");
}
}
#if UNITY_EDITOR
public class EditorTool
{
public void Process()
{
Debug.Log("Processing..."); // 5. Debug.Log OK in editor
}
}
#endif
⚠️ Unity アーキテクチャのルール(品質基準の適用後)
フレームワークスタックを 1 つ選択する
プロジェクトごとに 1 つのスタックを選択してください。
オプション 1:VContainer + SignalBus
- ✅ 依存性注入には VContainer を使用する
- ✅ イベントには SignalBus を使用する
- ✅ コンストラクターには [Preserve] 属性を付ける
オプション 2:TheOne.DI + Publisher/Subscriber
- ✅ TheOne.DI ラッパーを使用する
- ✅ イベントには IPublisher/ISubscriber を使用する
- ✅ コンストラクターには [Inject] 属性を付ける
共通ルール(どちらのスタックでも適用):
- ✅ Data Controller を使用する(データに直接アクセスしてはいけません)
- ✅ 非同期処理には UniTask を使用する
- ✅ Dispose でアセットをアンロードする
- ✅ ランタイムでは TheOne.Logging.ILogger を使用する(ガード、プレフィックス、コンストラクターログは禁止)。エディターでのみ Debug.Log を使用する
簡単な例
🔴 コード品質を最優先
// ✅ EXCELLENT: Quality rules enforced
#nullable enable
public sealed class PlayerController
{
private readonly TheOne.Logging.ILogger logger;
private const int MaxRetries = 3;
public PlayerController(TheOne.Logging.ILogger logger)
{
this.logger = logger;
}
public Player LoadPlayer(string id)
{
if (!File.Exists(id))
throw new FileNotFoundException($"Player file not found: {id}");
this.logger.Info($"Loading player {id}");
return DeserializePlayer(id);
}
}
#if UNITY_EDITOR
public class EditorHelper
{
public void Log() => Debug.Log("Editor only"); // Debug.Log OK in editor
}
#endif
🟡 モダンな C# パターン
// ✅ GOOD: LINQ instead of loops
var activeEnemies = allEnemies.Where(e => e.IsActive).ToList();
// ✅ GOOD: Expression bodies
public int Health => this.currentHealth;
// ✅ GOOD: Null-coalescing
var name = playerName ?? "Unknown";
// ✅ GOOD: Pattern matching
if (obj is Player player) player.TakeDamage(10);
Unity アーキテクチャ(VContainer)
using UnityEngine.Scripting;
using VContainer.Unity;
public sealed class GameService : IInitializable, IDisposable
{
private readonly SignalBus signalBus;
private readonly LevelDataController levelController;
[Preserve]
public GameService(SignalBus signalBus, LevelDataController levelController)
{
this.signalBus = signalBus;
this.levelController = levelController;
}
void IInitializable.Initialize()
{
this.signalBus.Subscribe<WonSignal>(this.OnWon);
}
void IDisposable.Dispose()
{
this.signalBus.TryUnsubscribe<WonSignal>(this.OnWon);
}
}
Unity アーキテクチャ(TheOne.DI)
public sealed class GameService : IAsyncEarlyLoadable, IDisposable
{
private readonly IPublisher<WonSignal> publisher;
private IDisposable? subscription;
[Inject]
public GameService(
IPublisher<WonSignal> publisher,
ISubscriber<WonSignal> subscriber)
{
this.publisher = publisher;
this.subscription = subscriber.Subscribe(this.OnWon);
}
public void Dispose()
{
this.subscription?.Dispose();
}
}
コードレビュー用チェックリスト
簡易チェック(コミット前)
🔴 コード品質(最初に確認):
- Nullable 参照型が有効になっている(#nullable enable)
- すべてのアクセス修飾子が適切である(デフォルトは private)
- コンパイラー警告がゼロである
- エラーに対して例外をスローしている(エラーをログに記録していない)
- TheOne.Logging(ランタイム)と Debug.Log(エディターのみ)を使い分けている
- 再代入されないフィールドに readonly を使用している
- 定数に const を使用している
- 文字列リテラルの代わりに nameof を使用している
- using ディレクティブを最も深いスコープに置いている
- インラインコメントがない(コードだけで理解できる)
🟡 モダンな C# パターン:
- 手動のループの代わりに LINQ を使用している
- 単純なメンバーには式形式の本体を使用している
- Null 合体演算子を使用している
- 型チェックにパターンマッチングを使用している
- 適切な場面でモダンな C# 機能を使用している
🟢 Unity アーキテクチャ:
- VContainer/TheOne.DI を適切に使用している
- SignalBus/Publisher-Subscriber を適切に使用している
- データにアクセスする際は Controller のみを経由している
- Dispose ですべてのシグナルの購読を解除している
- コンストラクターに [Preserve] または [Inject] 属性を付けている
🟢 Unity 固有の項目:
- 読み込んだアセットを Dispose でアンロードしている
- Update/ランタイムループ内で Find/GetComponent を使用していない
- GetComponent と null チェックの代わりに TryGetComponent を使用している
- ライフサイクルメソッドを正しい順序で配置している
🔵 パフォーマンス:
- Update/FixedUpdate 内でアロケーションが発生しない
- ホットパスでは LINQ を避けている
- 変更しない場合は .ToList() の代わりに .ToArray() を使用している
避けるべきよくある間違い
❌ DON'T:
- nullable 警告を無視する → #nullable を有効にして、すべての警告を修正してください
- エラーをスローせずにログに記録する → エラーには例外をスローしてください
- ランタイムコードで Debug.Log を使う → TheOne.Logging.ILogger を使ってください(Debug.Log はエディター専用です)
- ログに条件付きガードを追加する → ILogger が内部で #if を処理します
- ログに手動でプレフィックスを追加する → ILogger が自動的に [prefix] を処理します
- コンストラクターでログを記録する → コンストラクターではログを記録しないでください(高速で副作用のない状態を保ちます)
- logger?.Method() を使う → logger.Method() を使ってください(DI により null でないことが保証されます)
- 冗長なログを追加する → 必要なログだけを残してください
- アクセス修飾子を省略する → 常に最も制限の強いアクセス修飾子を使ってください(既定は private)
- 文字列をハードコードする → プロパティ名やパラメーター名には nameof() を使ってください
- フィールドを変更可能なままにする → 可能な場合は readonly/const を使ってください
- Zenject を使う → VContainer を使ってください
- MessagePipe を直接使う → SignalBus を使ってください
- データモデルに直接アクセスする → Controllers を使ってください
- シグナルの購読解除を忘れる → IDisposable を実装してください
- インラインコメントを追加する → 代わりに説明的な名前を使ってください
✅ DO:
- nullable 参照型を有効にする(#nullable enable)
- エラーには例外をスローする(エラーをログに記録しないでください)
- ランタイムでは TheOne.Logging.ILogger を使う(ガードなし、プレフィックスなし、コンストラクターでのログなし)
- logger.Method() を直接使う(null 条件演算子は使わず、DI により null でないことが保証されます)
- Debug.Log はエディター専用にする(#if UNITY_EDITOR)
- 最も制限の強いアクセス修飾子を使う(既定は private)
- 説明的な名前を使う(インラインコメントは使わない)
- 文字列リテラルには nameof() を使う
- 変更できないフィールドには readonly/const を使う
- 依存性注入には VContainer または TheOne.DI を使う
- すべてのイベントには SignalBus または Publisher/Subscriber を使う
- すべてのデータアクセスには Controllers を使う
- 必ず IDisposable を実装し、購読を解除する
- コードストリッピングを防ぐため、[Preserve] または [Inject] を追加する
- コレクション操作には LINQ を使う
レビューの重大度レベル
🔴 重大(必ず修正)
- nullable 警告が未修正 - #nullable を有効にして、すべての警告を修正してください
- エラーをスローせずにログに記録している - エラーにはログではなく throw を使ってください
- ランタイムコードで Debug.Log を使用している - TheOne.Logging.ILogger を使う必要があります(Debug.Log はエディター専用です)
- ログに条件付きガードを設定している - ILogger が内部で #if を処理するため、ガードを削除してください
- ログに手動でプレフィックスを追加している - ILogger が自動的に [prefix] を処理するため、プレフィックスを削除してください
- コンストラクターでログを記録している - コンストラクターではログを記録しないでください(高速で副作用のない状態を保ちます)
- ロガーに null 条件演算子を使っている - logger?.Method() ではなく logger.Method() を使ってください
- アクセス修飾子がない - すべてのメンバーに明示的な修飾子を指定してください
- コンパイラー警告を無視している - 警告は一切許容しません
- インラインコメントを使用している - 代わりに説明的な名前を使ってください
- VContainer の代わりに Zenject を使用している
- SignalBus の代わりに MessagePipe を使用している
- 直接データにアクセスしている(Controllers を使用していない)
- メモリーリークがある(購読を解除していない)
- IDisposable の実装がない
🟡 重要(修正を推奨)
- readonly/const が不足している - 可能な場合、フィールドには readonly/const を指定してください
- 文字列がハードコードされている - プロパティ名やパラメーター名には nameof() を使ってください
- using ディレクティブが最も深いスコープにない - 可能な場合はメソッドレベルの using を使ってください
- 冗長で不要なログがある - 必要なログだけを残してください
- LINQ の代わりに冗長なコードを使用している
- [Preserve] または [Inject] 属性が不足している
- ホットパスにパフォーマンス上の問題がある
- ビジネスロジックの単体テストが不足している
- 公開 API に XML ドキュメントがない
🟢 あると望ましい(提案)
- 式形式を使える
- null 条件演算子を使える
- パターンマッチングを使える
- 命名を改善できる
- 最新の C# 機能を使って簡潔にできる
詳細なリファレンス
C# コーディング規約
- LINQ パターン - LINQ、拡張メソッド、var の使用
- 最新の C# 機能 - 式形式の本体、null 合体演算子、パターンマッチング、レコード
- 品質と衛生 - Nullable 型、アクセス修飾子、ロギング、例外
- パフォーマンスの最適化 - Unity のパターン、LINQ のパフォーマンス
Unity アーキテクチャ
- VContainer DI - VContainer による依存性注入の完全ガイド
- SignalBus イベント - SignalBus イベントシステムのパターン
- データコントローラー - データコントローラーの実装
- 統合パターン - サードパーティ SDK 向けのサービス/ブリッジ/アダプター
- TheOne フレームワーク - TheOne.DI + Publisher/Subscriber の代替パターン
- UniTask パターン - UniTask を使った Async/await
コードレビュー
- アーキテクチャレビュー - VContainer、SignalBus、コントローラーの違反
- C# 品質レビュー - LINQ、式形式の本体、null の処理
- Unity 固有のレビュー - コンポーネントへのアクセス、ライフサイクル、クリーンアップ
- パフォーマンスレビュー - アロケーション、ホットパスでの LINQ
概要
このスキルは、TheOne Studio の包括的な Unity 開発規約を提供します。
- C# の優れた実践:最新の、簡潔でプロフェッショナルな C# コード
- Unity アーキテクチャ:VContainer+SignalBus または TheOne.DI+Publisher のパターン
- コード品質:品質、衛生、パフォーマンスのルールを徹底
- コードレビュー:プルリクエストレビュー用の完全なチェックリスト
上記のクイックリファレンスガイドを使用して、必要なパターンに移動してください。
コメント
Markdown 対応