Cours

Lua Leçon 5

Lua dans les jeux : les événements

Comment un script de jeu réagit à ce qui se passe : les événements, les fonctions de rappel et les boucles de jeu.

20 min

À la fin de cette leçon, tu sauras

  • Comprendre le principe d'un événement
  • Enregistrer une fonction qui réagit à un événement
  • Éviter les pièges classiques des scripts de jeu

Le principe

Dans un jeu, le script ne tourne pas du début à la fin comme un programme classique. Il dit plutôt au jeu : « quand un joueur se connecte, appelle cette fonction », « quand il entre dans un véhicule, appelle celle-là ». Ces moments s'appellent des événements, et les fonctions appelées des fonctions de rappel (callbacks).

Chaque jeu a ses propres noms de fonctions (Roblox, FiveM, WoW…), mais le principe est toujours le même. Pour le comprendre, on va écrire notre propre petit système d'événements, en Lua pur.

Un système d'événements maison

local ecouteurs = {}

local function surEvenement(nom, fonction)
    ecouteurs[nom] = ecouteurs[nom] or {}
    table.insert(ecouteurs[nom], fonction)
end

local function declencher(nom, ...)
    for _, fonction in ipairs(ecouteurs[nom] or {}) do
        fonction(...)
    end
end
  • ecouteurs est une table qui associe à chaque nom d'événement une liste de fonctions ;
  • surEvenement enregistre une fonction pour un événement ;
  • declencher appelle toutes les fonctions enregistrées. Les trois points ... transmettent tous les arguments reçus ;
  • _ est le nom qu'on donne par convention à une variable dont on ne se sert pas.

L'utiliser

surEvenement("joueurConnecte", function(pseudo)
    print("Bienvenue " .. pseudo .. " !")
end)

surEvenement("joueurConnecte", function(pseudo)
    print(pseudo .. " reçoit 500 $ de départ")
end)

declencher("joueurConnecte", "Skap")

Dans un vrai jeu, c'est le moteur qui appelle declencher au bon moment. Toi, tu n'écris que les fonctions de rappel.

Les pièges classiques

  • Les boucles infinies : une boucle while true do sans pause bloque tout le serveur. Les jeux fournissent une fonction d'attente (souvent Wait ou task.wait) à appeler dans la boucle ;
  • Faire confiance au joueur : un joueur peut modifier ce qui se passe sur son ordinateur. Tout ce qui compte (argent, objets, droits) doit être vérifié côté serveur, jamais seulement côté client ;
  • Oublier local : avec des dizaines de scripts sur un même serveur, une variable globale finit toujours par entrer en conflit avec une autre.

À toi de jouer

En utilisant les fonctions surEvenement et declencher de la leçon (déjà écrites ci-dessous) :

  • enregistre une fonction pour l'événement "vehiculeEntre", qui reçoit pseudo et modele et affiche une phrase avec les deux ;
  • déclenche cet événement avec un pseudo et un modèle de voiture.
main.lua
  • Une fonction est enregistrée pour "vehiculeEntre"
  • Elle reçoit pseudo et modele
  • Elle affiche une phrase avec les deux
  • L'événement est déclenché avec deux valeurs
Bloqué ? Voir une solution
-- (après les fonctions de la leçon)
surEvenement("vehiculeEntre", function(pseudo, modele)
    print(pseudo .. " monte dans une " .. modele)
end)

declencher("vehiculeEntre", "Skap", "Clio")

Quiz

1Qu'est-ce qu'une fonction de rappel (callback) ?
2Pourquoi vérifier l'argent d'un joueur côté serveur ?
3Que se passe-t-il avec while true do … end sans aucune pause ?