Unity C# fundamental patterns including TryGetComponent, SerializeField, RequireComponent, and safe coding practices. Essential patterns for robust Unity development. Use PROACTIVELY for any Unity C# code to ensure best practices.
Core Unity C# patterns for safe, maintainable code. Not optimizations but fundamental practices.
Foundation Required: C# basics, Unity MonoBehaviour lifecycle
Core Topics: TryGetComponent, SerializeField, RequireComponent, Null-safe patterns, Lifecycle management
Always use TryGetComponent instead of GetComponent:
// ❌ WRONG
Rigidbody rb = GetComponent<Rigidbody>();
rb.velocity = Vector3.zero; // NullReferenceException!
// ✅ CORRECT
Rigidbody rb;
if (TryGetComponent(out rb))
{
rb.velocity = Vector3.zero;
}
// ✅ Cache in Awake with validation
private Rigidbody mRb;
void Awake()
{
if (!TryGetComponent(out mRb))
{
Debug.LogError($"Missing Rigidbody on {gameObject.name}", this);
}
}
// ❌ OBSOLETE - DON'T USE
GameManager manager = FindObjectOfType<GameManager>();
// ✅ CORRECT - Fastest (unordered)
GameManager manager = FindAnyObjectByType<GameManager>();
// ✅ CORRECT - Ordered
GameManager manager = FindFirstObjectByType<GameManager>();
// ✅ Multiple objects
Enemy[] enemies = FindObjectsByType<Enemy>(FindObjectsSortMode.None);
// ❌ WRONG: Public field
public float speed;
// ✅ CORRECT: SerializeField + private
[SerializeField] private float mSpeed = 5f;
// ✅ With Inspector helpers
[SerializeField, Tooltip("Units/second"), Range(0f, 100f)]
private float mMoveSpeed = 5f;
public float Speed => mSpeed; // Read-only access
[RequireComponent(typeof(Rigidbody))]
[DisallowMultipleComponent]
public class PhysicsObject : MonoBehaviour
{
private Rigidbody mRb;
void Awake()
{
TryGetComponent(out mRb); // Guaranteed to exist
}
}
// ❌ WRONG: C# null operators don't work with Unity Objects
Transform target = mCached ?? FindTarget(); // Broken!
mEnemy?.TakeDamage(10); // May fail after Destroy
// ✅ CORRECT: Explicit null check
Transform target = mCached != null ? mCached : FindTarget();
if (mEnemy != null)
{
mEnemy.TakeDamage(10);
}
void Awake() { /* 1. Self-init, cache components */ }
void OnEnable() { /* 2. Subscribe events */ }
void Start() { /* 3. Cross-object init */ }
void OnDisable() { /* 4. Unsubscribe events */ }
void OnDestroy() { /* 5. Final cleanup */ }
Important: Unity's Mono/IL2CPP runtime lacks
IsExternalInit.initaccessor causes compile error CS0518.
// ❌ COMPILE ERROR in Unity
public string Name { get; private init; }
// ✅ Use private set
public string Name { get; private set; }
// ✅ Or readonly field + property
private readonly string mName;
public string Name => mName;
Available: Pattern matching, switch expressions, covariant returns
NOT Available: init, required (C# 11)
| Pattern | Rule |
|---------|------|
| Component access | Always TryGetComponent, never bare GetComponent |
| Serialization | [SerializeField] private, not public |
| Dependencies | Use [RequireComponent] for guaranteed components |
| Null checks | Explicit != null, not ?? or ?. |
| Caching | Get in Awake, reuse everywhere |
| Events | Subscribe in OnEnable, unsubscribe in OnDisable |
| Global search | FindAnyObjectByType (fastest), not FindObjectOfType |
init accessor alternatives with code examplesrequired modifier alternativesnpx skills add creator-hian/unity-csharp-fundamentals下载完整 Skill 目录,包含 SKILL.md 及所有相关文件
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer