Catégories
Jeu vidéo ROBLOX ROBLOX-NIVEAU01

Comprendre l’apparition des joueurs

et les changements d’états

Découvrir la vie d’un joueur dans Roblox avec un script « d’observation » :

  1. Quand un joueur se connecte (PlayerAdded).
  2. Quand son personnage apparaît (CharacterAdded).
  3. Quand son personnage change d’état (StateChanged : saut, chute, atterrissage…).

Ce script n’est pas un jeu : c’est un script espion ! Il ne fait qu’afficher dans la console (Output) tout ce qui arrive aux joueurs. C’est l’outil parfait pour comprendre ces trois événements avant de les utiliser dans de vrais jeux (comme la zone anti-gravité ou les checkpoints !).

Introduction : La vie d’un joueur Roblox

Quand tu joues à un jeu Roblox, voici ce qui se passe dans l’ordre :

1. Le JOUEUR se connecte au jeu        → événement PlayerAdded
2. Son PERSONNAGE apparaît dans le monde → événement CharacterAdded
3. Le personnage agit : court, saute, tombe, atterrit...
                                          → événements StateChanged (très fréquents !)
4. Le personnage meurt → il est détruit
5. Un NOUVEAU personnage apparaît        → de nouveau CharacterAdded !
6. Le joueur quitte le jeu               → événement PlayerRemoving

Les trois personnages-clés de ce tuto :

  • player : le compte du joueur (son nom, son UserId…). Il ne meurt jamais.
  • character : le bonhomme 3D dans le monde (le Model). Il est détruit à chaque mort et recréé à chaque respawn !
  • humanoid : l’ordinateur de bord du personnage : il gère la santé, la marche, les sauts… et ses états.

Les états d’un Humanoid (Enum.HumanoidStateType)

ÉtatSignification
RunningLe personnage court au sol.
JumpingIl vient de sauter.
FreefallIl tombe dans les airs.
LandedIl vient d’atterrir.
ClimbingIl grimpe à une échelle.
SwimmingIl nage.
SeatedIl est assis (dans un siège).
DeadIl est mort !
PlatformStanding / PhysicsÉtats spéciaux (plateformes, physique).

C’est la même liste que celle utilisée dans le tutoriel de la zone anti-gravité (Jumping, Freefall, Landed) !

Voici le script commenté en français :

-- Récupérer le service des joueurs
local Players = game:GetService("Players")

-- Fonction appelée à chaque changement d'état du Humanoid
-- Paramètres : le joueur, l'ancien état, le nouvel état
local function onStateChanged(player, oldState, newState)
    -- Affiche dans la console : nom du joueur, ancien état -> nouvel état
    print(player.Name, "État changé :", oldState, "->", newState)
end

-- Fonction appelée à chaque apparition du personnage
local function onCharacterAdded(player, character)
    -- Attendre que le Humanoid existe (le personnage se construit progressivement !)
    local humanoid = character:WaitForChild("Humanoid")

    -- Connecter le suivi des changements d'états de CE personnage
    humanoid.StateChanged:Connect(function(oldState, newState)
        onStateChanged(player, oldState, newState)
    end)
end

-- Fonction appelée à chaque connexion d'un joueur
local function onPlayerAdded(player)
    print(player.Name .. " est connecté")

    -- Cas 1 : le personnage existe DÉJÀ (joueur connecté avant le script)
    if player.Character then
        task.spawn(onCharacterAdded, player, player.Character)
    end

    -- Cas 2 : chaque apparition/réapparition FUTURE (mort, respawn...)
    player.CharacterAdded:Connect(function(character)
        onCharacterAdded(player, player.Character and character)
    end)
end

-- Nouveaux joueurs : événement pour chaque joueur qui se connecte
Players.PlayerAdded:Connect(onPlayerAdded)

-- Joueurs déjà connectés AVANT l'exécution du script
for _, player in ipairs(Players:GetPlayers()) do
    task.spawn(onPlayerAdded, player)
end

Explications Détaillées : les 4 fonctions du script

Le script est construit comme des poupées russes : chaque fonction appelle la suivante !

onPlayerAdded ──► onCharacterAdded ──► onStateChanged
     (1)                (2)                  (3)

1. onStateChanged : l’espion des états

local function onStateChanged(player, oldState, newState)
    print(player.Name, "État changé :", oldState, "->", newState)
