Ce système affiche un chrono qui mesure le temps mis par un joueur pour aller d’un bloc de départ à un bloc d’arrivée.
Le script serveur est placé sur les blocs (départ/arrivée) : il détecte quand le joueur les touche (Touched) et décide quand le chrono doit démarrer ou s’arrêter.
Le LocalScript, lui, tourne uniquement sur l’ordinateur du joueur : il gère l’affichage du chrono à l’écran (le TextLabel).
Le serveur ne peut pas modifier directement l’écran d’un joueur : il doit envoyer un message au client via un RemoteEvent.
Le RemoteEvent fonctionne comme une messagerie entre le serveur et le client : quand le joueur touche le bloc de départ, le serveur « fire » (envoie) l’événement StartEvent.
Le LocalScript écoute cet événement avec OnClientEvent:Connect(...) et, dès qu’il le reçoit, enregistre l’heure de départ (tick()) et active running = true.
De la même façon, quand le joueur touche le bloc d’arrivée, le serveur envoie WinEvent, et le LocalScript reçoit ce signal pour arrêter le chrono (running = false).
Pendant que running est actif, la fonction RunService.Heartbeat recalcule et affiche le temps écoulé à chaque frame (60 fois par seconde environ).
La fonction formatTime transforme le nombre de secondes brut en un affichage lisible du type 01:23 (minutes:secondes).
En résumé : le serveur décide (quand démarrer/arrêter), les RemoteEvents transmettent l’info, et le LocalScript affiche le résultat à l’écran du joueur.
Petit rappel pour bien comprendre
Script serveur : tourne sur l’ordinateur qui héberge la partie. Il contrôle les règles du jeu, mais ne peut pas modifier ce qui s’affiche à l’écran d’un joueur précis.
LocalScript : tourne uniquement sur l’ordinateur du joueur. Il gère l’affichage (interface, sons, caméra…) mais ne peut pas être utilisé pour des règles importantes du jeu (sinon un joueur pourrait tricher).
RemoteEvent : le « pont » entre les deux. Le serveur envoie une info avec FireClient(), et le LocalScript la reçoit avec OnClientEvent:Connect().
QCM pour bien comprendre
1. Où s’exécute un LocalScript ? A. Sur le serveur du jeu B. Sur l’ordinateur du joueur uniquement C. Sur tous les ordinateurs en même temps D. Nulle part, c’est juste un fichier texte
2. Pourquoi ne peut-on pas modifier directement le TextLabel depuis le script serveur ? A. Parce que c’est interdit par Roblox B. Parce que le serveur n’a pas accès à l’affichage local de chaque joueur C. Parce que le TextLabel n’existe pas sur le serveur D. Parce que ça coûte trop cher en mémoire
3. À quoi sert un RemoteEvent ? A. À supprimer un joueur du jeu B. À transmettre une information entre le serveur et un client C. À changer la couleur d’un bloc automatiquement D. À sauvegarder les données du joueur
4. Que fait startEvent:FireClient(player) côté serveur ? A. Il supprime le joueur B. Il envoie un signal au client précis pour déclencher une action C. Il démarre le jeu pour tous les joueurs D. Il crée un nouveau RemoteEvent
5. Que fait RunService.Heartbeat dans ce script ? A. Il vérifie les battements de cœur du joueur B. Il exécute du code à chaque frame, ici pour actualiser l’affichage du chrono C. Il redémarre le serveur régulièrement D. Il compte le nombre de joueurs connectés
6. Que se passe-t-il si running vaut false ? A. Le chrono continue de s’incrémenter B. Le texte du chrono arrête de se mettre à jour C. Le joueur est téléporté au départ D. Le RemoteEvent est détruit
Crée un part pour déterminer le départ du chrono et un part pour déterminer le stop du chrono.
Puis deux RemoteEvent pour gérer le démarrage et l’arrêt du chrono :
Puis script sur le serveur pour gérer les collisions entre le player et les parts de départ et d’arrivée :
local replicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = replicatedStorage:WaitForChild("Coursetimecheck")
local startEvent = remoteEvent.StartEvent
local winEvent = remoteEvent.WinEvent
local start = script.Parent.StartPart
local succes = script.Parent.SuccessPart
succes.SurfaceGui.Enabled = false
succes.ParticleEmitter.Enabled = false
succes.Anchored = true
succes.CanCollide = true
succes.CanTouch = true
start.Anchored = true
start.CanCollide = false
start.CanTouch = true
start.Transparency = 1
succes.Touched:Connect(function(hit)
local character = hit.Parent
local humanoid = character and character:FindFirstChild("Humanoid")
if not humanoid then return end
if succes.SurfaceGui.Enabled then return end
remoteEvent.WinEvent:FireClient(game.Players:GetPlayerFromCharacter(character))
succes.SurfaceGui.Enabled = true
succes.ParticleEmitter.Enabled = true
end)
start.Touched:Connect(function(hit)
local character = hit.Parent
local humanoid = character and character:FindFirstChild("Humanoid")
if not humanoid then return end
local player = game.Players:GetPlayerFromCharacter(character)
if not player then return end -- sécurité si ce n'est pas un joueur (NPC par ex.)
print("StartEvent déclenché pour " .. player.Name)
startEvent:FireClient(player)
end)
Et également un localScript pour l’affichage du chrono pour le joueur :
-- Récupération des services
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
-- Récupération du joueur actuel et de la PlayerGui
local player = Players.LocalPlayer
local playerGui = player:WaitForChild("PlayerGui")
-- Récupération de l'UI du chrono
local chrono = playerGui:WaitForChild("ScreenGui"):WaitForChild("Frame"):WaitForChild("ChronoLabel")
-- Récupération des RemoteEvents start et stop du chrono
local remoteEventsFolder = ReplicatedStorage:WaitForChild("Coursetimecheck")
local startEvent = remoteEventsFolder:WaitForChild("StartEvent")
local stopEvent = remoteEventsFolder:WaitForChild("WinEvent")
-- Fonction pour formater le temps en minutes:secondes
local function formatTime(t)
local minutes = math.floor(t / 60)
local seconds = math.floor(t % 60)
return string.format("%02d:%02d", minutes, seconds)
end
-- Variables globales pour suivre le temps et l'état du chrono
local startTime = nil
chrono.Text = "00:00"
local running = false
-- Connexion des événements serveur au client
startEvent.OnClientEvent:Connect(function()
startTime = tick()
running = true
end)
stopEvent.OnClientEvent:Connect(function()
running = false
end)
-- Mise à jour continue de l'affichage du chrono
RunService.Heartbeat:Connect(function()
if not running or not startTime then return end
chrono.Text = formatTime(tick() - startTime)
end)
Ce script est attaché à un Part (bloc) et détecte quand un joueur le touche, via l’événement Touched.
Il vérifie que c’est bien un personnage avec un Humanoid, et bloque les déclenchements répétés grâce à un système de cooldown (table cooldowns).
Si le joueur n’a pas encore été rétréci/agrandi, le script sauvegarde sa taille actuelle dans un dossier Scale, puis applique la taille SCALEMAX (0.3) à sa hauteur, largeur, profondeur et tête.
Si le joueur a déjà été modifié (le dossier Scale existe), le script lui redonne sa taille d’origine et supprime le dossier.
Autrement dit : c’est un bloc « grandir/rétrécir » qui bascule (toggle) la taille du joueur à chaque contact, avec une seconde d’attente avant de pouvoir réutiliser le bloc.
QCM : Testez votre compréhension !
1. Que fait l’événement Touched dans ce script ? A. Il vérifie si le joueur a cliqué sur le bloc B. Il détecte quand quelque chose touche la Part C. Il compte le nombre de joueurs dans le jeu D. Il détruit le bloc
2. À quoi sert la variable COOLDOWN ? A. À changer la couleur du bloc B. À définir la taille maximale du joueur C. À empêcher de réutiliser le bloc trop vite D. À supprimer le personnage
3. Que se passe-t-il si le joueur touche le bloc une deuxième fois (après le cooldown) ? A. Rien, ça ne marche qu’une fois B. Le joueur reprend sa taille normale C. Le joueur devient minuscule D. Le jeu plante
4. À quoi sert le dossier (IntValue) nommé "Scale" ? A. À afficher un message au joueur B. À mémoriser la taille d’origine du joueur C. À compter le temps de cooldown D. À stocker le nom du joueur
5. Pourquoi utilise-t-on une table cooldowns avec le character comme clé ? A. Pour donner un nom à chaque joueur B. Pour savoir si CE joueur précis est en cooldown C. Pour compter les points de chaque joueur D. Pour changer la vitesse du joueur
local part = script.Parent
local SCALEMAX = 0.3
local COOLDOWN = 1 -- secondes avant de pouvoir re-déclencher
local cooldowns = {} -- [character] = true pendant le cooldown
part.Touched:Connect(function(plr)
local character = plr.Parent
local humanoid = character and character:FindFirstChild("Humanoid")
if not humanoid then return end
if cooldowns[character] then return end
cooldowns[character] = true
local existingFolder = humanoid:FindFirstChild("Scale")
if existingFolder then
humanoid.BodyHeightScale.Value = existingFolder.Value
humanoid.BodyWidthScale.Value = existingFolder.Value
humanoid.BodyDepthScale.Value = existingFolder.Value
humanoid.HeadScale.Value = existingFolder.Value
existingFolder:Destroy()
else
local folder = Instance.new("IntValue")
folder.Name = "Scale"
folder.Parent = humanoid
folder.Value = humanoid.BodyHeightScale.Value
humanoid.BodyHeightScale.Value = SCALEMAX
humanoid.BodyWidthScale.Value = SCALEMAX
humanoid.BodyDepthScale.Value = SCALEMAX
humanoid.HeadScale.Value = SCALEMAX
end
task.wait(COOLDOWN)
cooldowns[character] = nil
end)
Ce script surveille une part (un bloc) dans le jeu, et attend qu’un joueur la touche.
Quand un joueur la touche, le script vérifie qu’il s’agit bien d’un personnage (avec un Humanoid, la partie du jeu qui gère la santé, les déplacements, etc.).
Si c’est bien un joueur, sa vitesse de déplacement (WalkSpeed) passe à 50; il devient beaucoup plus rapide (par défaut, c’est 16).
QCM — vérifie ta compréhension
1. Que fait part.Touched:Connect(...) ? A) Il détruit la part B) Il détecte quand quelque chose touche la part C) Il déplace la part D) Il change la couleur de la part
2. Pourquoi le script vérifie if not humanoid then return end ? A) Pour vérifier que la part existe B) Pour arrêter le script si ce qui a touché n’est pas un personnage (par exemple un objet sans Humanoid) C) Pour ralentir le joueur D) Pour supprimer le Humanoid
3. Que représente Humanoid dans un personnage Roblox ? A) Le nom du joueur B) La couleur de la peau C) La partie qui gère la santé, les déplacements, etc. D) Un accessoire du personnage
4. Que se passe-t-il quand humanoid.WalkSpeed = 50 s’exécute ? A) Le joueur devient invisible B) Le joueur saute plus haut C) Le joueur se déplace plus vite D) Le joueur perd de la vie
5. Si un objet SANS Humanoid (comme une simple balle) touche la part, que se passe-t-il ? A) Le script plante avec une erreur B) Rien, le script s’arrête grâce au return C) La balle devient rapide D) Le jeu redémarre
local part = script.Parent
part.Touched:Connect(function(plr)
local character = plr.Parent
local humanoid = character and character:FindFirstChild("Humanoid")
if not humanoid then return end
humanoid.WalkSpeed = 50
end)
Bascule courir plus vite / normalement
Quand un joueur touche la part, le script regarde s’il a déjà une vitesse « boostée » (mémorisée dans un petit objet nommé « Speed ») : si oui, il lui rend sa vitesse normale, sinon il sauvegarde sa vitesse actuelle et le rend très rapide (50).
Un système de « cooldown » (temps d’attente) empêche le joueur de retoucher la part plusieurs fois par seconde et de faire buguer le changement de vitesse.
Ainsi, la part fonctionne comme un interrupteur : un coup pour accélérer, un coup pour revenir à la normale, avec une petite pause obligatoire entre deux touches.
QCM — vérifie ta compréhension
1. À quoi sert la variable cooldowns ? A) À compter combien de joueurs ont touché la part B) À empêcher un joueur de redéclencher l’effet plusieurs fois trop vite C) À stocker la couleur de la part D) À sauvegarder le nom du joueur
2. Que fait l’objet IntValue nommé « Speed » ? A) Il affiche un message au joueur B) Il mémorise la vitesse de marche du joueur avant le boost, pour pouvoir la restaurer plus tard C) Il détruit le personnage D) Il change la couleur de la part
3. Que se passe-t-il si le joueur touche la part une seconde fois (sans cooldown actif) ? A) Sa vitesse redevient normale, car le dossier « Speed » existe déjà B) Rien ne se passe C) Sa vitesse augmente encore plus D) Le jeu plante
4. Pourquoi utilise-t-on task.wait(COOLDOWN) à la fin de la fonction ? A) Pour ralentir tous les joueurs du jeu B) Pour attendre 1 seconde avant de permettre au joueur de redéclencher l’effet C) Pour détruire la part après 1 seconde D) Pour attendre que le joueur meure
5. Si un joueur touche la part pendant que son cooldown est actif, que fait le script ? A) Il double sa vitesse B) Il arrête la fonction immédiatement avec return, sans rien changer C) Il redémarre le cooldown D) Il supprime le dossier « Speed »
local part = script.Parent
local SPEEDMAX = 50
local COOLDOWN = 1 -- secondes avant de pouvoir re-déclencher
local cooldowns = {} -- [character] = true pendant le cooldown
part.Touched:Connect(function(plr)
local character = plr.Parent
local humanoid = character and character:FindFirstChild("Humanoid")
if not humanoid then return end
if cooldowns[character] then return end
cooldowns[character] = true
local existingFolder = humanoid:FindFirstChild("Speed")
if existingFolder then
humanoid.WalkSpeed = existingFolder.Value
existingFolder:Destroy()
else
local folder = Instance.new("IntValue")
folder.Name = "Speed"
folder.Parent = humanoid
folder.Value = humanoid.WalkSpeed
humanoid.WalkSpeed = SPEEDMAX
end
task.wait(COOLDOWN)
cooldowns[character] = nil
end)
Essaye le même système pour faire sauter plus haut :
humanoid.JumpHeight = 20
local part = script.Parent
local SCALEMAX = 4
local COOLDOWN = 1 -- secondes avant de pouvoir re-déclencher
local cooldowns = {} -- [character] = true pendant le cooldown
part.Touched:Connect(function(plr)
local character = plr.Parent
local humanoid = character and character:FindFirstChild("Humanoid")
if not humanoid then return end
if cooldowns[character] then return end
cooldowns[character] = true
local existingFolder = humanoid:FindFirstChild("Scale")
if existingFolder then
humanoid.BodyHeightScale.Value = existingFolder.Value
humanoid.BodyWidthScale.Value = existingFolder.Value
humanoid.BodyDepthScale.Value = existingFolder.Value
humanoid.HeadScale.Value = existingFolder.Value
existingFolder:Destroy()
else
local folder = Instance.new("IntValue")
folder.Name = "Scale"
folder.Parent = humanoid
folder.Value = humanoid.BodyHeightScale.Value
humanoid.BodyHeightScale.Value = SCALEMAX
humanoid.BodyWidthScale.Value = SCALEMAX
humanoid.BodyDepthScale.Value = SCALEMAX
humanoid.HeadScale.Value = SCALEMAX
end
task.wait(COOLDOWN)
cooldowns[character] = nil
end)
Ce script Roblox rend transparents (invisibles à 75%) les joueurs ou leurs accessoires (comme un chapeau ou une épée) quand ils touchent une pièce (la part). Il vérifie si ce qui a touché la pièce est un personnage avec un Humanoid (un joueur). Ensuite, il parcourt toutes les parties du personnage (corps, accessoires) et les rend transparentes. Seules les pièces 3D (BasePart, MeshPart) ou les textures (Decal) sont modifiées.
QCM : Teste ta compréhension !
1. Que fait ce script quand un joueur touche la pièce ? A) Il supprime le joueur. B) Il rend le joueur et ses accessoires transparents. C) Il change la couleur du joueur en rouge. D) Il fait exploser la pièce.
2. Pourquoi vérifie-t-on if not humanoid then return end ? A) Pour éviter que le script ne s’applique aux objets qui ne sont pas des joueurs. B) Pour accélérer le jeu. C) Pour rendre la pièce invisible. D) Pour ajouter un accessoire au joueur.
3. Que signifie descendant.Transparency = 0.75 ? A) La pièce devient complètement invisible. B) La pièce devient à 75% transparente (presque invisible). C) La pièce clignote. D) La pièce devient plus grande.
4. Quel type d’objet n’est PAS modifié par ce script ? A) Un chapeau (Accessory). B) Une épée (MeshPart). C) Un mur (Part). D) Une texture (Decal) sur un accessoire.
-- Script pour rendre invisible les joueurs qui touchent la part
local part = script.Parent
part.Touched:Connect(function(hit)
local character = hit.Parent
local humanoid = character and character:FindFirstChild("Humanoid")
if not humanoid then return end
for _, chose in ipairs(character:GetChildren()) do
if chose:IsA("Accessory") then
-- Rend transparent les BasePart/Decal de l'accessoire
for _, descendant in ipairs(chose:GetDescendants()) do
if descendant:IsA("BasePart") or descendant:IsA("Decal") then
descendant.Transparency = 0.75
end
end
elseif chose:IsA("MeshPart") then
-- Le MeshPart lui-même est la part à rendre transparente
chose.Transparency = 0.75
end
end
end)
Bascule invisible/visible
Ce script Roblox permet de rendre un joueur transparent à 50% quand il touche une pièce, puis de le rendre à nouveau visible s’il la touche une deuxième fois. Il utilise un délai de 1 seconde (COOLDOWN) pour éviter de déclencher l’effet trop vite. Un dossier caché (Transparency) est créé dans le personnage pour « mémoriser » s’il est déjà transparent. Seuls les joueurs (avec un Humanoid) sont concernés, et leurs accessoires ou parties du corps deviennent transparents.
QCM : Teste ta compréhension !
1. Que fait ce script quand un joueur touche la pièce pour la première fois ? A) Il le supprime. B) Il le rend transparent à 50%. C) Il le rend complètement invisible. D) Il le fait sauter.
2. Pourquoi utilise-t-on cooldowns[character] = true ? A) Pour empêcher le joueur de déclencher l’effet plusieurs fois en 1 seconde. B) Pour rendre le joueur invincible. C) Pour changer la couleur de la pièce. D) Pour ajouter un accessoire au joueur.
3. À quoi sert le dossier Transparency dans le Humanoid ? A) À stocker si le joueur est déjà transparent pour inverser l’effet au prochain contact. B) À rendre le joueur plus rapide. C) À supprimer le personnage. D) À afficher un message.
4. Que se passe-t-il si un joueur touche la pièce une deuxième fois ? A) Il devient à nouveau visible (transparence à 0%). B) Il devient complètement invisible. C) Il explose. D) Rien, le script ne fait plus rien.
-- Script pour rendre invisible les joueurs qui touchent la part
local part = script.Parent
local TRANSPARENCE_ACTIVE = 0.5
local TRANSPARENCE_INACTIVE = 0
local COOLDOWN = 1 -- secondes avant de pouvoir re-déclencherlocal cooldowns = {} -- [character] = true pendant le cooldownlocal function playerTransparency(character, transparency)
for _, chose in ipairs(character:GetChildren()) do
if chose:IsA("Accessory") then
-- Rend transparent les BasePart/Decal de l'accessoire
for _, descendant in ipairs(chose:GetDescendants()) do
if descendant:IsA("BasePart") or descendant:IsA("Decal") then
descendant.Transparency = transparency
end
end
elseif chose:IsA("MeshPart") then
-- Le MeshPart lui-même est la part à rendre transparente
chose.Transparency = transparency
end
end
end
part.Touched:Connect(function(hit)
local character = hit.Parent
local humanoid = character and character:FindFirstChild("Humanoid")
if not humanoid then return end
if cooldowns[character] then return end
cooldowns[character] = true
local existingFolder = humanoid:FindFirstChild("Transparency")
local transparency if existingFolder then
existingFolder:Destroy()
transparency = TRANSPARENCE_INACTIVE
else
local folder = Instance.new("Folder")
folder.Name = "Transparency"
folder.Parent = humanoid
transparency = TRANSPARENCE_ACTIVE
end
playerTransparency(character, transparency)
task.wait(COOLDOWN)
cooldowns[character] = nil
end)
Gestion d’un folder pour gérer plusieurs parts pour rendre invisible
-- Boucle sur toutes les parts du folder des parts pour rendre invisible
local folder = workspace:FindFirstChild("Zone Invisibilite", true)
for _, part in ipairs(folder:GetChildren()) do
if not part:IsA("BasePart") then return end
part.Touched:Connect(function(hit)
local character = hit.Parent
local humanoid = character and character:FindFirstChild("Humanoid")
if not humanoid then return end
if cooldowns[character] then return end
cooldowns[character] = true
local existingFolder = humanoid:FindFirstChild("Transparency")
local transparency
if existingFolder then
existingFolder:Destroy()
transparency = TRANSPARENCE_INACTIVE
else
local folder = Instance.new("Folder")
folder.Name = "Transparency"
folder.Parent = humanoid
transparency = TRANSPARENCE_ACTIVE
end
playerTransparency(character, transparency)
task.wait(COOLDOWN)
cooldowns[character] = nil
end)
end
Traverser un mur quand le player est transparent
Quand un personnage touche la Part, le script vérifie s’il a un Humanoid possédant un attribut/valeur nommé "Transparency" , si oui, il rend la Part traversable (CanCollide = false).
Quand ce même personnage arrête de toucher la Part (TouchEnded), le script refait la vérification et remet la Part solide (CanCollide = true).
Résultat : c’est un bloc qui devient traversable uniquement pour les joueurs possédant la valeur « Transparency » (par exemple des joueurs rendus invisibles/fantômes ailleurs dans le jeu), et redevient solide dès qu’ils sont passés.
QCM : Teste ta compréhension !
1. Que vérifie le script avant de rendre la Part traversable ? A. Que le joueur a un pseudo spécial B. Que le personnage possède une valeur nommée « Transparency » C. Que le joueur est en l’air D. Que la Part est de couleur rouge
2. Que fait part.CanCollide = false ? A. Le bloc devient invisible B. Le bloc disparaît définitivement C. Le bloc laisse passer les objets/joueurs à travers D. Le bloc explose
3. Quand se déclenche l’événement TouchEnded ? A. Quand le joueur commence à toucher la Part B. Quand le joueur arrête de toucher la Part C. Quand le joueur meurt D. Quand le jeu se termine
4. Que se passe-t-il si un joueur SANS la valeur « Transparency » touche la Part ? A. Il traverse quand même le bloc B. Rien ne change, la Part reste solide pour lui C. Il devient invisible D. La Part se détruit
5. Pourquoi remet-on CanCollide = true dans TouchEnded ? A. Pour empêcher d’autres joueurs (sans la bonne valeur) de traverser après B. Pour changer la couleur du bloc C. Pour supprimer le joueur D. Pour recommencer le jeu
local part = script.Parent
part.Touched:Connect(function(hit)
local character = hit.Parent
local humanoid = character and character:FindFirstChild("Humanoid")
if not humanoid then return end
local existingFolder = humanoid:FindFirstChild("Transparency")
if not existingFolder then return end
part.CanCollide= false
end)
part.TouchEnded:Connect(function(hit)
local character = hit.Parent
local humanoid = character and character:FindFirstChild("Humanoid")
if not humanoid then return end
local existingFolder = humanoid:FindFirstChild("Transparency")
if not existingFolder then return end
part.CanCollide= true
end)
local teleports = script.Parent
local teleportA = teleports.TeleportA
local teleportB = teleports.TeleportB
On récupère deux objets dans le jeu Roblox : la plateforme A (celle sur laquelle on va marcher) et la plateforme B (celle où on va arriver). Ces deux plateformes sont des enfants du script dans l’arbre du jeu.
L’événement Touched
teleportA.Touched:Connect(function(hit)
Touched est un événement Roblox : il se déclenche automatiquement dès que quelque chose touche la plateforme A. Le paramètre hit contient la pièce (la partie du corps) qui l’a touchée.
La vérification du joueur
local character = hit.Parent local humanoid = character and character:FindFirstChildOfClass("Humanoid") if not humanoid or humanoid.Health <= 0 then return end
On remonte d’un niveau pour trouver le personnage entier (hit.Parent), puis on cherche s’il contient un Humanoid (ce qui prouve que c’est bien un joueur, pas un mur ou une balle). Si rien de valide n’est trouvé, ou si le joueur est mort (Health <= 0), on arrête tout avec return.
La téléportation
local offset = Vector3.new(0, 2, 0) character:PivotTo(CFrame.new(teleportB.Position + offset))
Vector3.new(0, 2, 0) crée un décalage de 2 unités vers le haut pour que le joueur atterrisse au-dessus de la plateforme B et pas à l’intérieur. PivotTo est la fonction qui déplace instantanément tout le personnage à une nouvelle position — c’est ça la téléportation !
Le code complet de la téléportation
-- Configuration
local teleports = script.Parent
local teleportA = teleports.TeleportA
local teleportB = teleports.TeleportB
teleportA.Touched:Connect(function(hit)
-- Récupération du joueur
local character = hit.Parent
local humanoid = character and character:FindFirstChildOfClass("Humanoid")
if not humanoid or humanoid.Health <= 0 then return end
-- Décalage légert vers le haut pour poser le joueur sur la plateforme
local offset = Vector3.new(0, 2, 0)
character:PivotTo(CFrame.new(teleportB.Position + offset))
end)
Créer un script pour afficher un tableau de score au joueur sousServerScriptService :
Renommer le script leaderstats :
Saisir le code suivant pour un affichage d’une barre de scores :
local players = game:GetService("Players")
players.PlayerAdded:Connect(function(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
end)
Si tu lances ton jeu une barre s’affiche :
Si le score ne s’affiche pas vérifie :
Rajoute à ton script un score à afficher :
local players = game:GetService("Players")
players.PlayerAdded:Connect(function(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local score = Instance.new("IntValue")
score.Parent = leaderstats
score.Name = "Score"
score.Value = 0
end)
Le score s’affiche si tu lances ton jeu :
Exemple d’un script pour augmenter le score si le joueur click sur un ClickDetector :
local clickDetector = script.Parent.ClickDetector
clickDetector.MouseClick:Connect(function(player)
player:WaitForChild("leaderstats").Score.Value += 10
end)
Exemple d’un script pour augmenter le score si le joueur rentre en collision avec un part :
local myPart = script.Parent
myPart.Touched:Connect(function(hit)
-- Vérifie si c'est un joueur qui a touché la part
local joueur = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent)
if joueur then
-- Trouve le score du joueur dans Leaderstats
local leaderstats = joueur:FindFirstChild("leaderstats")
if leaderstats then
local score = leaderstats:FindFirstChild("Score")
if score then
-- Incrémente le score
score.Value = score.Value + 1
end
end
end
end)
Exemple d’un script pour augmenter le score si le joueur rentre en collision avec un part :
local myPart = script.Parent
myPart.Touched:Connect(function(hit)
-- Vérifie si c'est un joueur qui a touché la part
local joueur = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent)
if joueur then
-- Trouve le score du joueur dans Leaderstats
local leaderstats = joueur:FindFirstChild("leaderstats")
if leaderstats then
local score = leaderstats:FindFirstChild("Score")
if score then
-- Incrémente le score
score.Value = score.Value + 1
end
end
end
end)
Un système de score avec un ModuleScript
1. Créer un ModuleScript pour gérer les scores
-- ModuleScript dans ServerScriptService : "ScoreManager"
local ScoreManager = {}
-- Initialise le Leaderstats pour un joueur
function ScoreManager.initPlayer(player)
local leaderstats = Instance.new("Folder", player)
leaderstats.Name = "leaderstats"
local points = Instance.new("IntValue", leaderstats)
points.Name = "Score"
points.Value = 0
end
-- Met à jour le score d'un joueur
function ScoreManager.addPoints(player, points)
local leaderstats = player:FindFirstChild("leaderstats")
if leaderstats then
local score = leaderstats:FindFirstChild("Score")
if score then
score.Value = score.Value + points
end
end
end
return ScoreManager
Appel dans scriptServeur pour rajouter des points :
-- Script dans ServerScriptService
local ScoreManager = require(game:GetService("ServerScriptService"):WaitForChild("ScoreManager"))
-- Initialiser le Leaderstats pour chaque joueur
game.Players.PlayerAdded:Connect(function(player)
ScoreManager.initPlayer(player)
end)
local part = workspace.Part -- La Part qui déclenche l'événement
-- Exemple : Ajouter 10 points à un joueur
part.Touched:Connect(function(otherPart)
-- Vérifie que otherPart fait partie d'un personnage
local humanoid = otherPart.Parent:FindFirstChild("Humanoid")
if humanoid then
-- Récupère le joueur associé au personnage
local player = game.Players:GetPlayerFromCharacter(otherPart.Parent)
if player then
ScoreManager.addPoints(player, 10)
part:Destroy() -- Supprime la Part après utilisation
end
end
end)
Une course parsemée de difficultés et de briques mortelles. Le joueur doit traverser des espaces en utilisant des pouvoirs à sa disposition (sauter plus haut, courir plus vite, rétrécir, devenir transparent pour passer à travers les murs. Au contact d’un part mortel, son personnage meurt instantanément (Humanoid.Health = 0). Des zones sûres (parts verts) permettent de souffler avant d’atteindre une zone verte de victoire.
Règles du jeu
Rejoignez l’arène verte de victoire à l’autre bout du parcours en utilisant les pouvoirs à votre disposition. Chaque mort vous remet au départ. Pas de limite de tentatives.
1. Quel événement Roblox détecte le contact avec une part ?
OnTouch
Touched
Hit
Collide
2. Pour tuer un personnage, on modifie quelle propriété du Humanoid ?
MaxHealth
WalkSpeed
Health
Jump
3. Où place-t-on un Script qui affecte le serveur ?
StarterGui
ReplicatedStorage
ServerScriptService
LocalScript
4. Comment récupérer le Humanoid d’un personnage touché ?
hit.Humanoid
hit.Parent:FindFirstChild(‘Humanoid’)
game.Players.Humanoid
workspace.Humanoid
5. Quelle propriété rend une Part non-solide mais visible ?
Transparency = 0
CanCollide = false
Anchored = true
Locked = true
Défi 02 : Speed Runner
Touches clavier & compétences joueur
Description
Un parcours d’obstacles où le joueur peut débloquer une compétence en appuyant sur une touche du clavier. Appuyez sur [F] pour activer un boost d’un saut et vitesse rapide temporaire. Le boost a un cooldown visible et une barre d’énergie.
Des checkpoints invisibles qui font respawn le joueur au bon endroit si le joueur tombe ou meurt. Un compteur de tours : combien de fois le joueur a terminé le parcours. Un meilleur temps (record) qui s’affiche et se met à jour automatiquement
Règles du jeu
Parcourez le parcours le plus vite possible. Utilisez votre touche de compétence au bon moment. Franchissez la ligne d’arrivée. Votre temps est affiché.
Quel service Roblox gère les entrées clavier côté client ?
InputServiceUser
InputService
KeyboardService
ContextService
2. Dans quel type de script utilise-t-on UserInputService ?
ScriptModule
ScriptLocal
ScriptServer
Script
3. Comment détecter l’appui sur la touche E ?
Enum.KeyCode.E
Key.E
Input.E
Keyboard.E
4. Quelle propriété du Humanoid contrôle la vitesse de marche ?
Speed
RunSpeed
WalkSpeed
MoveSpeed
5. tick() retourne quoi en Lua Roblox ?
Le tick d’horloge en ms
Le temps en secondes depuis le lancement
Le framerate actuel
Le temps depuis le début de la partie
Défi 03 : Le Magasin de Pouvoirs
GUI & ScreenGui
Description
Un magasin en jeu affiché via un ScreenGui. Le joueur ouvre l’interface avec [G] et voit une liste de pouvoirs à acheter (vitesse, saut, bouclier). Chaque pouvoir a un prix en pièces d’or ramassées dans le monde. L’achat est confirmé par un bouton.
Règles du jeu
Collectez des pièces d’or dans la carte. Appuyez sur [G] pour ouvrir la boutique. Achetez des pouvoirs avec vos pièces. Activez vos pouvoirs via les touches attribuées.
Compétences acquises
ScreenGui & Frame
TextButton.MouseButton1Click
RemoteEvent (achat)
leaderstats basiques
Visible toggle
QCM — Testez vos connaissances
Où place-t-on un ScreenGui pour qu’il s’affiche à tous les joueurs ?
Workspace
StarterGui
ReplicatedStorage
ServerStorage
2. Quel événement déclenche un clic sur un TextButton ?
MouseButton1Click
Clicked
OnClick
Activated
3. Comment rendre une Frame invisible via Script ?
Frame.Hide()
Frame.Enabled = false
Frame.Visible = false
Frame.Alpha = 0
4. Un RemoteEvent sert à quoi ?
Communiquer entre LocalScript et Script serveur
Créer des GUI
Détecter les touches
Gérer les collisions
5. Pour déclencher un RemoteEvent depuis le client vers le serveur, on utilise ?
RemoteEvent:FireServer()
RemoteEvent:FireClient()
RemoteEvent:Send()
RemoteEvent:Trigger()
Défi 04 : La Porte Télékinésique
RemoteEvents & communication Client/Sserveur
Description
Des portes et pièges contrôlés en réseau. Quand un joueur marche sur un bouton (Part), un RemoteEvent notifie le serveur qui ouvre la porte correspondante pour TOUS les joueurs. Des pièges s’activent de même en temps réel.
Règles du jeu
Explorez la carte coopérativement. Trouvez les boutons cachés qui ouvrent des portes. Un joueur peut sacrifier sa position pour ouvrir le chemin à ses coéquipiers. Atteignez la sortie ensemble.
Compétences acquises
RemoteEvent:FireServer
RemoteEvent:FireClient
RemoteEvent.OnServerEvent
ReplicatedStorage
synchronisation multi-joueurs
QCM — Testez vos connaissances
1. Où stocke-t-on les RemoteEvents accessibles client ET serveur ?
ServerStorage
ServerScript
ServiceReplicated
StorageStarterGui
2. OnServerEvent est connecté dans quel type de script ?
LocalScript
Script (serveur)
ModuleScript
PluginScript
3. FireClient() envoie un event à ?
Tous les joueurs
Un joueur spécifique
Le serveur
Le workspace
4. FireAllClients() envoie à ?
Un joueur
Le serveur uniquement
Tous les clients connectés
Les NPC seulement
5. Quel est le premier paramètre reçu par OnServerEvent ?
Les données envoyées
Le joueur (Player) émetteur
Le nom du Remote
Eventnil
Défi 05 : Les Plateformes Mobiles
Mouvement de Parts via Script
Description
Des plateformes qui se déplacent selon des trajectoires (haut/bas, gauche/droite, circulaire). Certaines accélèrent, d’autres s’arrêtent selon des conditions (joueur dessus, timer). Utilisez RunService ou des boucles pour animer les positions.
Règles du jeu
Sautez de plateforme en plateforme pour atteindre la tour centrale. Les plateformes bougent en continu. Certaines disparaissent après 3 secondes de contact. Atteignez le sommet.
Compétences acquises
CFrame et Vector3
RunService.Heartbeat
while true do / wait()
math.sin() pour oscillation
Anchored vs non-Anchored
1. Quelle propriété utilise-t-on pour déplacer une Part sans physique ?
Position seule
CFrame
Velocity
MoveDirection
2. RunService.Heartbeat s’exécute à quelle fréquence ?
1 fois/seconde
Chaque frame (~60fps)
10 fois/seconde
À la demande
3. math.sin() est utile pour créer quel type de mouvement ?
Téléportation
Mouvement linéaire
Oscillation fluide
Rotation fixe
4. Une part Anchored peut-elle être déplacée par CFrame ?
Non, elle est immobile
Oui, le script peut changer son CFrame
Seulement par les joueurs
Seulement via TweenService
5. Vector3.new(0, 5, 0) représente quoi ?
Un déplacement de 5 studs vers le bas
Un déplacement de 5 studs vers le haut
Une rotation de 5 degré
sUne mise à l’échelle de 5
Défi 06 : L’Atelier des Effets
ParticleEmitter & effets visuels
Description
Un laboratoire où le joueur active différents effets visuels : feu, fumée, étincelles, traînées de lumière. Des zones déclenchent des effets via Touched. Le joueur peut ramasser un ‘orbe de feu’ qui attache un effet de flamme à son personnage.
Règles du jeu
Explorez le laboratoire et touchez les zones d’activation. Ramassez des orbes pour équiper des effets sur votre personnage. Certains effets boostent vos stats en plus d’être visuels.
Compétences acquises
ParticleEmitter
Fire & Smoke objects
Attachment points
Enabled toggle
PointLight & SpotLight
1. Où attache-t-on un ParticleEmitter dans un modèle 3D ?
Directement dans Workspace
Dans un Attachment ou une Part
Dans StarterGui
Dans ServerStorage
2. Comment activer/désactiver un ParticleEmitter ?
ParticleEmitter.Start()
ParticleEmitter.Enabled = true/false
ParticleEmitter.Visible = true/false
ParticleEmitter.Rate = 0
3. L’objet Fire de Roblox simule quoi ?
Un effet de lumière uniquement
Des flammes visuelles directement sur une Part
Un dégât de brûlure
Une explosion
4. Un PointLight émet la lumière dans quelle direction ?
Devant la Part
Dans toutes les directions
Vers le haut uniquement
Vers le bas uniquement
5. La propriété Rate d’un ParticleEmitter contrôle quoi ?
La taille des particules
La couleur
Le nombre de particules émises par seconde
La durée de vie du ParticleEmitter
Défi 07 : L’Ascenseur Magique
TweenService & animations fluides
Description
Des ascenseurs, portes coulissantes et objets animés avec TweenService. Les transitions sont fluides grâce aux EasingStyle. Un boss oscille sur place avec un Tween en boucle. Des récompenses s’animent quand ramassées (scale up/down).
Règles du jeu
Utilisez les ascenseurs pour monter les étages. Chaque étage déverrouille une porte animée. Ramassez les cristaux (avec animation) pour gagner des points. Atteignez le dernier étage.
Compétences acquises
TweenService:Create()
TweenInfoEasing
Style & Easing
DirectionTween:Play() / Pause() / Cancel()
Tween.Completed event
1. Quel service Roblox gère les transitions animées ?
AnimationService
TweenService
RunService
PhysicsService
2. TweenInfo.new() prend quoi comme premier paramètre ?
EasingStyle
La durée en secondes
L’objet à animer
Le nombre de répétitions
3. EasingStyle.Bounce donne quel effet ?
Mouvement linéaire
Rebond à la fin de l’animation
Accélération progressive
Pause au milieu
4. Comment déclencher quelque chose APRÈS la fin d’un Tween ?
Tween.OnComplete()
Tween.Completed:Wait()
wait(tween.duration)
TweenService.OnDone()
5. Peut-on tweener la couleur (Color3) d’une Part ?
Non, seulement la position
Oui, Color3 est une propriété tweénable
Seulement via ParticleEmitter
Seulement avec des scripts serveur
Défi 08 : Le Marchand & Le Détective
ProximityPrompt & ClickDetector
Description
Des PNJ (statues) équipés de ProximityPrompts affichent un menu de dialogue et de commerce quand on s’approche. Des objets dans le décor ont des ClickDetectors qui révèlent des indices. Un coffre s’ouvre au clic après avoir collecté tous les indices.
Règles du jeu
Approchez-vous des PNJ pour interagir. Cliquez sur les éléments suspects pour trouver les 5 indices. Apportez les indices au bon PNJ pour ouvrir le coffre au trésor.
Compétences acquises
ProximityPrompt.TriggeredClick
Detector.MouseClick
distance d’interaction
GUI contextuel
état de jeu (indices trouvés)
1. ProximityPrompt.Triggered est écouté depuis quel script ?
Uniquement LocalScript
Script serveur uniquement
Les deux sont possibles
ModuleScript seulement
2. Quelle propriété définit la distance d’activation d’un ProximityPrompt ?
RangeMax
ActivationDistance
TriggerRadius
ActivationDistance
3. ClickDetector.MouseClick passe quoi comme argument ?
La Part cliquée
Le Player qui a cliqué
Les coordonnées du clic
Nil
4. Comment afficher un texte personnalisé sur un ProximityPrompt ?
ProximityPrompt.Label
ProximityPrompt.Action
TextProximityPrompt.Text
ProximityPrompt.Title
5. Quelle est la différence principale entre ClickDetector et ProximityPrompt ?
Aucune différence
ClickDetector nécessite un clic, ProximityPrompt une touche en s’approchant
ProximityPrompt est plus ancien
ClickDetector fonctionne sans script
Défi 09 : Le Grand Tournoi
Leaderstats & tableau de score
Description
Un jeu de compétition avec un classement en temps réel (leaderstats). Points gagnés en touchant des zones, en éliminant des adversaires (PvP désactivable) ou en terminant des épreuves. Le score se met à jour pour tous via le tableau Roblox natif.
Règles du jeu
Accumulez des points en 5 minutes. Éliminez des adversaires (+10pts), touchez des zones (+5pts), finissez des épreuves bonus (+25pts). Le joueur avec le plus de points gagne.
Compétences acquises
leaderstats dans PlayerAdded
IntValue & StringValue
PlayerRemoving cleanup
tri et classement
DataStoreService (sauvegarde basique)
1. Comment créer les leaderstats d’un joueur ?
Directement dans Workspace
Folder nommé ‘leaderstats’ dans le Player
Dans ReplicatedStorage
Via un RemoteEvent
2. Quel événement se déclenche quand un joueur rejoint la partie ?
Players.PlayerJoined
Players.PlayerAdded
Players.New
PlayerPlayers.OnJoin
3. Quelle valeur utilise-t-on pour stocker un nombre entier dans leaderstats ?
NumberValue
IntValue
FloatValu
eStringValue
4. DataStoreService sert à quoi ?
Afficher le leaderboard
Persister des données entre les sessions
Communiquer entre scripts
Gérer les équipes
5. PlayerRemoving est utile pour ?
Accueillir le joueur
Sauvegarder les données avant que le joueur parte
Réinitialiser la map
Ajouter des points
Défi 10 : ROBLOX ADVENTURE COMPLETE
Jeu complet — tous les concepts
Description
Un jeu d’aventure complet qui intègre les 9 compétences précédentes : une carte avec zones mortelles (P1), des compétences débloquables (P2), une boutique GUI (P3), des events réseau (P4), des plateformes mobiles (P5), des effets visuels (P6), des animations TweenService (P7), des PNJ interactifs (P8) et un leaderboard complet (P9). Plusieurs niveaux, un boss final avec patterns d’attaque.
Règles du jeu
Traversez 3 zones distinctes (Forêt des Pièges, Tour des Pouvoirs, Donjon du Boss). Collectez des cristaux, achetez des améliorations, interagissez avec les PNJ, esquivez les obstacles animés. Battez le boss final et terminez premier au classement. Progression sauvegardée.
Compétences acquises
Architecture modulaire (ModuleScript)
Toutes les compétences P1-P9
Gestion d’état global
Équipes & rounds
Optimisation & bonnes pratiques
1. Un ModuleScript retourne quoi en général ?
Nil
Un tableau ou une fonction
Un RemoteEvent
Une GUI
2. Pour partager du code entre plusieurs scripts, on utilise ?
Copy-paste du code
ModuleScript + require()
RemoteEvent
Un Script dans Workspace
3. Quelle pratique évite les memory leaks avec les events ?
Utiliser task.wait()
Déconnecter les connexions avec :Disconnect()
Supprimer les RemoteEvents
Utiliser des LocalScripts uniquement
4. task.spawn() est préféré à coroutine.wrap() car ?
Il est plus lent
Il est intégré au scheduler Roblox et plus sûr
Il ne fonctionne qu’en serveur
Il bloque le thread principal
5. Dans une architecture propre, où stocke-t-on les ModuleScripts partagés ?
As-tu déjà rêvé de faire bondir les joueurs à plusieurs mètres de hauteur dans ton jeu Roblox ? Elles peuvent servir à franchir un obstacle, atteindre une plateforme cachée ou simplement ajouter une touche amusante à un niveau. Dans ce tutoriel, tu vas découvrir comment transformer un simple part en véritable trampoline interactif. Tu verras également comment régler la puissance du rebond pour obtenir différents effets de jeu.
Rebond du joueur sur la plaque
Crée un part et dessous un script :
Saisie ce code dans le script :
local TweenService = game:GetService("TweenService")
local BOUNCE_SPEED = 120 -- vitesse verticale imposée (studs/s)
local COOLDOWN = 0.3 -- évite les rebonds multiples par contact
local trampoline = script.Parent
local lastBounce = {} -- cooldown par joueur
local function squish(trampoline, bounceSpeed, squishTime)
if bounceSpeed==nil then bounceSpeed = BOUNCE_SPEED end
-- Remplace directement la vélocité verticale
local vel = trampoline.AssemblyLinearVelocity
trampoline.AssemblyLinearVelocity = Vector3.new(vel.X, bounceSpeed, vel.Z)
end
-- Appliquer des propriétés physiques pour que la part soit glissante
trampoline.CustomPhysicalProperties = PhysicalProperties.new(
0.7, -- Density
1, -- Friction
1, -- Elasticity
1, -- FrictionWeight
1 -- ElasticityWeight
)
-- Appliquer un matériau glissant comme de la glace
trampoline.Material = Enum.Material.Carpet
trampoline.Touched:Connect(function(hit)
local character = hit.Parent
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
if not humanoid or humanoid.Health <= 0 then return end
local rootPart = character:FindFirstChild("HumanoidRootPart")
if not rootPart then return end
-- Cooldown par personnage
local now = tick()
if lastBounce[character] and (now - lastBounce[character]) < COOLDOWN then return end
lastBounce[character] = now
squish(trampoline)
end)
Ce script transforme une simple pièce Roblox en trampoline capable de faire rebondir les joueurs lorsqu’ils la touchent. Les variables BOUNCE_SPEEDet COOLDOWNdéfinissent respectivement la puissance du rebond et le temps d’attente avant qu’un même joueur puisse rebondir à nouveau. Les propriétés physiques et le matériau de la pièce sont modifiés pour lui donner l’apparence et le comportement d’une surface adaptée au rebond.
La fonction squish() applique une nouvelle vitesse verticale à la pièce afin de créer l’effet de propulsion vers le haut.
L’événement Touched détecte lorsqu’un objet entre en contact avec le trampoline et vérifie qu’il s’agit bien d’un personnage vivant possédant un Humanoid. Un système de cooldown mémorise l’instant du dernier rebond de chaque joueur afin d’éviter plusieurs déclenchements successifs lorsque le personnage reste en contact avec le trampoline.
Animation de la plaque comme un trampoline
Par rapport à la version précédente, le script suivant ajoute un effet visuel d’écrasement et de retour à la forme initiale, ce qui donne davantage l’impression qu’il s’agit d’un véritable trampoline.
Une nouvelle variable originalSizemémorise la taille initiale de la plaque afin de pouvoir la restaurer après l’animation. La constante SQUISH_TIME définit la durée de l’animation de compression et de retour à la normale. La table isSquishingempêche que plusieurs animations soient lancées en même temps sur la même plaque, ce qui éviterait des déformations incohérentes. Le service TweenServiceest utilisé pour créer une animation fluide plutôt qu’un changement instantané de taille.
Lorsqu’un joueur rebondit, la plaque s’aplatit : sa hauteur diminue tandis que sa largeur et sa longueur augmentent légèrement. Cela reproduit visuellement le comportement d’un trampoline qui se comprime sous le poids du joueur. Après un court délai, une seconde animation redonne progressivement à la plaque sa taille d’origine, donnant l’impression qu’elle reprend sa forme après avoir propulsé le joueur.
L’effet visuel est synchronisé avec le rebond du joueur, ce qui rend l’interaction plus réaliste et plus agréable à observer.
local TweenService = game:GetService("TweenService")
local BOUNCE_SPEED = 120 -- vitesse verticale imposée (studs/s)
local COOLDOWN = 0.3 -- évite les rebonds multiples par contact
local SQUISH_TIME = 0.08 -- durée de l'étirement en secondes
local trampoline = script.Parent
local lastBounce = {} -- cooldown par joueur
local isSquishing = {} -- marquage de la part en état d'étirement
local function squish(trampoline, bounceSpeed, squishTime)
if bounceSpeed==nil then bounceSpeed = BOUNCE_SPEED end
if squishTime==nil then squishTime = SQUISH_TIME end
local originalSize = trampoline.Size
-- Remplace directement la vélocité verticale
local vel = trampoline.AssemblyLinearVelocity
trampoline.AssemblyLinearVelocity = Vector3.new(vel.X, bounceSpeed, vel.Z)
if isSquishing[trampoline] then return end
isSquishing[trampoline] = true
local tweenInfo = TweenInfo.new(squishTime, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
TweenService:Create(trampoline, tweenInfo, {
Size = Vector3.new(originalSize.X * 1.05, originalSize.Y * 0.4, originalSize.Z * 1.05)
}):Play()
task.delay(SQUISH_TIME, function()
TweenService:Create(trampoline, tweenInfo, { Size = originalSize }):Play()
task.delay(SQUISH_TIME, function() isSquishing[trampoline] = false end)
end)
end
-- Appliquer des propriétés physiques pour que la part soit glissante
trampoline.CustomPhysicalProperties = PhysicalProperties.new(
0.7, -- Density
1, -- Friction
1, -- Elasticity
1, -- FrictionWeight
1 -- ElasticityWeight
)
-- Appliquer un matériau glissant comme de la glace
trampoline.Material = Enum.Material.Carpet
trampoline.Touched:Connect(function(hit)
local character = hit.Parent
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
if not humanoid or humanoid.Health <= 0 then return end
local rootPart = character:FindFirstChild("HumanoidRootPart")
if not rootPart then return end
-- Cooldown par personnage
local now = tick()
if lastBounce[character] and (now - lastBounce[character]) < COOLDOWN then return end
lastBounce[character] = now
squish(trampoline)
end)
Système de plaques rebondissantes
Modifie la structure en créant un Folder, sous le folder ton script et la part, puis duplique la plaque rebondissante plusieurs fois :
Modifie ton script pour lire tous les parts rebondissants :
local TweenService = game:GetService("TweenService")
local BOUNCE_SPEED = 120 -- vitesse verticale imposée (studs/s)
local COOLDOWN = 0.3 -- évite les rebonds multiples par contact
local SQUISH_TIME = 0.08 -- durée de l'étirement en secondes
local trampolines = script.Parent
local lastBounce = {} -- cooldown par joueur
local isSquishing = {} -- marquage de la part en état d'étirement
local function squish(trampoline, bounceSpeed, squishTime)
if bounceSpeed==nil then bounceSpeed = BOUNCE_SPEED end
if squishTime==nil then squishTime = SQUISH_TIME end
local originalSize = trampoline.Size
-- Remplace directement la vélocité verticale
local vel = trampoline.AssemblyLinearVelocity
trampoline.AssemblyLinearVelocity = Vector3.new(vel.X, bounceSpeed, vel.Z)
if isSquishing[trampoline] then return end
isSquishing[trampoline] = true
local tweenInfo = TweenInfo.new(squishTime, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
TweenService:Create(trampoline, tweenInfo, {
Size = Vector3.new(originalSize.X * 1.05, originalSize.Y * 0.4, originalSize.Z * 1.05)
}):Play()
task.delay(SQUISH_TIME, function()
TweenService:Create(trampoline, tweenInfo, { Size = originalSize }):Play()
task.delay(SQUISH_TIME, function() isSquishing[trampoline] = false end)
end)
end
for _, trampoline in ipairs(trampolines:GetChildren()) do
if not trampoline:IsA("BasePart") then continue end
-- Appliquer des propriétés physiques pour que la part soit glissante
trampoline.CustomPhysicalProperties = PhysicalProperties.new(
0.7, -- Density
1, -- Friction
1, -- Elasticity
1, -- FrictionWeight
1 -- ElasticityWeight
)
-- Appliquer un matériau glissant comme de la glace
trampoline.Material = Enum.Material.Carpet
trampoline.Touched:Connect(function(hit)
local character = hit.Parent
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
if not humanoid or humanoid.Health <= 0 then return end
local rootPart = character:FindFirstChild("HumanoidRootPart")
if not rootPart then return end
-- Cooldown par personnage
local now = tick()
if lastBounce[character] and (now - lastBounce[character]) < COOLDOWN then return end
lastBounce[character] = now
squish(trampoline)
end)
end
Dans beaucoup de jeux Roblox, il existe des zones spéciales qui changent complètement la manière de jouer. Imagine un sol où ton personnage se met à glisser tout seul, comme sur de la glace, sans pouvoir s’arrêter immédiatement. Ou encore une pente qui accélère ton déplacement, te propulsant vers une nouvelle plateforme. Ces effets simples transforment un niveau classique en un vrai parcours d’obstacles amusant et dynamique. Dans ce tutoriel, tu vas apprendre à créer ce type de mécanismes toi-même avec Lua dans Roblox Studio. Tu vas découvrir comment contrôler le comportement d’un joueur lorsqu’il touche une zone spéciale. Tu vas progresser étape par étape pour comprendre comment la physique du jeu peut être modifiée. À la fin, tu seras capable de concevoir tes propres zones de glisse comme dans les vrais jeux d’obby.
Ce tutoriel est organisé en trois parties :
La première te montrera comment créer une plaque glissante simple pour faire “patiner” un joueur.
La deuxième expliquera comment gérer une plaque en pente pour influencer la direction du déplacement.
Enfin, la troisième partie te permettra de combiner plusieurs plaques glissantes pour créer un parcours complet et dynamique.
Plaque glissante
Crée un part puis dessous un script :
Ce script transforme une Part en surface glissante grâce à des propriétés physiques qui réduisent les frottements et lui donnent l’apparence de la glace. Lorsqu’un joueur touche cette Part, le script vérifie qu’il s’agit bien d’un personnage et récupère son HumanoidRootPart, qui représente le centre de son déplacement. Il calcule ensuite la direction dans laquelle regarde le joueur à l’aide du LookVector. La Part reçoit alors une vitesse SPEED qui la fait glisser dans la direction choisie pendant une durée définie SLIDER_LENGTH. Enfin, après ce délai, la vitesse est remise à zéro pour arrêter la glissade.
-- Script pour une part qui glisse sur un joueur lorsqu'il la touche
local part = script.Parent
-- Appliquer des propriétés physiques pour que la part soit glissante
part.CustomPhysicalProperties = PhysicalProperties.new(
0.7, -- Density
0, -- Friction
0, -- Elasticity
0, -- FrictionWeight
1 -- ElasticityWeight
)
-- Appliquer un matériau glissant comme de la glace
part.Material = Enum.Material.Ice
-- Vitesse de déplacement de la glissade
local SPEED = 15
local SLIDER_LENGTH = 1
-- Fonction appelée lorsque la part est touchée
part.Touched:Connect(function(hit)
-- Vérifier si l'objet touché est un personnage
local character = hit:FindFirstAncestorOfClass("Model")
if not character then return end
-- Récupérer le joueur et sa racine
local rootPart = character:FindFirstChild("HumanoidRootPart")
if not rootPart then return end
-- Récupérer la direction de la caméra du joueur
local dir = rootPart.CFrame.LookVector
-- Appliquer une impulsion sur la part pour faire glisser le joueur dans la direction de la caméra
part.AssemblyLinearVelocity = dir * SPEED
-- Arrêter la glissade après un délai
task.spawn(function()
task.wait(SLIDER_LENGTH)
part.AssemblyLinearVelocity = Vector3.zero
end)
end)
Pente glissante
Modifie le code pour permettre à la plaque glissante de tenir compte de son inclinaison.
Une nouvelle fonction, getSurfaceInclination, calcule la direction naturelle de la pente à partir de la gravité et de la normale de la surface. La gravité indique toujours le bas, tandis que la normale renseigne sur l’orientation de la plaque. En combinant ces deux informations, le script détermine la direction dans laquelle un objet glisserait naturellement sur la pente.
Lorsque le joueur touche la plaque, le script calcule cette direction de glissade et vérifie si elle est suffisamment importante. Si la plaque est inclinée, la vitesse est appliquée dans le sens de la pente afin de simuler une descente naturelle. Si la plaque est horizontale, il n’y a pas de direction de pente significative : le joueur glisse alors dans la direction vers laquelle il regarde. Grâce à cet ajout, le même script peut gérer aussi bien une plaque plate qu’une plaque inclinée, ce qui rend le comportement plus réaliste et permet de créer des parcours plus variés.
-- Script pour une part qui glisse sur un joueur lorsqu'il la touche
local part = script.Parent
-- Appliquer des propriétés physiques pour que la part soit glissante
part.CustomPhysicalProperties = PhysicalProperties.new(
0.7, -- Density
0, -- Friction
0, -- Elasticity
0, -- FrictionWeight
1 -- ElasticityWeight
)
-- Appliquer un matériau glissant comme de la glace
part.Material = Enum.Material.Ice
-- Vitesse de déplacement de la glissade
local SPEED = 15
local SLIDER_LENGTH = 1
local function getSurfaceInclination(hit)
-- Récupérer la direction de la gravité
local gravity = Vector3.new(0, -1, 0)
-- Récupérer la normale de la surface de la part
-- la normale est un vecteur unitaire perpendiculaire à la surface
-- qui indique “dans quel sens la surface est orientée"
local normal = part.CFrame.UpVector
-- enlève la composante perpendiculaire à la surface
local slopeDirection = gravity - normal * gravity:Dot(normal)
return slopeDirection.Unit
end
-- Fonction appelée lorsque la part est touchée
part.Touched:Connect(function(hit)
-- Vérifier si l'objet touché est un personnage
local character = hit:FindFirstAncestorOfClass("Model")
if not character then return end
-- Récupérer le joueur et sa racine
local rootPart = character:FindFirstChild("HumanoidRootPart")
if not rootPart then return end
-- Récupérer la direction de la caméra du joueur
local dir = rootPart.CFrame.LookVector
-- Récuoération du sens de la pente de la part par rapport à la gravité
local slopeDirection = getSurfaceInclination(part)
-- Glissade en fonction si pente de la part ou part horizontale
if slopeDirection.Magnitude > 0.1 then
-- Appliquer une impulsion sur la part pour faire glisser le joueur dans la direction de la pente
part.AssemblyLinearVelocity = slopeDirection * SPEED
else
-- Appliquer une impulsion sur la part pour faire glisser le joueur dans la direction de la caméra
part.AssemblyLinearVelocity = dir * SPEED
-- Arrêter la glissade après un délai
task.spawn(function()
task.wait(SLIDER_LENGTH)
part.AssemblyLinearVelocity = Vector3.zero
end)
end
end)
Systèmes de plaques et pentes glissantes
Dans cette nouvelle version, le script ne gère plus une seule plaque glissante mais un ensemble de plaques regroupées dans un dossier (Folder). Au démarrage, le script récupère tous les objets contenus dans ce dossier puis les parcourt un par un grâce à une boucle.
local folder = script.Parent
local parts = folder:GetChildren()for _, part in pairs(parts) do
end
Une vérification est effectuée pour s’assurer que chaque objet est bien une BasePart afin d’éviter les erreurs avec d’autres types d’objets.
if not part:IsA("BasePart") then continue end
Pour chaque plaque trouvée, les propriétés physiques et le matériau de glace sont appliqués automatiquement. Cela évite de dupliquer le même script sur chaque plaque du parcours. La fonction de calcul de la pente est ensuite associée à chaque plaque afin que son inclinaison soit prise en compte individuellement. Enfin, un événement Touched est créé pour chacune d’elles : lorsqu’un joueur touche une plaque, le script utilise les caractéristiques propres à cette plaque (orientation, pente, vitesse de glisse) pour déterminer son déplacement.
Grâce à cette modification, il devient très simple de créer un parcours complet composé de nombreuses surfaces glissantes. Il suffit d’ajouter ou de supprimer des plaques dans le dossier pour que le script les prenne automatiquement en charge, sans aucune modification supplémentaire du code.
-- Script pour une part qui glisse sur un joueur lorsqu'il la touche
local folder = script.Parent
local parts = folder:GetChildren()for _, part in pairs(parts) doif not part:IsA("BasePart") then continue end
-- Appliquer des propriétés physiques pour que la part soit glissante
part.CustomPhysicalProperties = PhysicalProperties.new(
0.7, -- Density
0, -- Friction
0, -- Elasticity
0, -- FrictionWeight
1 -- ElasticityWeight
)
-- Appliquer un matériau glissant comme de la glace
part.Material = Enum.Material.Ice
-- Vitesse de déplacement de la glissade
local SPEED = 15
local SLIDER_LENGTH = 3
local function getSurfaceInclination(hit)
-- Récupérer la direction de la gravité
local gravity = Vector3.new(0, -1, 0)
-- Récupérer la normale de la surface de la part
-- la normale est un vecteur unitaire perpendiculaire à la surface
-- qui indique “dans quel sens la surface est orientée"
local normal = part.CFrame.UpVector
-- enlève la composante perpendiculaire à la surface
local slopeDirection = gravity - normal * gravity:Dot(normal)
return slopeDirection.Unit
end
-- Fonction appelée lorsque la part est touchée
part.Touched:Connect(function(hit)
-- Vérifier si l'objet touché est un personnage
local character = hit:FindFirstAncestorOfClass("Model")
if not character then return end
-- Récupérer le joueur et sa racine
local rootPart = character:FindFirstChild("HumanoidRootPart")
if not rootPart then return end
-- Récupérer la direction de la caméra du joueur
local dir = rootPart.CFrame.LookVector
-- Récuoération du sens de la pente de la part par rapport à la gravité
local slopeDirection = getSurfaceInclination(part)
-- Glissade en fonction si pente de la part ou part horizontale
if slopeDirection.Magnitude > 0.1 then
-- Appliquer une impulsion sur la part pour faire glisser le joueur dans la direction de la pente
part.AssemblyLinearVelocity = slopeDirection * SPEED
else
-- Appliquer une impulsion sur la part pour faire glisser le joueur dans la direction de la caméra
part.AssemblyLinearVelocity = dir * SPEED
-- Arrêter la glissade après un délai
task.spawn(function()
task.wait(SLIDER_LENGTH)
part.AssemblyLinearVelocity = Vector3.zero
end)
end
end)
end
Dans ce tutoriel, tu vas créer une plaque spéciale qui modifie la gravité lorsque le joueur marche dessus.
Grâce à cette plaque, les personnages pourront :
sauter beaucoup plus haut ;
retomber plus lentement ;
atteindre des plateformes normalement inaccessibles.
Ce type de mécanisme est souvent utilisé dans les jeux de science-fiction, les parcours d’obstacles (Obby) ou les bases spatiales.
Comprendre la gravité
La gravité est la force qui attire les objets vers le sol.
Sur Terre, lorsque tu sautes :
tu montes ;
tu ralentis ;
tu redescends.
Dans Roblox, la gravité agit exactement de la même manière.
Si on la diminue :
les sauts deviennent plus grands ;
les chutes sont plus lentes ;
les déplacements semblent plus légers.
Solution 1 : Modifier la gravité pour tout le monde
Dans cette version, lorsqu’un joueur active la plaque, la gravité du jeu entier est modifiée.
Conséquences
tous les joueurs sont affectés ;
tous les sauts deviennent plus grands ;
tous les objets physiques réagissent également à la nouvelle gravité.
Cette solution est simple à mettre en place mais peut rendre le jeu imprévisible si plusieurs joueurs jouent en même temps.
Exemple de situation
Imaginons :
Paul marche sur la plaque ;
la gravité est divisée par deux.
Même les autres joueurs situés à l’autre bout de la carte profiteront immédiatement de cet effet.
Créer une plaque de non gravité
Commence par construire une Part qui servira de plaque spéciale.
Tu peux lui donner :
une couleur vive ;
un matériau futuriste ;
un effet lumineux.
Les joueurs comprendront ainsi qu’il s’agit d’une zone particulière du parcours.
Détecter l’entrée du joueur
Lorsque le personnage marche sur la plaque, le jeu doit détecter le contact.
Cette détection permet de savoir :
quel joueur est entré dans la zone ;
quand appliquer l’effet de faible gravité.
C’est le même principe que pour une zone de téléportation ou un checkpoint.
Puis un script :
-- référence au part pour le changement de gravité
local part = script.Parent
-- détection du joueur qui touche la part
part.Touched:Connect(function(hit)
local character = hit.Parent
local humanoid = character and character:FindFirstChild("Humanoid")
if not humanoid then return end
-- changement de gravité à 10 au moment de la collision
workspace.Gravity = 10
end)
Créer une plaque pour retrouver la gravité
Commence par construire une Part qui servira de plaque spéciale .
Puis un script :
-- référence de la part pour retourner la gravité à 196.2
local part = script.Parent
-- détection du joueur qui touche la part
part.Touched:Connect(function(hit)
local character = hit.Parent
local humanoid = character and character:FindFirstChild("Humanoid")
if not humanoid then return end
-- retour de la gravité à 196.2 au moment de la collision
workspace.Gravity = 196.2
end)
Solution 2 : Modifier la gravité pour un seul joueur
Dans cette version, seul le joueur qui touche la plaque bénéficie de l’effet.
Les autres joueurs continuent à jouer normalement.
Cette méthode est souvent préférable dans un jeu multijoueur car chacun peut vivre sa propre expérience.
Comment simuler une faible gravité pour un joueur ?
Comme la gravité du monde est partagée par tous, on ne peut pas simplement changer la gravité globale pour un seul joueur.
On utilise donc une autre technique :
augmenter sa puissance de saut ;
ralentir sa descente ;
modifier certaines propriétés de déplacement.
Le résultat ressemble à une gravité plus faible sans affecter les autres joueurs.
Script à modifier pour la plaque de changement de gravité pour un seul joueur :
-- référence au part pour le changement de gravité
local part = script.Parent
-- détection du joueur qui touche la part
part.Touched:Connect(function(hit)
local character = hit.Parent
local hrp = character and character:WaitForChild("HumanoidRootPart")
if not hrp then return end
if hrp:FindFirstChild("GravityAttachment") then return end -- évite les doublons
-- 1. Créer une pièce jointe (Attachment) requise pour VectorForce
local attachment = Instance.new("Attachment")
attachment.Name = "GravityAttachment"
attachment.Parent = hrp
-- 2. Créer la force physique (VectorForce)
local vectorForce = Instance.new("VectorForce")
vectorForce.Name = "CustomGravityForce"
vectorForce.Attachment0 = attachment
vectorForce.ApplyAtCenterOfMass = true
vectorForce.RelativeTo = Enum.ActuatorRelativeTo.World
-- 3. Calculer la masse totale du personnage
local totalMass = 0
for _, part in ipairs(character:GetDescendants()) do
if part:IsA("BasePart") then
totalMass = totalMass + part:GetMass()
end
end
-- 4. Appliquer une force vers le haut pour réduire la gravité ressentie
-- Exemple : contrer 60% de la gravité (le joueur se sentira plus léger)
local gravityCounterFactor = 0.6
local upwardForce = totalMass * workspace.Gravity * gravityCounterFactor
vectorForce.Force = Vector3.new(0, upwardForce, 0)
vectorForce.Parent = hrp
end)
Script à modifier pour retrouver la gravité normal pour un seul joueur :
-- référence de la part pour retourner la gravité à 196.2
local part = script.Parent
-- détection du joueur qui touche la part
part.Touched:Connect(function(hit)
local character = hit.Parent
local hrp = character and character:FindFirstChild("HumanoidRootPart")
if not hrp then return end
-- Trouver et supprimer l'Attachment
local attachment = hrp:FindFirstChild("GravityAttachment")
if attachment then
attachment:Destroy()
end
-- Trouver et supprimer le VectorForce
local vectorForce = hrp:FindFirstChild("CustomGravityForce")
if vectorForce then
vectorForce:Destroy()
end
end)