Module 05 · Leçon 6 sur 6
Animer objets et interfaces avec TweenService
Fais bouger les plateformes de l’Obby des Nuages et anime ta boutique avec TweenService, TweenInfo et les styles d’easing, en choisissant bien entre serveur et client.
- ⏱️ 35 min
- 📝 Quiz de 6 questions
- 🔄 Vérifié le 24 octobre 2026
🎯 Dans cette leçon, tu vas apprendre à…
- Créer et lancer un tween avec TweenService:Create et TweenInfo.new
- Choisir la durée, le style et la direction d’easing, les répétitions et l’aller-retour
- Animer des plateformes mobiles en connaissant leur effet sur le personnage
- Animer une interface côté client et enchaîner des tweens avec Completed
Un obby où tout est immobile, c’est un peu triste. Dans cette leçon, tu fais bouger l’Obby des Nuages : des plateformes qui montent et descendent, une boutique qui glisse à l’écran, un compteur de pièces qui « rebondit » à chaque gain. L’outil pour ça : TweenService, qui anime en douceur presque n’importe quelle propriété.
Qu’est-ce qu’un tween ?
« Tween » vient de in-between (« entre-deux »). Tu donnes une valeur de départ (la valeur actuelle), une valeur d’arrivée, une durée, et Roblox calcule toutes les valeurs intermédiaires, image par image. Pas besoin de boucle avec task.wait : l’animation est fluide et bien plus simple à écrire.
On peut tweener des propriétés de nombreux types : nombres, Vector3, CFrame, Color3, UDim2, Vector2… Exemples : la Position ou la CFrame d’une Part, sa Transparency, sa Color, ou la Size d’un Frame.
Les trois étapes d’un tween
- Décrire le mouvement avec
TweenInfo.new(...): durée, style, répétitions… - Créer le tween avec
TweenService:Create(objet, infos, objectif), oùobjectifest une table « nom de propriété → valeur d’arrivée ». - Le lancer avec
tween:Play().
-- Script placé dans une Part (côté serveur) : la Part devient rouge et transparente
local TweenService = game:GetService("TweenService")
local part = script.Parent
local infos = TweenInfo.new(2) -- 2 secondes, les autres réglages par défaut
local objectif = {
Color = Color3.fromRGB(255, 60, 60),
Transparency = 0.5,
}
local tween = TweenService:Create(part, infos, objectif)
tween:Play()
Un même tween peut animer plusieurs propriétés à la fois, comme ici la couleur et la transparence.
TweenInfo en détail
Voici la signature exacte, d’après la référence API (au moment de la rédaction) :
-- Les 6 paramètres, dans l'ordre, avec leur valeur par défaut
local infos = TweenInfo.new(
1, -- 1. time : durée en secondes (défaut : 1)
Enum.EasingStyle.Quad, -- 2. easingStyle : la « forme » du mouvement (défaut : Quad)
Enum.EasingDirection.Out, -- 3. easingDirection : où s'applique l'easing (défaut : Out)
0, -- 4. repeatCount : répétitions supplémentaires, -1 = à l'infini (défaut : 0)
false, -- 5. reverses : revenir au départ après chaque aller (défaut : false)
0 -- 6. delayTime : délai avant de commencer, en secondes (défaut : 0)
)
Les paramètres sont positionnels : c’est leur place qui compte, pas leur nom. Pour régler le 5e (aller-retour), tu dois donc aussi écrire les 4 premiers. Les propriétés d’un TweenInfo ne peuvent plus être modifiées après sa création : crée-en un nouveau si besoin.
Les styles d’easing
L’easing décrit comment la vitesse évolue pendant le mouvement. Quelques styles de Enum.EasingStyle :
| Style | Effet |
|---|---|
Linear |
vitesse constante, mécanique |
Sine, Quad, Cubic |
accélération ou freinage doux, de plus en plus marqué |
Back |
dépasse un peu la cible puis revient : effet « rebond » léger |
Bounce |
rebondit comme une balle à l’arrivée |
Elastic |
oscille comme un ressort |
Et la direction (Enum.EasingDirection) :
In: l’effet s’applique au début (départ lent, arrivée rapide) ;Out: l’effet s’applique à la fin (départ rapide, arrivée en douceur) ;InOut: au début et à la fin.
Contrôler un tween
tween:Play()lance (ou relance) le tween ;tween:Pause()le met en pause ;tween:Cancel()l’arrête ;- l’événement
tween.Completedse déclenche quand le tween se termine ou est annulé. Il reçoit unEnum.PlaybackStatequi indique pourquoi (CompletedouCancelled, par exemple).Pausene le déclenche pas.
Attention : si deux tweens modifient la même propriété du même objet, le premier est annulé et remplacé par le plus récent.
Les plateformes mobiles de l’Obby des Nuages
Crée un Folder PlateformesMobiles dans Workspace et ranges-y les Parts qui doivent bouger. Pour régler chaque plateforme sans toucher au code, on utilise des attributs. Pour en ajouter un, sélectionne la Part, descends jusqu’à la section Attributes de la fenêtre Properties et clique sur + : donne un nom, choisis le type, valide avec Save, puis règle la valeur comme une propriété normale. Deux attributs, tous deux facultatifs :
Deplacement(Vector3) : de combien la plateforme se déplace, en studs. Par exemple0, 8, 0pour monter de 8 studs ;Duree(number) : la durée d’un aller, en secondes.
Sans attribut, le script utilise des valeurs par défaut (8 studs vers le haut, 3 secondes). Crée ensuite un Script PlateformesMobiles dans ServerScriptService :
-- Script « PlateformesMobiles » dans ServerScriptService (côté serveur)
local TweenService = game:GetService("TweenService")
local Workspace = game:GetService("Workspace")
local dossier = Workspace:WaitForChild("PlateformesMobiles")
local function animerPlateforme(plateforme: Instance)
if not plateforme:IsA("BasePart") then
return
end
-- Un tween déplace la Part sans la physique : elle doit être ancrée
plateforme.Anchored = true
-- Réglages lus dans les attributs, avec des valeurs par défaut
local deplacement = plateforme:GetAttribute("Deplacement")
if typeof(deplacement) ~= "Vector3" then
deplacement = Vector3.new(0, 8, 0)
end
local duree = plateforme:GetAttribute("Duree")
if typeof(duree) ~= "number" then
duree = 3
end
local infos = TweenInfo.new(
duree, -- durée d'un aller
Enum.EasingStyle.Sine, -- départ et arrivée en douceur
Enum.EasingDirection.InOut,
-1, -- répétition à l'infini
true, -- aller-retour
0 -- pas de délai
)
-- On ajoute le déplacement à la CFrame actuelle (position + rotation)
local objectif = { CFrame = plateforme.CFrame + deplacement }
TweenService:Create(plateforme, infos, objectif):Play()
end
for _, plateforme in dossier:GetChildren() do
animerPlateforme(plateforme)
end
On tweene la CFrame plutôt que la Position : la CFrame contient la position et la rotation, et l’ajout d’un Vector3 la déplace sans changer son orientation.
Et le personnage, dans tout ça ?
C’est un piège classique des obbys. Un tween change directement la position d’une Part ancrée, sans passer par le moteur physique. La documentation officielle ne décrit pas ce cas ; voici ce que rapportent des développeurs sur le DevForum (par exemple le fil cité dans les sources), à vérifier toi-même en test :
- une plateforme qui monte pousse en général le personnage vers le haut, car il reste posé dessus : c’est le cas le plus simple ;
- une plateforme qui se déplace horizontalement glisse sous les pieds du personnage, qui ne suit pas et finit par tomber.
Pour l’Obby des Nuages, utilise les tweens pour les plateformes verticales (ascenseurs), les obstacles à éviter (un mur qui coulisse, une barre qui tourne) et les effets visuels. Pour une plateforme horizontale qui doit transporter le joueur, il faut une solution physique : par exemple une Part non ancrée guidée par une PrismaticConstraint motorisée (mode Servo), que la documentation cite justement pour les plateformes d’ascenseur. C’est plus avancé : teste soigneusement avant de l’utiliser.
Serveur ou client ?
- Plateformes et obstacles : dans un Script serveur. Les changements de position sont répliqués à tous les joueurs, et tout le monde voit la même chose au même endroit. C’est le plus simple et le plus juste pour un obby.
- Interfaces : dans un LocalScript. L’interface n’existe que sur le client (dans le PlayerGui), le serveur n’a rien à voir.
Animer l’interface de la boutique
Améliorons l’interface de la leçon 4. Crée un LocalScript AnimationsInterface dans StarterGui › InterfaceObby, puis supprime le bloc « 2. OUVRIR / FERMER LA BOUTIQUE » de ScriptInterface : sinon, les deux scripts se disputeraient la fenêtre. Supprime aussi, en haut de ScriptInterface, la ligne local boutonBoutique = …, qui ne sert plus (Studio signalerait une variable inutilisée).
-- LocalScript « AnimationsInterface » dans StarterGui > InterfaceObby (côté client)
-- Remplace le bloc « 2. OUVRIR / FERMER LA BOUTIQUE » de ScriptInterface (leçon 4)
local Players = game:GetService("Players")
local TweenService = game:GetService("TweenService")
local joueur = Players.LocalPlayer
local interface = script.Parent
local boutonBoutique = interface:WaitForChild("BoutonBoutique") :: TextButton
local fenetreBoutique = interface:WaitForChild("Boutique") :: Frame
local compteur = interface:WaitForChild("CompteurPieces") :: Frame
-- 1. LA FENÊTRE QUI GLISSE
local POSITION_OUVERTE = UDim2.fromScale(0.5, 0.5) -- centre de l'écran
local POSITION_CACHEE = UDim2.fromScale(0.5, 1.5) -- sous le bas de l'écran
local infosOuverture = TweenInfo.new(0.35, Enum.EasingStyle.Back, Enum.EasingDirection.Out)
local infosFermeture = TweenInfo.new(0.25, Enum.EasingStyle.Quad, Enum.EasingDirection.In)
local ouverte = false
fenetreBoutique.Position = POSITION_CACHEE
fenetreBoutique.Visible = false
boutonBoutique.Activated:Connect(function()
ouverte = not ouverte
if ouverte then
fenetreBoutique.Visible = true
TweenService:Create(fenetreBoutique, infosOuverture, { Position = POSITION_OUVERTE }):Play()
else
local fermeture = TweenService:Create(fenetreBoutique, infosFermeture, { Position = POSITION_CACHEE })
-- On ne masque la fenêtre qu'une fois la fermeture terminée
fermeture.Completed:Connect(function(etat)
-- Si le joueur a rouvert entre-temps, la fermeture a été annulée
if etat == Enum.PlaybackState.Completed and not ouverte then
fenetreBoutique.Visible = false
end
end)
fermeture:Play()
end
end)
-- 2. LE COMPTEUR QUI REBONDIT à chaque changement de pièces
local echelle = Instance.new("UIScale") -- agrandit le cadre ET tout son contenu
echelle.Parent = compteur
local pieces = joueur:WaitForChild("leaderstats"):WaitForChild("Pieces") :: IntValue
local infosRebond = TweenInfo.new(0.25, Enum.EasingStyle.Back, Enum.EasingDirection.Out)
pieces.Changed:Connect(function()
echelle.Scale = 1.25 -- grossit d'un coup…
TweenService:Create(echelle, infosRebond, { Scale = 1 }):Play() -- …et revient en rebondissant
end)
Remarque l’usage de Completed : la fenêtre ne devient invisible qu’après sa sortie de l’écran. Et si le joueur clique à nouveau pendant la fermeture, le tween d’ouverture remplace celui de fermeture (même propriété Position) : la fermeture est annulée (Cancelled) et la fenêtre reste visible. Pratique !
Ce qu’il faut retenir
- Un tween anime une propriété d’une valeur à une autre :
TweenService:Create(objet, infos, objectif)puis:Play(). TweenInfo.new(durée, style, direction, répétitions, allerRetour, délai): l’ordre compte ;-1répète à l’infini.- Le style (
Sine,Back,Bounce…) et la direction (In,Out,InOut) donnent son caractère au mouvement. - D’après des retours de développeurs, une plateforme ancrée tweenée n’emporte pas le personnage horizontalement : réserve les tweens aux ascenseurs, obstacles et effets.
- Objets du monde : tween côté serveur ; interface : tween côté client, avec
Completedpour enchaîner les actions.
Sources et pour aller plus loin
- TweenService — référence API
- TweenInfo — référence API (signature de TweenInfo.new)
- TweenBase (Play, Cancel, Completed) — référence API
- UI animation/tweens — documentation Roblox
- PrismaticConstraint — documentation Roblox
- Properties window — créer un attribut dans Studio (Roblox)
- Platform moves while character doesn’t — fil d’entraide du DevForum (retour de développeurs, 2021)