💻 Développement

dev-unity-game-helper

Développement de jeux avec Unity et C#.

⚡ Installation & lancement en 1 commande

Copiez-collez dans votre terminal : le skill s'installe dans ~/.claude/skills et Claude Code se lance directement dessus.

macOS / Linux
curl -fsSL https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.sh | sh -s -- dev-unity-game-helper --launch
Windows (PowerShell)
iex "& { $(iwr -useb https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.ps1) } dev-unity-game-helper -Launch"

🚀 Déjà installé ?

claude "/dev-unity-game-helper"

Ou tapez /dev-unity-game-helper dans une session Claude Code, ou décrivez simplement votre besoin — le skill se déclenche automatiquement via le skill-router.

🔑 Déclencheurs automatiques

Le skill s'active automatiquement quand votre demande contient :

Unitygame developmentjeu vidéoC# UnityGameObjectScriptableObject2D game3D gameUnity Editor

📦 Installation manuelle

git clone https://github.com/khalilbenaz/claude-skills-collection.git cp -r claude-skills-collection/skills/dev-unity-game-helper ~/.claude/skills/

Payload du plugin : skills/dev-unity-game-helper · source éditable : dev-skills/unity-game-helper

📖 Manuel

Unity Game Helper

Workflow

1. Choisir la version Unity et le render pipeline

CibleVersion recommandéePipeline
Mobile 2D/3DLTS actuelle (6.x)URP
PC/Console AAALTS actuelleHDRP
WebGL / prototypageLTS actuelleURP ou Built-in
# Créer un projet URP via CLI (Unity Hub)
Unity -createProject MyGame -version 6000.0.47f1 -templateId com.unity.template.urp-blank

2. Structurer le projet

Assets/
  _Project/
    Art/
    Audio/
    Prefabs/
    ScriptableObjects/
    Scripts/
      Core/        ← managers, state machine, services
      Gameplay/    ← character, enemies, interactions
      UI/
      Utils/
    Scenes/
  Tests/
    EditMode/
    PlayMode/

Règle : pas de scripts dans le dossier racine Assets. Tout code va sous _Project/Scripts/.


3. Architecture : Service Locator ou Injection

Option A — Service Locator (simple, no dependency)

public static class ServiceLocator
{
    private static readonly Dictionary<Type, object> _services = new();

    public static void Register<T>(T service) => _services[typeof(T)] = service;

    public static T Get<T>()
    {
        if (_services.TryGetValue(typeof(T), out var svc)) return (T)svc;
        throw new Exception($"Service {typeof(T).Name} non enregistré.");
    }
}

// Au démarrage
ServiceLocator.Register<IAudioService>(new AudioService());

// Usage
ServiceLocator.Get<IAudioService>().Play("sfx_jump");

Option B — Singleton (acceptable pour GameManager, uniquement)

public class GameManager : MonoBehaviour
{
    public static GameManager Instance { get; private set; }

    private void Awake()
    {
        if (Instance != null) { Destroy(gameObject); return; }
        Instance = this;
        DontDestroyOnLoad(gameObject);
    }
}

Critère de choix : > 2 singletons → passer au Service Locator ou Zenject/VContainer.


4. Input System (New Input System)

// PlayerControls.inputactions → générer la classe C#
public class PlayerController : MonoBehaviour
{
    private PlayerControls _controls;

    private void Awake()
    {
        _controls = new PlayerControls();
        _controls.Player.Jump.performed += _ => OnJump();
    }

    private void OnEnable()  => _controls.Enable();
    private void OnDisable() => _controls.Disable();

    private void OnJump() { /* logique */ }
}

Ne jamais utiliser Input.GetKey dans un nouveau projet — l'ancien Input Manager n'est pas rebindable.


5. ScriptableObjects : données et events

Canal d'événement découplé

[CreateAssetMenu(menuName = "Events/GameEvent")]
public class GameEvent : ScriptableObject
{
    private readonly List<GameEventListener> _listeners = new();

