Catégories
Jeu vidéo ROBLOX ROBLOX-NIVEAU01

Gérer des Checkpoints non Ordonnés

Les checkpoints sont des points de sauvegarde dans un jeu. Quand un joueur touche un checkpoint, sa position est enregistrée. Si le joueur meurt ou revient dans la partie, il réapparaît au dernier checkpoint touché.

Dans ce script, les checkpoints ne sont pas ordonnés : le joueur peut les toucher dans n’importe quel ordre.

  1. Comment parcourir les checkpoints dans un dossier avec une boucle for.
  2. Comment stocker le dernier checkpoint pour chaque joueur.
  3. Comment détecter quand un joueur revient dans la partie et le téléporter à son dernier checkpoint.

Préparation dans Roblox Studio

Pour tester ce script, suis ces étapes :

  1. Créer un dossier pour les checkpoints :
    • Dans Workspace, crée un dossier nommé CheckpointsFolder.
  2. Ajouter des checkpoints :
    • Ajoute plusieurs Part dans CheckpointsFolder.
    • Nomme-les comme tu veux (ex: Checkpoint1, Checkpoint2, etc.).
    • Place-les à différents endroits dans ton jeu.
  3. Ajouter le script :
    • Crée un Script dans ServerScriptService et copie le code suivant.
    • Le script supprime automatiquement la Baseplate pour éviter les interférences.
    • Si tu veux garder un sol, ajoute une Part plate dans Workspace.

Voici le script commenté pour comprendre :

-- Récupérer les services et objets nécessaires
local Players = game:GetService("Players")  -- Service pour gérer les joueurs

-- Récupérer la Baseplate et le dossier des checkpoints
local baseplate = workspace:WaitForChild("Baseplate")
local checkpointsFolder = workspace:WaitForChild("CheckpointsFolder")

-- Tableau pour stocker le dernier checkpoint de chaque joueur
-- Format : playerCheckpoints[userId] = CFrame du dernier checkpoint
local playerCheckpoints = {}

-- Supprimer la Baseplate (pour éviter les interférences)
baseplate:Destroy()

-- Fonction appelée quand un personnage est ajouté (ex: quand un joueur respawn)
local function onCharacterAdded(character, userId)
    -- Récupérer le dernier checkpoint du joueur
    local storedCFrame = playerCheckpoints[userId]

    -- Si le joueur n'a pas de checkpoint enregistré, on ne fait rien
    if not storedCFrame then
        return
    end

    -- Attendre que le HumanoidRootPart existe (partie principale du personnage)
    local humanoidRootPart = character:WaitForChild("HumanoidRootPart")

    -- Ajouter un petit décalage aléatoire pour éviter que les joueurs spawnent au même endroit
    local offset = Vector3.new(math.random(-1, 1), 4, math.random(-1, 1))

    -- Téléporter le joueur à son dernier checkpoint + décalage
    humanoidRootPart.CFrame = storedCFrame + offset
end

-- Fonction appelée quand un joueur touche un checkpoint
local function onTouched(checkpoint, hit)
    -- Récupérer le personnage qui a touché le checkpoint
    local character = hit.Parent

    -- Vérifier si c'est bien un personnage avec un Humanoid (un joueur)
    if not character or not character:FindFirstChildOfClass("Humanoid") then
        return
    end

    -- Récupérer le joueur associé au personnage
    local player = Players:GetPlayerFromCharacter(character)
    if not player then
        return
    end

    -- Récupérer l'ID unique du joueur
    local userId = player.UserId

    -- Connecter l'événement CharacterAdded UNE SEULE FOIS par joueur
    -- Cela évite de connecter plusieurs fois le même événement
    if not playerCheckpoints[userId] then
        player.CharacterAdded:Connect(function(newCharacter)
            onCharacterAdded(newCharacter, userId)
        end)
    end

    -- Stocker le CFrame (position + rotation) du checkpoint pour ce joueur
    playerCheckpoints[userId] = checkpoint.CFrame
end

-- Parcourir tous les checkpoints dans le dossier CheckpointsFolder
for _, checkpoint in ipairs(checkpointsFolder:GetChildren()) do
    -- Vérifier si l'objet est une BasePart (ex: une Part)
    if not checkpoint:IsA("BasePart") then continue end

    -- Configurer le checkpoint
    checkpoint.Anchored = true          -- Empêcher le checkpoint de bouger
    checkpoint.CanCollide = true        -- Permettre les collisions
    checkpoint.Transparency = 0.5       -- Rendre le checkpoint semi-transparent
    checkpoint.Material = Enum.Material.Neon  -- Matériau Neon pour un effet lumineux
    checkpoint.BrickColor = BrickColor.new("Bright blue")  -- Couleur bleue vive

    -- Connecter l'événement Touched pour détecter quand un joueur touche le checkpoint
    checkpoint.Touched:Connect(function(hit)
        onTouched(checkpoint, hit)
    end)
end

Le script supprime automatiquement la Baseplate.

1. La boucle for pour parcourir les checkpoints

for _, checkpoint in ipairs(checkpointsFolder:GetChildren()) do
    if not checkpoint:IsA("BasePart") then continue end
    -- Configurer le checkpoint...
end
  • checkpointsFolder:GetChildren() :
    • Récupère tous les enfants directs du dossier CheckpointsFolder.
    • Retourne une liste de tous les objets dans ce dossier.
  • ipairs(...) :
    • Parcourt la liste des enfants un par un.
    • _ est une variable temporaire (non utilisée) qui représente l’index (position dans la liste).
    • checkpoint est l’objet actuel dans la boucle (ex: une Part).
  • if not checkpoint:IsA("BasePart") then continue end :
    • Vérifie si checkpoint est une BasePart (ex: une Part).
    • Si ce n’est pas le cas (ex: un Folder, un Script), on passe à l’itération suivante avec continue.
  • Pourquoi utiliser GetChildren ?
    • On veut trouver tous les checkpoints dans le dossier CheckpointsFolder.
    • GetChildren est plus rapide que GetDescendants car on ne cherche que les enfants directs (pas les petits-enfants).

