Aller au contenu principal

Séparer la logique de jeu

Quand tu écris un mod, tu accomplis deux actions fondamentalement distinctes :

  1. Prendre des décisions de gameplay : L'ennemi doit-il attaquer ? La mission est-elle accomplie ? Le joueur a-t-il assez de réputation ?
  2. Appeler le moteur du jeu : Charger des modèles 3D, jouer des sons, changer la météo, couper une animation.

Si tu mélanges ces deux responsabilités dans la même méthode, la seule façon d'éprouver tes règles de gameplay consiste à lancer GTA V, charger ta sauvegarde, rouler jusqu'au point de rendez-vous et espérer reproduire la situation. Cela transforme une simple vérification de cinq secondes en un calvaire de dix minutes.

Le découpage : Le Cerveau contre les Mains

Considère ton mod comme un cerveau et une paire de mains :

  • Le Cerveau (Logique C# pure) : Ne manipule que des nombres, des booléens et du texte. Il ne contient aucune référence à GTA.dll ni à ScriptHookVDotNet. Il décide de ce qui doit se passer.
  • Les Mains (Passerelle SHVDN) : Hérite de Script. Elle lit l'état du monde, transmet les données au cerveau, récupère sa décision et ordonne au moteur ce qu'il doit afficher.
+------------------------------------+
| Monde du jeu (Moteur GTA V) |
+------------------------------------+
^
| (lire positions / appliquer tâches)
+------------------------------------+
| Classe Script (Les Mains) |
+------------------------------------+
| (transmet distance, estArme)
v
+------------------------------------+
| Classe Logique (Le Cerveau) |
+------------------------------------+

Exemple concret : L'évaluateur de rencontre

Voici une classe de pure logique. Remarque l'absence totale de using GTA; :

public sealed class EvaluateurRencontre
{
public EtatRencontre Evaluer(float distanceJoueur, bool joueurArme, EtatRencontre etatActuel)
{
// Règle 1 : Dégainer à moins de 8 mètres déclenche le combat immédiat
if (joueurArme && distanceJoueur <= 8.0f)
{
return EtatRencontre.Combat;
}

// Règle 2 : S'approcher à moins de 4 mètres déclenche le combat même désarmé
if (distanceJoueur <= 4.0f)
{
return EtatRencontre.Combat;
}

// Règle 3 : S'approcher à moins de 14 mètres déclenche l'alerte
if (distanceJoueur <= 14.0f)
{
return EtatRencontre.Alerte;
}

// Règle 4 : S'éloigner au-delà de 18 mètres restaure le calme
if (distanceJoueur > 18.0f)
{
return EtatRencontre.Calme;
}

return etatActuel;
}
}

Comment le script utilise le cerveau

Le gestionnaire OnTick de ton script devient alors d'une simplicité désarmante :

private readonly EvaluateurRencontre _evaluateur = new EvaluateurRencontre();

private void OnTick(object sender, EventArgs e)
{
Ped player = Game.Player.Character;
if (player == null || !player.Exists())
{
return;
}

float distance = player.Position.DistanceTo(_garde.Position);
bool estArme = player.IsArmed(WeaponCheckFlags.All);

// Le cerveau pur prend la décision
EtatRencontre nouvelEtat = _evaluateur.Evaluer(distance, estArme, _etatActuel);

if (nouvelEtat != _etatActuel)
{
AppliquerEtat(nouvelEtat);
}
}

Comme EvaluateurRencontre n'a aucune attache avec GTA V, tu peux exécuter des tests unitaires automatisés dessus dans Visual Studio en 50 millisecondes, sans même allumer le jeu.

Dans la leçon suivante, nous écrivons nos premiers tests unitaires pour prouver que cet évaluateur ne flanche jamais.