    public void Raise()
    {
        for (int i = _listeners.Count - 1; i >= 0; i--)
            _listeners[i].OnEventRaised();
    }

    public void Register(GameEventListener l)   => _listeners.Add(l);
    public void Unregister(GameEventListener l) => _listeners.Remove(l);
}

Usage : playerDied.Raise() depuis le gameplay, UI écoute sans référence directe au player.


6. Object Pooling (Unity 2021+)

using UnityEngine.Pool;

public class BulletSpawner : MonoBehaviour
{
    [SerializeField] private Bullet _prefab;
    private IObjectPool<Bullet> _pool;

    private void Awake()
    {
        _pool = new ObjectPool<Bullet>(
            createFunc:    () => Instantiate(_prefab),
            actionOnGet:   b  => b.gameObject.SetActive(true),
            actionOnRelease: b => b.gameObject.SetActive(false),
            actionOnDestroy: b => Destroy(b.gameObject),
            defaultCapacity: 20, maxSize: 100
        );
    }

    public void Shoot() => _pool.Get().Init(_pool);
}

7. Performance : règles Update

// MAL — recherche en Update, allocation string
void Update()
{
    var rb = GetComponent<Rigidbody>(); // alloc à chaque frame
    Debug.Log("pos: " + transform.position); // string concat
}

// BIEN — cache en Awake, pas d'alloc
private Rigidbody _rb;
void Awake() => _rb = GetComponent<Rigidbody>();

void Update()
{
    // utilise _rb directement, pas d'alloc
}

Checklist performance par domaine :


8. Animation

// Blend Tree : X = horizontal, Y = vertical
// Paramètres via hash (plus rapide que string)
private static readonly int SpeedX = Animator.StringToHash("SpeedX");
private static readonly int SpeedY = Animator.StringToHash("SpeedY");

private void Update()
{
    _animator.SetFloat(SpeedX, _moveInput.x);
    _animator.SetFloat(SpeedY, _moveInput.y);
}

Pour les tweens UI ou effets procéduraux, préférer DOTween (gratuit, zéro GC en mode Blendable) :

transform.DOMove(target, 0.5f).SetEase(Ease.OutBack);

9. Tests automatisés

// EditMode — test pur C#
[Test]
public void StatCalculator_AppliesMultiplier()
{
    var stat = new Stat(baseValue: 10f);
    stat.AddModifier(new StatModifier(0.5f, ModType.Percent));
    Assert.AreEqual(15f, stat.Value, 0.001f);
}

// PlayMode — test avec MonoBehaviour
[UnityTest]
public IEnumerator PlayerDies_WhenHealthZero()
{
    var go = new GameObject();
    var player = go.AddComponent<PlayerHealth>();
    player.TakeDamage(9999);
    yield return null; // une frame
    Assert.IsTrue(player.IsDead);
}

Lancer en CLI :

Unity -runTests -testPlatform EditMode -testResults results.xml -batchmode -projectPath .

10. Build et Addressables

// Chargement asynchrone d'un prefab
var handle = Addressables.LoadAssetAsync<GameObject>("Enemies/Boss");
await handle.Task;
Instantiate(handle.Result);
// Ne pas oublier de libérer
Addressables.Release(handle);

Paramètres de build recommandés (Player Settings) :


Anti-patterns à éviter

Anti-patternProblèmeAlternative
GameObject.Find() en UpdateRecherche O(n) à chaque frameCache en Awake / [SerializeField]
Instantiate/Destroy fréquentsGC spikes, hitchesObject Pool (§6)
Singleton sur toutCouplage fort, tests impossiblesService Locator ou Injection
SendMessageRéflexion lente, pas de typageEvents typés ou UnityEvent
Coroutines sans référenceFuite mémoire, double-startStocker Coroutine _c et vérifier null
Resources.Load au runtimeTous les assets chargés en RAMAddressables
string dans Animator.SetFloatAllocation + lenteurAnimator.StringToHash (§8)

Références rapides