Tu es le maître d‘un jeu d’un parcours d’obstacles (un Obby). Ton rôle est de surveiller les joueurs, de noter leur progression, et de les renvoyer au bon endroit s’ils tombent dans le vide.
Crée dans ton jeu des CheckPoints sur ton parcours, les checkpoints seront visibles ou non, puis programme un script qui reconnaitre tous les checkpoints et notera pour chaque joueur sa progression. En cas de respawn le joueur reviendra sur le dernier checkpoint validé.
Au tout début du script, on trouve une boîte appelée CONFIG. C’est le « panneau de contrôle » du jeu. C’est ici que tu peux changer facilement les règles sans toucher au reste du code.
- Quand un joueur rejoint le jeu (
PlayerAdded) :- On initialise ses données (il commence au Checkpoint 1).
- On écoute quand son personnage apparaît (
CharacterAdded) pour le téléporter au bon checkpoint (au cas où il meurt et respawn).
- Quand un joueur quitte le jeu (
PlayerRemoving) :- On supprime ses données pour libérer de la mémoire.
- Au démarrage du script :
- On initialise tous les joueurs déjà présents.
- On connecte tous les checkpoints.
Tu places 5 checkpoints dans un dossier appelé « Checkpoints » dans Workspace :
- Checkpoint1
- Checkpoint2
- Checkpoint3
- Checkpoint4
- Checkpoint5


- Un joueur (123CODAGE) rejoint le jeu :
- Ses données :
{ indexActuel = 0, checkpointPart = Checkpoint1 }. - Il spawn au Checkpoint1.
- Ses données :
- 123CODAGE touche Checkpoint2 :
- Le script vérifie :
indexActuel + 1 = 1→2 == 1 + 1→ OK ! indexActuelpasse à 2.- Checkpoint2 devient vert.
- Message : « 123CODAGE a atteint le checkpoint 2/5″.
- Le script vérifie :
- 123CODAGE tombe dans le vide :
- Il respawn au Checkpoint2 (dernier validé).
- 123CODAGE touche Checkpoint4 sans faire le 3 :
- Le script vérifie :
indexActuel + 1 = 3→4 != 3→ Bloqué ! (carsauvegarderOrdre = true).
- Le script vérifie :
- 123CODAGE termine tous les checkpoints :
- Message : « 123CODAGE a terminé le parcours ! » 🎉

Saisie ce script CheckpointsService sous ServerScriptService :

