Fail-Fast原則とUnity最適化ルールを強制するRoslyn Analyzerパッケージです。
このリポジトリは以下の構成になっています:
- UnityAnalyzer/ - Unity 6000.2.14f1プロジェクト(テスト・開発用)
- Packages/com.akiojin.unity.analyzers/ - 埋め込みUnityパッケージ
Analyzers~/- C# Roslyn AnalyzerソースコードPlugins/- ビルド済み Analyzer DLLEditor/- Unity Editor拡張package.json- パッケージ定義
- Packages/com.akiojin.unity.analyzers/ - 埋め込みUnityパッケージ
Unityプロジェクトを開くと、埋め込みパッケージが自動的にインポートされます。レジストリ設定は不要です。
このパッケージは、Unity開発における以下の重要なルールをコンパイル時に検証します:
- Fail-Fast原則の徹底 - エラー隠蔽コードの検出
- GetComponent/DIキャッシュの強制 - パフォーマンス劣化の防止
- 禁止メソッドの検出 - Find系メソッドの使用禁止
openupm add com.akiojin.unity.analyzersPackages/manifest.jsonに以下を追加:
{
"scopedRegistries": [
{
"name": "OpenUPM",
"url": "https://package.openupm.com",
"scopes": [
"com.akiojin"
]
}
],
"dependencies": {
"com.akiojin.unity.analyzers": "0.1.0"
}
}Window > Package Managerを開く+ボタンをクリックAdd package from git URL...を選択- 以下のURLを入力:
https://github.com/akiojin/unity-analyzers.git
またはPackages/manifest.jsonに直接追加:
{
"dependencies": {
"com.akiojin.unity.analyzers": "https://github.com/akiojin/unity-analyzers.git"
}
}Packages/フォルダにこのパッケージをコピーしてください。
Awake/Start以外でのGetComponent系メソッド呼び出しを検出します。 GetComponent系メソッドはAwake/Startでのみ許可されています。
重大度: Warning
検出対象:
GetComponent<T>()GetComponentInChildren<T>()GetComponentInParent<T>()GetComponents<T>()GetComponentsInChildren<T>()GetComponentsInParent<T>()
なぜ禁止か:
- 毎フレームのGCアロケーションが発生(60FPSで毎秒60回のガベージ生成)
- CPU負荷が10倍以上増大
- モバイル環境では致命的なフレームドロップの原因
- Awake/Startでキャッシュするか、VContainerでInjectすべき
Update/FixedUpdate/LateUpdate/OnGUI内でのFind系メソッドの使用を検出します。 初期化時や条件付きの一時的な呼び出しは許容されます。
重大度: Warning
検出対象(Update系メソッド内のみ):
FindObjectOfType<T>()FindObjectsOfType<T>()FindAnyObjectByType<T>()FindObjectsByType<T>()FindFirstObjectByType<T>()GameObject.Find()GameObject.FindWithTag()GameObject.FindGameObjectWithTag()GameObject.FindGameObjectsWithTag()
許容される使用例:
- Awake/Start内での初期化時の使用
- イベントハンドラー内での一時的な使用
- エディタースクリプト内での使用
なぜUpdate内で禁止か:
- 毎フレームシーン全体をスキャンするため致命的なパフォーマンス低下
- 60FPSで毎秒60回の重い処理が発生
- Awake/Startでキャッシュするか、DIまたはSerializeFieldで参照を解決すべき
GetComponent後のnullチェックを検出します(Fail-Fast違反)。
重大度: Warning
検出対象:
// ❌ これは禁止
var rb = GetComponent<Rigidbody>();
if (rb != null)
{
rb.velocity = Vector3.zero;
}
// ❌ null条件演算子も禁止
GetComponent<Rigidbody>()?.AddForce(Vector3.up);なぜ禁止か:
- 設計ミスを隠蔽してしまう
- 必須コンポーネントが存在しない場合は即座にクラッシュさせるべき
[RequireComponent]属性で依存を明示すべき
DI注入後のnullチェックを検出します(Fail-Fast違反)。
重大度: Warning
検出対象:
// ❌ これは禁止
[Inject]
public IGameService GameService { get; set; }
void Start()
{
if (GameService != null) // Fail-Fast違反!
{
GameService.Initialize();
}
}
// ❌ SerializeFieldのnullチェックも禁止
[SerializeField] Transform target;
void Update()
{
if (target != null) // Fail-Fast違反!
{
target.position = Vector3.zero;
}
}なぜ禁止か:
- DIコンテナは依存解決を保証する
- 未設定の場合は設計ミスであり、即座にクラッシュさせるべき
- フォールバック処理はバグの温床
このパッケージが強制するルールの背景にある、Unity開発のベストプラクティスを解説します。
最重要:エラーを隠蔽するコードは絶対に書いてはならない
Fail-Fast原則とは、エラーが発生した時点で即座にクラッシュさせることで、問題を早期に発見する設計哲学です。
// ✅ 直接使用(存在前提)
GetComponent<Rigidbody>().velocity = Vector3.zero;
// ✅ DIは必ず成功する前提
GameService.Initialize();
// ✅ SerializeFieldは設定済み前提
target.position = Vector3.zero;
// ✅ RequireComponentで依存を明示
[RequireComponent(typeof(Rigidbody))]
public class PlayerController : MonoBehaviour
{
private Rigidbody _rigidbody;
void Awake()
{
_rigidbody = GetComponent<Rigidbody>();
}
}以下の場合のみnullチェック・例外処理を許可:
- ネットワーク通信
- ファイルシステムアクセス
- プレイヤーの入力データ
- 外部プラグインとの連携
GetComponentはAwake/Startでのみ許可される
他のメソッド(Update/FixedUpdate/LateUpdate/UniTask/コルーチン等)での使用は禁止です。
public class PlayerController : MonoBehaviour
{
// Awakeでキャッシュ
private Rigidbody _rigidbody;
private Animator _animator;
void Awake()
{
_rigidbody = GetComponent<Rigidbody>();
_animator = GetComponent<Animator>();
}
void FixedUpdate()
{
// キャッシュした参照を使用
_rigidbody.velocity = CalculateVelocity();
}
}public class GameManager : MonoBehaviour
{
[Inject]
public IPlayerService PlayerService { get; set; }
[Inject]
public IScoreService ScoreService { get; set; }
void Start()
{
// DIで注入された参照を直接使用
PlayerService.Initialize();
ScoreService.Reset();
}
}- 各シーンで
LifetimeScopeを1つ配置し、Auto Runを有効化 - ルートとなる
LifetimeScopeはプレハブ化してVContainerSettingsに登録
[Inject]だけでは注入されないため、以下のいずれかで明示的に対象を登録:
- LifetimeScopeの
Auto Inject Game Objectsに対象を追加 builder.RegisterComponentInHierarchy<T>()を使用IObjectResolver.Instantiateで生成
GameObjectやautoRunが無効化されているとコンテナが構築されず、全Injectがnullになります。
シーン保存前にLifetimeScopeの有効状態を確認してください。
- Unity 2021.3以上であることを確認
- パッケージが正しくインストールされていることを確認
Plugins/StrictRules.Analyzers.dllの.metaファイルでRoslynAnalyzerが有効になっていることを確認
特定の行でAnalyzerを無効化するには:
#pragma warning disable SR0001
var component = GetComponent<SomeComponent>(); // この行は警告されない
#pragma warning restore SR0001ただし、この方法は本当に必要な場合のみ使用してください。
このプロジェクトへのコントリビューションを歓迎します!詳細はCONTRIBUTING.mdを参照してください。
このプロジェクトは自動リリースフローを採用しています:
すべてのコミットはConventional Commits形式に従う必要があります:
<type>(<scope>): <subject>
例:
feat(analyzer): add new Unity lifecycle rule
fix(workflow): resolve build failure
docs: update installation guide
主なtype:
feat: 新機能(MINORバージョンアップ)fix: バグ修正(PATCHバージョンアップ)feat!またはBREAKING CHANGE: 破壊的変更(MAJORバージョンアップ)
詳細はCONTRIBUTING.mdを参照。
-
リリースPRの自動作成
mainブランチへのマージ時、release-pleaseが自動的にリリースPRを作成・更新- コミットメッセージに基づいてバージョン番号を自動決定
- CHANGELOG.mdを自動更新
-
リリースの実行
- リリースPRがマージされると:
- GitHubリリースとタグを自動作成
- C# Analyzerプロジェクトを自動ビルド
Plugins/StrictRules.Analyzers.dllを自動更新- OpenUPMへの公開をトリガー
- リリースPRがマージされると:
-
継続的インテグレーション
- すべてのPRで自動ビルド・テストを実行
- コミットメッセージ形式を自動検証
- パッケージ構造を自動検証
プロジェクトにはMakefileが用意されています:
# ヘルプを表示
make help
# Analyzerをビルド
make build
# ビルドしてPluginsにコピー
make analyzer
# コードをフォーマット
make format
# すべての品質チェックを実行
make quality-checks
# クリーンアップ
make clean# Analyzerプロジェクトをビルド
cd Analyzers~
dotnet build --configuration Release
# ビルド済みDLLをPluginsにコピー
cp bin/Release/netstandard2.0/StrictRules.Analyzers.dll ../Plugins/詳細な開発ガイドラインはCLAUDE.mdを参照してください。
このプロジェクトは以下のGitHub Actionsワークフローを使用しています:
すべてのプルリクエストで実行される必須チェック:
- Build (
.github/workflows/build.yml): C# Analyzerのビルドとテスト - Lint (
.github/workflows/lint.yml): MarkdownとC#コードのリンティング - Commit Lint (
.github/workflows/commitlint.yml): コミットメッセージ検証
- Release (
.github/workflows/release.yml): 自動リリース処理 - OpenUPM (
.github/workflows/openupm.yml): OpenUPM公開
詳細はBranch Protection設定を参照してください。
プロジェクトにはDocker開発環境が用意されています。
まず、.envファイルを作成します:
# .env.exampleをコピー
cp .env.example .env
# 必要に応じて.envを編集
vim .env # または任意のエディタ# コンテナをビルドして起動
docker-compose up -d
# 開発環境のシェルに入る
docker-compose exec unity-analyzers-dev bash
# コンテナ内でビルド
make analyzer
# コンテナを停止
docker-compose down# Docker開発環境を起動してシェルに入る
make dev
# Dockerイメージをビルド
make docker-build
# コンテナを起動
make docker-up
# コンテナに入る
make docker-shell
# コンテナを停止
make docker-down
# コンテナとボリュームを削除
make docker-clean# スクリプトに実行権限を付与
chmod +x scripts/docker-dev.sh
# コンテナを起動して開発環境に入る
./scripts/docker-dev.sh up
# Analyzerをビルド
./scripts/docker-dev.sh analyzer
# ヘルプを表示
./scripts/docker-dev.sh help- .NET 8 SDK
- Node.js 20 LTS(ワークフローツール用)
- GitHub CLI
- commitlint
- その他の開発ツール
MIT License - 詳細はLICENSE.mdを参照してください。