2. Stocker le checkpoint pour le joueur

local playerCheckpoints = {}  -- Tableau pour stocker les checkpoints

-- Dans la fonction onTouched :
playerCheckpoints[userId] = checkpoint.CFrame
  • playerCheckpoints :
    • C’est un tableau associatif où :
      • Clé = userId (l’ID unique du joueur).
      • Valeur = CFrame du dernier checkpoint touché par le joueur.
  • checkpoint.CFrame :
    • Le CFrame est une propriété qui stocke la position et la rotation d’un objet.
    • Quand un joueur touche un checkpoint, on stocke son CFrame dans playerCheckpoints[userId].
  • Pourquoi utiliser userId comme clé ?
    • Chaque joueur a un ID unique (UserId).
    • Cela permet de stocker un checkpoint différent pour chaque joueur.

3. Détecter quand le joueur revient dans la partie

-- Dans la fonction onTouched :
if not playerCheckpoints[userId] then
    player.CharacterAdded:Connect(function(newCharacter)
        onCharacterAdded(newCharacter, userId)
    end)
end

-- Fonction onCharacterAdded :
local function onCharacterAdded(character, userId)
    local storedCFrame = playerCheckpoints[userId]
    if not storedCFrame then return end

    local humanoidRootPart = character:WaitForChild("HumanoidRootPart")
    local offset = Vector3.new(math.random(-1, 1), 4, math.random(-1, 1))
    humanoidRootPart.CFrame = storedCFrame + offset
end
  • player.CharacterAdded:Connect(...) :
    • Événement déclenché quand un joueur respawn (réapparaît après être mort ou avoir rejoint le jeu).
    • On connecte une seule fois cet événement par joueur (grâce à if not playerCheckpoints[userId]).
  • onCharacterAdded :
    • Cette fonction est appelée quand un joueur réapparaît.
    • Elle téléporte le joueur à son dernier checkpoint (storedCFrame).
    • offset : Ajoute un petit décalage aléatoire pour éviter que plusieurs joueurs spawnent au même endroit.
  • WaitForChild("HumanoidRootPart") :
    • Attend que le HumanoidRootPart (partie centrale du personnage) existe avant de le téléporter.
    • Cela évite les erreurs si le personnage n’est pas encore complètement chargé.

QCM : Teste ta compréhension !

Sur la boucle for et GetChildren :

  1. Que fait checkpointsFolder:GetChildren() ?
    • a) Récupère tous les enfants directs du dossier CheckpointsFolder.
    • b) Récupère tous les descendants (enfants, petits-enfants, etc.) du dossier.
    • c) Supprime tous les enfants du dossier.
  1. Pourquoi utilise-t-on if not checkpoint:IsA("BasePart") then continue end ?
    • a) Pour ignorer les objets qui ne sont pas des BasePart (ex: des Folder).
    • b) Pour supprimer les checkpoints.
    • c) Pour changer la couleur des checkpoints.
  1. Que contient la variable checkpoint dans la boucle for ?
    • a) Un objet (ex: une Part) dans le dossier CheckpointsFolder.
    • b) Un nombre.
    • c) Un joueur.

Sur le stockage des checkpoints :

  1. À quoi sert playerCheckpoints[userId] = checkpoint.CFrame ?
    • a) Stocker la position et la rotation du checkpoint pour un joueur.
    • b) Supprimer le checkpoint.
    • c) Changer la taille du checkpoint.
  1. Pourquoi utilise-t-on userId comme clé dans playerCheckpoints ?
    • a) Parce que chaque joueur a un ID unique, ce qui permet de stocker un checkpoint différent pour chaque joueur.
    • b) Parce que c’est plus rapide.
    • c) Parce que c’est obligatoire.
  1. Que fait playerCheckpoints[userId] si userId n’existe pas dans le tableau ?
    • a) Retourne nil.
    • b) Crée une erreur.
    • c) Retourne 0.

Sur la détection du retour du joueur :

  1. À quoi sert player.CharacterAdded:Connect(...) ?
    • a) Exécuter une fonction quand un joueur réapparaît dans la partie.
    • b) Créer un nouveau personnage.
    • c) Supprimer le personnage.
  1. Pourquoi utilise-t-on WaitForChild("HumanoidRootPart") ?
    • a) Pour attendre que le HumanoidRootPart existe avant de le téléporter.
    • b) Pour supprimer le HumanoidRootPart.
    • c) Pour changer la couleur du personnage.
  1. Que fait humanoidRootPart.CFrame = storedCFrame + offset ?
    • a) Téléporte le joueur à son dernier checkpoint avec un petit décalage aléatoire.
    • b) Fait grandir le joueur.
    • c) Supprime le joueur.
  1. Pourquoi ajoute-t-on un offset aléatoire ?
    • a) Pour éviter que plusieurs joueurs spawnent exactement au même endroit.
    • b) Pour rendre le jeu plus difficile.
    • c) Pour changer la taille du joueur.

Idées pour aller plus loin

1. Ajouter un effet visuel aux checkpoints

  • Objectif : Faire clignoter les checkpoints quand un joueur les touche.

2. Ajouter un son quand un checkpoint est touché

  • Objectif : Jouer un son quand un joueur touche un checkpoint.