-- Script : GestionCheckpoints
local Players = game:GetService("Players")
local DialogueModule = require(game.ReplicatedStorage.DialogueModule)
-- ═══════════════════════════════════════
-- CONFIGURATION
-- ═══════════════════════════════════════
local CONFIG = {
dossierCheckpoints = "Checkpoints", -- nom du dossier dans Workspace
offsetRespawn = Vector3.new(0, 3, 0), -- hauteur au-dessus du checkpoint
afficherMessages = true,
sauvegarderOrdre = true, -- respecte l'ordre numérique des checkpoints
checkpointValidated = BrickColor.Green(),
checkpointInitial = BrickColor.DarkGray()
}
-- ═══════════════════════════════════════
-- RÉCUPÉRATION DES CHECKPOINTS
-- ═══════════════════════════════════════
local dossier = workspace:WaitForChild(CONFIG.dossierCheckpoints)
local function getCheckpointsTries()
local liste = {}
for _, cp in ipairs(dossier:GetChildren()) do
if cp:IsA("BasePart") or cp:IsA("Model") then
table.insert(liste, cp)
end
end
-- Trier par nom numérique (Checkpoint1, Checkpoint2...)
table.sort(liste, function(a, b)
local numA = tonumber(a.Name:match("%d+")) or 0
local numB = tonumber(b.Name:match("%d+")) or 0
return numA < numB
end)
return liste
end
local checkpoints = getCheckpointsTries()
-- ═══════════════════════════════════════
-- DONNÉES PAR JOUEUR
-- ═══════════════════════════════════════
local progressionJoueurs = {}
-- { [userId] = { indexActuel = 1, checkpointPart = part } }
local function getPositionCheckpoint(cp)
if cp:IsA("Model") then
local primary = cp.PrimaryPart or cp:FindFirstChildOfClass("BasePart")
return primary and primary.Position or Vector3.new(0, 0, 0)
end
return cp.Position
end
-- ═══════════════════════════════════════
-- RESPAWN AU DERNIER CHECKPOINT
-- ═══════════════════════════════════════
local function respawnAuCheckpoint(player)
local data = progressionJoueurs[player.UserId]
if not data then return end
local character = player.Character
if not character then return end
local rootPart = character:FindFirstChild("HumanoidRootPart")
if not rootPart then return end
local position = getPositionCheckpoint(data.checkpointPart)
rootPart.CFrame = CFrame.new(position + CONFIG.offsetRespawn)
end
-- ═══════════════════════════════════════
-- VALIDATION D'UN CHECKPOINT
-- ═══════════════════════════════════════
local function validerCheckpoint(player, indexCP)
local data = progressionJoueurs[player.UserId]
if not data then return false end
-- Vérifier l'ordre si activé
if CONFIG.sauvegarderOrdre and indexCP ~= data.indexActuel + 1 then
return false -- ignore si ce n'est pas le suivant
end
if indexCP > #checkpoints or indexCP <= data.indexActuel then return false end
data.indexActuel = indexCP
data.checkpointPart = checkpoints[indexCP]
if CONFIG.afficherMessages then
local character = player.Character
DialogueModule.creerDialogue(character, "🏁 " .. player.Name .. " a atteint le checkpoint " .. indexCP .. "/" .. #checkpoints)
end
-- Dernier checkpoint = fin du parcours
if indexCP == #checkpoints then
if CONFIG.afficherMessages then
local character = player.Character
DialogueModule.creerDialogue(character, "🎉 " .. player.Name .. " a terminé le parcours !")
end
-- Ajoute ici ta logique de fin (récompense, téléportation...)
end
return true
end
-- ═══════════════════════════════════════
-- CONNEXION DES TOUCHES DE CHAQUE CHECKPOINT
-- ═══════════════════════════════════════
local function connecterCheckpoints()
for index, cp in ipairs(checkpoints) do
local part = cp:IsA("Model") and (cp.PrimaryPart or cp:FindFirstChildOfClass("BasePart")) or cp
if part then
-- Couleur initiale pour visualiser l'ordre
if CONFIG.checkpointInitial then
part.BrickColor = CONFIG.checkpointInitial
end
part.Touched:Connect(function(hit)
local character = hit.Parent
local player = Players:GetPlayerFromCharacter(character)
if not player then return end
local data = progressionJoueurs[player.UserId]
if not data then return end
-- Déjà validé
if data.indexActuel >= index then return end
if validerCheckpoint(player, index) then
-- Allumer le checkpoint pour ce joueur (visuel global simplifié)
if CONFIG.checkpointValidated then
part.BrickColor = CONFIG.checkpointValidated
end
end
end)
end
end
end
--
-- GESTION DES JOUEURS
--
local function initialiserJoueur(player)
progressionJoueurs[player.UserId] = {
indexActuel = 0,
checkpointPart = checkpoints[1], -- spawn initial = checkpoint 1
}
player.CharacterAdded:Connect(function(character)
task.wait(0.2) -- laisser le personnage se charger
respawnAuCheckpoint(player)
end)
end
-- supprimer la progression du joueur
local function nettoyerJoueur(player)
progressionJoueurs[player.UserId] = nil
end
--
-- LANCEMENT
--
Players.PlayerAdded:Connect(initialiserJoueur)
Players.PlayerRemoving:Connect(nettoyerJoueur)
for _, player in ipairs(Players:GetPlayers()) do
initialiserJoueur(player)
end
connecterCheckpoints()
Rangement des Checkpoints (getCheckpointsTries)
Dans Roblox, quand le jeu se lance, les objets ne s’installent pas toujours dans l’ordre. Le script doit donc faire le tri.
- Il va chercher tous les blocs dans le dossier « Checkpoints ».
- Il regarde leur nom (ex: « Checkpoint1 », « Checkpoint2 », « Checkpoint3 »).
- Il extrait les chiffres grâce à une formule magique (
%d+) et les trie du plus petit au plus grand dans une liste ordonnée
Le carnet de notes du jeu (progressionJoueurs)
Le jeu a besoin d’une mémoire pour savoir où en est chaque joueur. Pour cela, il utilise un tableau (comme une liste de classe) :
lualocal progressionJoueurs = {}
Quand un joueur se connecte, le script lui crée une fiche :
- Le bloc de réapparition (le tout premier checkpoint).
- Son niveau actuel (commence à 0).
Le Respawn (La réapparition après une chute)
Quand ton personnage meurt ou réapparaît, la fonction respawnAuCheckpoint se déclenche :
- Le script cherche le nom du joueur dans son carnet de notes.
- Il trouve la position 3D (X, Y, Z) du dernier checkpoint validé.
- Il téléporte le joueur à cette position, en le surélevant légèrement (grâce à l’offset de 3 blocs défini dans la configuration) pour qu’il ne s’enfonce pas dans le bloc.
Toucher et Valider un Checkpoint (validerCheckpoint)
C’est ici que la magie opère quand tes pieds touchent une plaque :
- Le détecteur (
Touched) : Chaque checkpoint possède un capteur invisible. Dès qu’un joueur marche dessus, le script se réveille. - La vérification anti-triche : Si
sauvegarderOrdreest activé, le script vérifie si le checkpoint touché est bien le suivant dans la liste (par exemple, passer du 2 au 3). Si tu essaies de sauter directement du 1 au 3, le jeu t’ignore ! - La mise à jour : Si tout est bon :
- Le jeu met à jour ta fiche dans le carnet.
- Le checkpoint change de couleur (il devient vert pour te montrer visuellement que c’est bon).
- Un message s’affiche dans le chat grâce à un module de dialogue (ex: » Joueur1 a atteint le checkpoint 3/5″).
- Si c’est le tout dernier checkpoint, une fête se déclenche ( » Joueur1 a terminé le parcours ! »).
L’arrivée et le départ des joueurs
Tout en bas du script, le jeu surveille les connexions :
- Un joueur arrive (
PlayerAdded) : On crée sa fiche de suivi et on prépare son personnage pour qu’il soit téléporté à son dernier checkpoint à chaque fois qu’il réapparaît. - Un joueur s’en va (
PlayerRemoving) : On efface sa fiche du carnet de notes pour ne pas encombrer inutilement la mémoire du serveur du jeu (c’est le nettoyage).
Ce qu’il faut retenir (les concepts clés de programmation) :
- Les Variables (
local ...) : Des boîtes pour ranger des informations (la couleur des blocs, les coordonnées…). - Les Tableaux (
{}) : Des listes pour ranger des groupes d’objets (les checkpoints dans l’ordre) ou des informations complexes (la liste des joueurs et leur niveau). - Les Événements (
.Touched,.PlayerAdded) : Des déclencheurs qui disent au script : « Hé ! Quelque chose s’est passé, exécute le code maintenant ! »
