From vfm-agent-company
Unity game development expertise covering Unity 2D/3D, C# programming, game mechanics, multiplayer networking, and performance optimization. Use when building games with Unity engine, implementing game systems (player controllers, physics, AI, combat), optimizing for 60 FPS, setting up multiplayer with Unity Netcode/Mirror, or working with Unity-specific features (ScriptableObjects, Prefabs, Animation, UI). Applies to PC, mobile, console, and WebGL platforms.
npx claudepluginhub duylinhdang1998/claude-template-agent --plugin vfm-agent-companyThis skill uses the workspace's default tool permissions.
Expert guidance for building games with Unity engine. Covers architecture, performance, networking, and Unity-specific patterns.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Checks Next.js compilation errors using a running Turbopack dev server after code edits. Fixes actionable issues before reporting complete. Replaces `next build`.
Expert guidance for building games with Unity engine. Covers architecture, performance, networking, and Unity-specific patterns.
Component-Based Design: Unity's architecture centers on GameObjects with MonoBehaviour components. Keep components focused and single-purpose.
Data-Driven Configuration: Use ScriptableObjects for game data (weapons, characters, levels) to enable designer-friendly tweaking without code changes.
Performance First: Target 60 FPS. Avoid GC allocations in Update/FixedUpdate/LateUpdate. Use object pooling for frequently instantiated objects.
Clean Architecture: Separate concerns - player input, game logic, presentation, networking. Follow SOLID principles in C#.
Assets/
├── _Project/ # All project-specific code
│ ├── Scripts/
│ │ ├── Player/ # Player-related scripts
│ │ ├── Weapons/ # Weapon systems
│ │ ├── Enemy/ # AI and enemies
│ │ ├── Managers/ # Game managers (singleton pattern)
│ │ ├── UI/ # UI controllers
│ │ └── Utilities/ # Helper classes
│ ├── Prefabs/ # Reusable GameObjects
│ ├── Scenes/ # Unity scenes
│ ├── Data/ # ScriptableObject instances
│ ├── Sprites/ # 2D sprites and textures
│ ├── Audio/ # Sound effects and music
│ └── Animations/ # Animation clips and controllers
└── Plugins/ # Third-party packages
Player Controller (2D top-down):
public class PlayerController : MonoBehaviour
{
[SerializeField] private float moveSpeed = 5f;
private Rigidbody2D rb;
private Vector2 moveInput;
void Awake() => rb = GetComponent<Rigidbody2D>();
void Update() {
// Read input (runs every frame for responsiveness)
moveInput.x = Input.GetAxisRaw("Horizontal");
moveInput.y = Input.GetAxisRaw("Vertical");
moveInput = moveInput.normalized; // Prevent diagonal speed boost
}
void FixedUpdate() {
// Apply physics (runs at fixed intervals)
rb.velocity = moveInput * moveSpeed;
}
}
ScriptableObject for Data:
[CreateAssetMenu(fileName = "WeaponData", menuName = "Game/Weapon")]
public class WeaponData : ScriptableObject
{
public string weaponName;
public int damage;
public float fireRate;
public Sprite icon;
public GameObject projectilePrefab;
}
Object Pooling (avoid GC):
public class ObjectPool
{
private Queue<GameObject> pool = new Queue<GameObject>();
private GameObject prefab;
public GameObject Get() {
if (pool.Count > 0) {
var obj = pool.Dequeue();
obj.SetActive(true);
return obj;
}
return Object.Instantiate(prefab);
}
public void Return(GameObject obj) {
obj.SetActive(false);
pool.Enqueue(obj);
}
}
1. Setup
2. Core Mechanics
3. Game Systems
4. Multiplayer (if needed)
5. Polish
6. Build
Update Loops:
Update() - Every frame, use for input and non-physics logicFixedUpdate() - Fixed intervals (default 50Hz), use for physicsLateUpdate() - After all Updates, use for camera followingFinding Objects:
FindObjectOfType() in Update (slow)Awake() or via serialized fieldsGetComponent<T>() in Awake, not UpdateInstantiate/Destroy:
Instantiate() and Destroy() cause GC allocationsInput:
Input.GetKey()❌ Allocating in Update:
void Update() {
var enemies = FindObjectsOfType<Enemy>(); // GC allocation every frame!
}
✅ Cache references:
private Enemy[] enemies;
void Start() => enemies = FindObjectsOfType<Enemy>();
❌ String concatenation:
scoreText.text = "Score: " + score; // GC allocation!
✅ Use StringBuilder or format:
scoreText.SetText("Score: {0}", score); // No allocation with TextMeshPro
❌ Using Update for timers:
void Update() {
timer += Time.deltaTime; // Fine, but...
}
✅ Use Coroutines for delays:
IEnumerator Cooldown() {
yield return new WaitForSeconds(1f);
}
Play Mode Tests: Test game logic in Unity Editor
[UnityTest]
public IEnumerator Player_TakesDamage_HealthDecreases() {
var player = new GameObject().AddComponent<Player>();
player.health = 100;
player.TakeDamage(10);
Assert.AreEqual(90, player.health);
yield return null;
}
Unit Tests: Test pure C# logic without Unity
[Test]
public void WeaponData_DPS_CalculatesCorrectly() {
var weapon = ScriptableObject.CreateInstance<WeaponData>();
weapon.damage = 10;
weapon.fireRate = 2f; // shots per second
Assert.AreEqual(20f, weapon.DPS);
}
See assets/ for:
2d-project-structure/ - Example folder hierarchy for 2D gamesscriptableobject-template.cs - Boilerplate ScriptableObject templatemonobehaviour-template.cs - Clean MonoBehaviour template with regionsMobile (Android/iOS):
WebGL:
PC (Windows/Mac/Linux):
For detailed architecture patterns, performance tuning, or multiplayer setup, refer to the key areas above.