end
  • oldState : l’état avant le changement (ex: Enum.HumanoidStateType.Freefall).
  • newState : le nouvel état (ex: Enum.HumanoidStateType.Landed).
  • Rappel des tutoriels précédents : print(...) avec plusieurs valeurs séparées par des virgules affiche tout sur une ligne (pas besoin de concaténer avec .. !).

2. onCharacterAdded : l’espion des personnages

local function onCharacterAdded(player, character)
    local humanoid = character:WaitForChild("Humanoid")
    humanoid.StateChanged:Connect(function(oldState, newState)
        onStateChanged(player, oldState, newState)
    end)
end
  • WaitForChild("Humanoid") : quand le personnage apparaît, il se construit pièce par pièce (jambes, torse, tête, Humanoid…). Si on cherche le Humanoid trop tôt, il n’existe pas encore → erreur ! WaitForChild attend qu’il soit prêt. (Rappel : c’est pareil que WaitForChild("HumanoidRootPart") dans le tutoriel des checkpoints !)
  • On connecte StateChanged pour ce personnage précis. Quand il mourra, ce personnage sera détruit — et sa connexion avec lui ! C’est pour ça qu’il faut reconnecter StateChanged à chaque nouveau personnage (d’où la fonction !).

3. onPlayerAdded : l’espion des joueurs (avec ses DEUX pièges !)

local function onPlayerAdded(player)
    print(player.Name .. " est connecté")

    -- Cas 1 : le personnage existe DÉJÀ
    if player.Character then
        task.spawn(onCharacterAdded, player, player.Character)
    end

    -- Cas 2 : apparitions futures
    player.CharacterAdded:Connect(function(character)
        onCharacterAdded(player, character)
    end)
end

Piège n°1 : le joueur est arrivé AVANT le script !

  • Le problème : PlayerAdded ne se déclenche que pour les joueurs qui arrivent après la connexion de l’événement. Si tu es déjà dans le jeu quand le script démarre (par exemple au lancement d’un test Studio), l’événement t’a raté !
  • La solution en deux temps :
    • Cas 1 : if player.Character then → le personnage existe déjà → on appelle directement onCharacterAdded.
    • Cas 2 : player.CharacterAdded:Connect(...) → on guette toutes les apparitions futures (respawn après mort !).

Piège n°2 : CharacterAdded ne se déclenche pas à la connexion… mais un peu après !

  • Quand un joueur se connecte, PlayerAdded se déclenche, puis Roblox crée son personnage (quelques millisecondes plus tard) → c’est ensuite que CharacterAdded se déclenche. C’est pour ça que le Cas 2 attrape aussi la toute première apparition !

Pourquoi task.spawn ?

  • task.spawn(fonction, arguments...) lance la fonction dans un thread séparé : le script n’attend pas qu’elle soit finie pour continuer.
  • Indispensable ici : onCharacterAdded commence par un WaitForChild… qui peut bloquer quelques instants. Sans task.spawn, un joueur « lent à charger » bloquerait le traitement des autres joueurs !

4. La boucle finale : rattraper tout le monde

Players.PlayerAdded:Connect(onPlayerAdded)

for _, player in ipairs(Players:GetPlayers()) do
    task.spawn(onPlayerAdded, player)
end
  • Players.PlayerAdded:Connect(onPlayerAdded) : tous les joueurs qui arriveront à partir de maintenant.
  • Players:GetPlayers() : la liste des joueurs déjà présents (rappel : c’est une liste numérotée, donc on utilise ipairs, comme pour les checkpoints et les blocs de la pyramide !).
  • La boucle appelle onPlayerAdded pour chacun : personne n’est oublié, même si le script a démarré en retard !

Le schéma complet :


Préparation et Test dans Roblox Studio

  1. Crée un Script dans ServerScriptService et colle le code corrigé.
  2. Ouvre la fenêtre Output (onglet View → Output) : c’est là que les print s’affichent.
  3. Lance le jeu en mode multi-joueurs (onglet Test → 2 Players) pour observer plusieurs joueurs !
  4. Expérimente et observe la console :
ActionCe que tu dois voir dans l’Output
Le jeu démarrepatrick est connecté (et celui du 2ème joueur !)
Tu marchesRien (rester en Running ne change pas l’état !)
Tu sautesJumping puis Freefall
Tu atterrisLanded puis Running
Tu montes une échelleClimbing
Tu tombes dans l’eauSwimming
Tu t’assois sur un siègeSeated
Tu te reset (menu Echap → Reset)Dead… puis re-connexion automatique de CharacterAdded !

Contrôle important : après ta mort, observe bien : onCharacterAdded est rappelé automatiquement pour ton nouveau personnage (le script continue d’afficher tes états, sans rien refaire !). C’est la preuve que le Cas 2 de onPlayerAdded fonctionne.


QCM : Teste ta compréhension !

Sur la vie du joueur :

  1. Dans quel ordre se passent les événements quand un joueur rejoint le jeu ?
    • a) PlayerAdded → CharacterAdded → puis les StateChanged.
    • b) CharacterAdded → PlayerAdded → StateChanged.
    • c) Tout en même temps.
  1. Quelle est la différence entre player et character ?
    • a) player est le compte (ne meurt jamais) ; character est le bonhomme 3D, détruit à chaque mort et recréé à chaque respawn.
    • b) Ce sont deux noms pour la même chose.
    • c) character est le compte du joueur.
  1. Que se passe-t-il pour la connexion StateChanged quand le personnage meurt et respawn ?
    • a) Elle est détruite avec l’ancien personnage ; onCharacterAdded reconnecte StateChanged sur le NOUVEAU Humanoid.
    • b) Elle reste active sur l’ancien personnage.
    • c) Roblox la reconnecte automatiquement tout seul.

Sur les états du Humanoid :

  1. Dans quel ordre les états s’enchaînent-ils quand tu sautes d’une plateforme ?
    • a) Jumping → Freefall → Landed → Running.
    • b) Running → Landed → Jumping.
    • c) Freefall → Jumping → Running.
  1. Pourquoi ne voit-on rien s’afficher quand on marche normalement pendant longtemps ?
    • a) Parce qu’on reste dans l’état Running : sans changement d’état, StateChanged ne se déclenche pas.
    • b) Parce que print est cassé.
    • c) Parce que la marche est trop rapide.
  1. Quels sont les paramètres reçus par la fonction connectée à StateChanged ?
    • a) L’ancien état et le nouvel état (oldState, newState).
    • b) Le joueur et le personnage.
    • c) Rien.

Sur les deux pièges :

  1. Pourquoi le script a-t-il besoin de la boucle for ... ipairs(Players:GetPlayers()) à la fin ?
    • a) Pour rattraper les joueurs déjà connectés AVANT le démarrage du script (l’événement PlayerAdded ne se déclenche pas pour eux).
    • b) Pour déconnecter les joueurs.
    • c) Pour afficher la liste des règles du jeu.
  1. Pourquoi utilise-t-on task.spawn(onCharacterAdded, player, player.Character) ?
    • a) Pour lancer la fonction dans un thread séparé et ne pas bloquer le script, car elle contient un WaitForChild qui peut attendre.
    • b) Pour aller plus vite que WaitForChild.
    • c) Parce que onCharacterAdded est interdite ailleurs.
  1. Pourquoi onCharacterAdded utilise-t-elle WaitForChild("Humanoid") ?
    • a) Parce que le personnage se construit pièce par pièce : au moment de l’événement, le Humanoid n’existe peut-être pas encore.
    • b) Pour faire joli.
    • c) Parce que le Humanoid n’existe jamais.
  1. Dans onPlayerAdded, à quoi sert le if player.Character then ?
    • a) À vérifier si le personnage existe DÉJÀ (le joueur était là avant le script) pour ne pas rater son suivi.
    • b) À créer un personnage.
    • c) À détruire le personnage.

Résumé des concepts clés

ConceptDescriptionExemple
PlayerAddedUn joueur se connecte au jeu.Players.PlayerAdded:Connect(onPlayerAdded)
CharacterAddedUn personnage apparaît (1ère fois OU respawn !).player.CharacterAdded:Connect(...)
StateChangedLe Humanoid change d’état (saut, chute, atterrissage…).humanoid.StateChanged:Connect(...)
Enum.HumanoidStateTypeLa liste des états possibles.Landed, Jumping, Freefall, Dead…
GetPlayers()Liste des joueurs déjà présents (rattrapage !).for _, player in ipairs(...) do
task.spawnLance une fonction sans bloquer le script.task.spawn(onPlayerAdded, player)
WaitForChild("Humanoid")Attend que le personnage soit prêt.Anti-erreur !
GetState()Lit l’état ACTUEL (sans attendre un changement).Utilisé dans la zone anti-gravité

Astuce : Garde ce script espion dans un coin de tes projets : dès qu’un comportement te semble mystérieux (pourquoi mon joueur ne saute plus ?), les print des états te diront exactement ce qui se passe dans la tête du Humanoid ! C’est l’outil de débogage parfait