Module joystick Gravity DFRobot basé sur 2 potentiomètres (axes X et Y) et d’un bouton-poussoir pour des applications spécifiques. Il délivre deux sorties analogiques en fonction de la position des deux potentiomètres et une sortie logique en fonction du bouton-poussoir.
Il se raccorde sur deux entrées analogiques et une entrée logique directement sur le Board pour UNIHIKER K10, M10 et micro:bit. Cette carte d’extension modulable est conçue pour du prototypage et des projets robotiques. Elle combine un pilote de moteur, une alimentation avec support pour accu Li-Ion 18650 et de nombreuses E/S Gravity.
Alimentation :
Support pour batterie 18650 (3,7 Vcc) avec circuit de charge intégré et indicateur de niveau à LEDs.
Entrée USB Type-C (5 Vcc) : pour alimentation externe et recharge.
LEDs : état de charge, niveau de batterie, alimentation et sens des moteurs.
Moteurs et servomoteurs :
Driver pour 4 moteurs CC (1,5 A maxi par moteur) à connecter sur borniers à vis.
6 sorties servomoteurs sur connecteurs 3 contacts
Interfaces :
8 broches GPIO via le connecteur Edge des cartes micro:bit ou Unihiker.
6 broches GPIO supplémentaires : digitale et analogique.
Bus I2C : trois interfaces à 3,3 V et une interface I2C en 5 V.
Interface pour capteurs à ultrasons 5 V (Trigger et Echo).
Autres : 2 x LEDs RGB programmables (WS2812) et émetteur/récepteur infrarouge
installation du logiciel de la carte d’extension dans MIND+
Cliquer sur l’icone.
Installe les trois câbles du joystick sur les 3 premières broches GPIO supplémentaires C0, C1, C2 : digitale et analogique.
C0 déplacement en X (0 à 4095, autour de 2000 en repos)
C1 déplacement en Y (0 à 4095, autour de 2000 en repos)
C2 appui sur le Joystick (1 repos, 0 appuié)
Exemple de programme pour récupérer les évènements du Joystick :
Apprendre à afficher une bulle de chat au-dessus de la tête du joueur quand il touche une Part, avec un cooldown pour éviter le spam. Ce tutoriel explique :
Le service Chat et la fonction Chat:Chat().
Le tableau de cooldown (avec une nouveauté : ici la clé est le personnage, pas le joueur !).
La détection de collision avec Touched.
Au passage : corriger les noms de variables pour qu’ils soient en anglais (bonne pratique de programmeur !).
Introduction : À quoi sert ce script ?
Dans beaucoup de jeux, on veut féliciter le joueur quand il atteint une zone :
« Bien joué ! » quand il touche la ligne d’arrivée.
« Bravo ! » quand il trouve un secret.
Dans ce script, quand un joueur touche la Part (la ligne d’arrivée par exemple), une bulle verte s’affiche au-dessus de sa tête avec le message « bien jouer ».
Mais il y a un piège ! L’événement Touched se déclenche des dizaines de fois par seconde tant que le joueur touche la Part (une fois par partie du corps qui la touche : pied, jambe, bras…). Sans protection, on verrait des dizaines de bulles de chat en même temps ! C’est pour cela qu’on utilise un cooldown de 10 secondes.
Préparation dans Roblox Studio
Créer la Part :
Dans Workspace, ajoute une Part (ex: une ligne d’arrivée plate et large).
Positionne-la au sol dans ton niveau.
Ajouter le script DANS la Part (important !) :
Clic droit sur la Part → Insert Object → Script.
Le script devient enfant de la Part (c’est ce que script.Parent utilise).
Coller le code corrigé ci-dessus dans ce script.
Tester :
Lance le jeu et marche sur la Part :
Une bulle verte « Bien joué ! » apparaît au-dessus de ta tête.
Reste sur la Part ou re-touche-la : rien ne se passe pendant 10 secondes (le cooldown !).
Après 10 secondes, retouche-la : la bulle réapparaît !
Script commenté :
-- Récupérer la Part parente du script (la Part qui déclenche le message)
local wellDonePart = script.Parent
-- Récupérer le service Chat pour afficher des bulles de dialogue
local chatService = game:GetService("Chat")
-- Tableau de cooldown : [character] = true si le personnage est en cooldown
local cooldowns = {}
-- Détecter quand quelque chose touche la Part
wellDonePart.Touched:Connect(function(hit)
-- Récupérer le personnage (Model) qui touche la Part
local character = hit.Parent
if not character then return end
-- VÉRIFIER LE COOLDOWN : si ce personnage a déjà déclenché le message, on arrête
if cooldowns[character] then return end
-- Trouver la tête du personnage (là où la bulle de chat apparaît)
local head = character:FindFirstChild("Head")
if not head then return end
-- Afficher une bulle de chat verte au-dessus de la tête avec le message
chatService:Chat(head, "Bien joué !", Enum.ChatColor.Green)
-- ACTIVER LE COOLDOWN pour ce personnage pendant 10 secondes
cooldowns[character] = true
task.wait(10) -- Attendre 10 secondes
cooldowns[character] = false -- Réautoriser le message
end)
Explications Détaillées
1. script.Parent : le script est DANS la Part !
local wellDonePart = script.Parent
Grande nouveauté par rapport aux tutoriels précédents : ici, le script est placé directement dans la Part (dans l’arborescence : Part > Script), pas dans ServerScriptService.
script.Parent = l’objet parent du script, c’est-à-dire la Part elle-même !
Avantage : le script fonctionne n’importe où où tu copies la Part. Tu peux dupliquer la Part, le script fonctionne tout seul dans chaque copie !
2. Le service Chat et la fonction Chat:Chat()
local chatService = game:GetService("Chat")
chatService:Chat(head, "Bien joué !", Enum.ChatColor.Green)
game:GetService("Chat") : service Roblox qui gère les bulles de dialogue.
chatService:Chat(...) : affiche une bulle de message au-dessus d’une partie du corps. Elle prend 3 paramètres :
Paramètre
Valeur ici
Rôle
1. La partie
head
Là où la bulle apparaît (au-dessus de la tête du personnage).
2. Le message
"Bien joué !"
Le texte affiché dans la bulle.
3. La couleur
Enum.ChatColor.Green
La bulle est verte (il existe aussi Blue, Red, White…).
Différence avec le chat normal : Chat:Chat() ne fait qu’afficher une bulle au-dessus du personnage (comme quand un joueur parle dans le jeu). Ce n’est pas un message envoyé dans la fenêtre de chat.
3. Le tableau de cooldown… avec le PERSONNAGE comme clé !
local cooldowns = {}
if cooldowns[character] then return end
cooldowns[character] = true
task.wait(10)
cooldowns[character] = false
Rappel des tutoriels précédents : un cooldown, c’est un temps d’attente pour éviter qu’une action se déclenche trop souvent.
La nouveauté ici : la clé du tableau n’est ni player, ni userId, mais character (le Model du personnage) !
Pourquoi character et pas player ?
On n’a pas besoin du joueur : on a déjà son personnage (hit.Parent), et c’est lui qu’on vérifie.
Ça économise une étape (pas besoin de Players:GetPlayerFromCharacter).
⚠️ Mais attention, il y a un piège avec ce choix ! Regarde la fin du cooldown :luaCopiercooldowns[character] = false -- Ici on met falseDans les tutoriels précédents, on mettait nil (on supprimait l’entrée). Ici on met false… mais la vérification if cooldowns[character] fonctionne quand même ! Pourquoi ? Parce que la condition vérifie simplement que la valeur n’est ni false ni nil. Les deux solutions marchent :
cooldowns[character] = nil → l’entrée n’existe plus (table plus propre).
cooldowns[character] = false → l’entrée existe mais vaut false (accepté par le if).
Autre piège subtil : quand le joueur meurt et respawn, son personnage est détruit et un nouveau Model est créé. L’ancienne entrée cooldowns[ancienCharacter] reste dans le tableau avec false… mais elle ne gêne pas (elle ne sera plus jamais utilisée). Dans un vrai jeu, on nettoierait avec Players.PlayerRemoving comme dans les tutoriels précédents !
4. La détection de collision avec Touched
wellDonePart.Touched:Connect(function(hit)
local character = hit.Parent
if not character then return end
hit : la partie du corps (ou objet) qui touche la Part.
hit.Parent : le Model du personnage (si un pied touche la Part, hit = le pied, hit.Parent = le personnage entier).
if not character then return end : si hit n’a pas de parent (impossible normalement), on arrête.
⚠️ Petit trou dans le filet : ce script vérifie seulement si hit.Parent existe. Une Part libre qui roule sur la ligne d’arrivée a aussi un Parent… mais elle n’a pas de Head, donc la vérification if not head then return end la rejette ! C’est la recherche de la Head qui filtre les vrais joueurs.
5. Pourquoi chercher la Head ?
local head = character:FindFirstChild("Head")
if not head then return end
La bulle de chat apparaît au-dessus de la partie qu’on donne en paramètre.
On donne la tête pour que la bulle apparaisse au-dessus de la tête du joueur (comme dans le tutoriel des messages cliquables !).
Si le personnage n’a pas de tête (ex: un objet qui touche la Part), on arrête : pas de tête, pas de bulle !
QCM : Teste ta compréhension !
Sur le service Chat :
Que fait chatService:Chat(head, "Bien joué !", Enum.ChatColor.Green) ?
a) Affiche une bulle verte « Bien joué ! » au-dessus de la tête du personnage.
b) Envoie un message dans la fenêtre de chat globale.
c) Change la couleur du personnage en vert.
À quoi sert le paramètre Enum.ChatColor.Green ?
a) À définir la couleur de la bulle de chat.
b) À définir la couleur de la Part.
c) À définir la vitesse du personnage.
Sur script.Parent :
Que vaut script.Parent si le script est placé DANS une Part ?
a) La Part qui contient le script.
b) Le Workspace.
c) Le joueur.
Quel est l’avantage de placer le script dans la Part avec script.Parent ?
a) On peut dupliquer la Part, et chaque copie fonctionne toute seule.
b) Le script va plus vite.
c) Le message est plus long.
Sur le cooldown :
Pourquoi un cooldown est-il indispensable ici ?
a) L’événement Touched se déclenche des dizaines de fois par seconde, on aurait des dizaines de bulles.
b) Pour économiser la batterie.
c) Pour changer la couleur du message.
Quelle est la clé du tableau cooldowns dans ce script ?
a) Le personnage (character).
b) Le pseudo du joueur.
c) Le nom de la Part.
Que se passe-t-il pendant les 10 secondes de cooldown si le joueur re-touche la Part ?
a) La fonction s’arrête immédiatement à if cooldowns[character] then return end, aucune bulle ne s’affiche.
b) La bulle s’affiche quand même.
c) Le jeu plante.
Ce script remet le cooldown avec cooldowns[character] = false. Quelle autre écriture était aussi possible (comme dans les tutoriels précédents) ?
a) cooldowns[character] = nil (supprimer l’entrée du tableau).
b) cooldowns[character] = "stop".
c) cooldowns = {} (vider tout le tableau, ce qui supprimerait les cooldowns des AUTRES joueurs !).
Sur la détection de collision :
Que vaut hit quand un joueur touche la Part avec son pied ?
a) Le pied (la Part du corps qui touche).
b) Le personnage entier.
c) Le joueur.
Pourquoi la vérification if not head then return end est-elle utile, en plus de chercher la tête ?
a) Elle filtre les objets qui ne sont pas des personnages (une Part qui roule sur la ligne d’arrivée n’a pas de Head).
b) Elle accélère le script.
c) Elle change la couleur de la bulle.
Idées pour aller plus loin
1. Personnaliser le message avec un attribut (rappel du tutoriel des messages cliquables !)
Objectif : Chaque copie de la Part affiche son propre message, sans modifier le script.
Comment faire ?
Ajoute un attribut Message (type String) sur la Part, puis :luaCopierlocal message = wellDonePart:GetAttribute("Message") or "Bien joué !" chatService:Chat(head, message, Enum.ChatColor.Green)
Objectif : La Part donne des points à chaque passage.
Comment faire ?luaCopierlocal Players = game:GetService("Players") local player = Players:GetPlayerFromCharacter(character) if player then local leaderstats = player:FindFirstChild("leaderstats") if leaderstats then leaderstats.Score.Value += 1 end end
3. Ajouter un effet visuel et sonore (rappel du tutoriel des particules !)
Comment faire ?luaCopierlocal emitter = wellDonePart:FindFirstChildOfClass("ParticleEmitter") local sound = wellDonePart:FindFirstChildOfClass("Sound") if emitter then emitter.Enabled = true end if sound then sound:Play() end task.delay(2, function() if emitter then emitter.Enabled = false end end)
4. Nettoyer le tableau quand le joueur quitte (bonne pratique !)
Objectif : Éviter que le tableau cooldowns garde des entrées inutiles.
Comment faire ? Comme dans le tutoriel flip/flop, utilise un cooldown basé sur le joueur (player.UserId comme clé, comme le tutoriel des checkpoints) + un nettoyage :luaCopierlocal Players = game:GetService("Players") local player = Players:GetPlayerFromCharacter(character) if not player then return end if cooldowns[player.UserId] then return end cooldowns[player.UserId] = true task.delay(10, function() cooldowns[player.UserId] = nil end) Players.PlayerRemoving:Connect(function(leavingPlayer) cooldowns[leavingPlayer.UserId] = nil end)
Bonus : avec task.delay au lieu de task.wait, la fonction Touched ne reste pas bloquée 10 secondes et peut traiter d’autres joueurs !
Résumé des concepts clés
Concept
Description
Exemple
script.Parent
L’objet qui contient le script (ici, la Part).
local wellDonePart = script.Parent
game:GetService("Chat")
Service pour afficher des bulles de dialogue.
chatService:Chat(head, message, color)
Chat:Chat()
Affiche une bulle au-dessus d’une partie, avec un message et une couleur.
Enum.ChatColor.Green
Touched
Événement déclenché à chaque contact avec la Part (très fréquent !).
wellDonePart.Touched:Connect(...)
hit.Parent
Le personnage (Model) qui touche la Part.
local character = hit.Parent
FindFirstChild("Head")
Cherche la tête (et filtre les non-personnages).
if not head then return end
Tableau de cooldown
[character] = true pendant 10 secondes pour bloquer le spam.
if cooldowns[character] then return end
task.wait(10)
Attend 10 secondes avant de réautoriser le message.
…et Roblox fait tout le travail, frame par frame, à ta place !
Comparaison avec le tutoriel précédent :
Technique
Tutoriel précédent (Heartbeat)
Ce tutoriel (TweenService)
Qui déplace la Part ?
Ton code, à chaque frame.
Roblox, automatiquement.
Lignes de code
Beaucoup (calculs, direction, elapsed…).
Très peu !
Vitesse fluide / accélération
À coder soi-même.
Intégrée (EasingStyle) !
Transport du joueur
Oui (avec AssemblyLinearVelocity).
Oui (Roblox gère la vélocité du Tween).
SCRIPT 1 : Animer un seul ascenseur
Préparation dans Roblox Studio
Dans Workspace, crée un dossier MovementsFolder.
Ajoute deux Part nommées Part et Part02 (plates et larges : Size = Vector3.new(20, 1, 20)).
Crée un Script dans ServerScriptService et colle le Script 1. Teste :
L’ascenseur 1 monte en 15 s, redescend, remonte… à l’infini, en douceur.
Monte dessus : tu es transporté (TweenService gère la physique pour toi !).
Remplace par le Script 2. Teste :
L’ascenseur 1 monte (10 s), l’ascenseur 2 recule de 200 studs sur l’axe X.
Les deux animations tournent en même temps, chacune dans son sens.
Voici le premier script :
-- Récupérer le dossier et les deux ascenseurs
local folder = workspace:WaitForChild("MovementsFolder")
local elevator01 = folder:WaitForChild("Part")
local elevator02 = folder:WaitForChild("Part02")
-- Récupérer le service d'animations TweenService
local tweenService = game:GetService("TweenService")
-- Décrire les règles de l'animation avec TweenInfo
local tweenInfo = TweenInfo.new(
15, -- Durée : 15 secondes pour monter
Enum.EasingStyle.Sine, -- Style : démarre doucement, accélère, ralentit (comme un vrai ascenseur !)
Enum.EasingDirection.InOut, -- Direction : fluide au début ET à la fin
-1, -- Répétition : -1 = INFINIE (jamais arrêtée)
true -- Reverser : à l'arrivée, l'animation REPART EN ARRIÈRE (descente !)
)
-- Créer le Tween : on anime elevator01 vers une position 100 studs plus haut
local tween = tweenService:Create(
elevator01, -- Objet à animer
tweenInfo, -- Les règles de l'animation
{ -- Propriétés à modifier (la destination) :
Position = Vector3.new( -- La nouvelle Position = position actuelle + 100 en Y
elevator01.Position.X, -- X : inchangé
elevator01.Position.Y + 100, -- Y : +100 studs (on monte !)
elevator01.Position.Z -- Z : inchangé
)
}
)
-- Lancer l'animation !
tween:Play()
Explications du Script 1
1. TweenInfo.new : les règles du jeu
TweenInfo.new accepte 5 paramètres (dans cet ordre, attention !) :
Paramètre
Valeur ici
Signification
1. Durée
15
Le trajet dure 15 secondes.
2. Style
Enum.EasingStyle.Sine
L’ascenseur démarre doucement et freine à l’arrivée (pas de secousse !).
3. Direction
Enum.EasingDirection.InOut
L’effet de style s’applique au début ET à la fin.
4. Répétitions
‘-1
‘-1 = répétition à l’infini. (0 = une fois, 2 = trois allers…)
5. Reverser
true
Après chaque montée, l’animation rejoue en sens inverse : c’est la descente automatique !
2. Les styles d’animation (EasingStyle) — à expérimenter !
Style
Effet
Linear
Vitesse constante, comme un tapis roulant.
Sine
Doux au départ et à l’arrivée — parfait pour un ascenseur.
Quad, Cubic
Accélération de plus en plus marquée.
Bounce
Rebondit à l’arrivée comme un ballon !
Elastic
Élastique, dépasse la cible puis revient.
Back
Part légèrement en arrière avant d’avancer.
3. La cible : une table de propriétés
{Position = Vector3.new(...)}
Le 3ème argument de Create est une table qui contient les propriétés à animer et leur valeur finale.
Ici, on anime seulement la Position, mais on peut animer Color, Transparency, Size… tout à la fois !
Astuce : la cible est calculée à partir de la position actuelle (elevator01.Position.Y + 100) : le script fonctionne où que soit placée la Part dans ton niveau !
4. La magie Reverser = true
Montée (15 s) → descente (15 s) → montée → descente… à l’infini, sans aucune boucle while ni variable direction !
Compare avec le tutoriel précédent : des dizaines de lignes remplacées par -1 et true !
5. N’oublie pas Anchored = true !
Dans le Script 1, la Part doit être ancrée dans Studio (case Anchored cochée), sinon elle tombe avant même que le Tween commence ! (Le Script 2 corrige cela dans le code.)
SCRIPT 2 : Gérer plusieurs ascenseurs différents
Problème du Script 1 : il n’anime que elevator01, et il faut copier-coller tout le code pour un 2ème ascenseur. Mauvaise pratique !
Solution (rappel des tutoriels précédents) : une fonction createElevator paramétrable + un tableau de fiches + une boucle pairs !
Voici le script commenté :
-- Récupérer le dossier et les deux ascenseurs
local folder = workspace:WaitForChild("MovementsFolder")
local elevator01 = folder:WaitForChild("Part")
local elevator02 = folder:WaitForChild("Part02")
-- Récupérer le service d'animations TweenService
local tweenService = game:GetService("TweenService")
-- Tableau des ascenseurs (une fiche de paramètres par ascenseur)
local elevators = {}
-- Fonction pour créer un ascenseur avec SES paramètres propres
-- Paramètres :
-- part : la Part à animer
-- movement : le déplacement à effectuer (Vector3)
-- duration : la durée de l'animation (secondes)
-- style : le style d'animation (EasingStyle)
-- direction : le sens de l'animation (EasingDirection)
-- repeatCount : le nombre de répétitions (-1 = infini)
-- reverser : retour à l'origine à la fin (true/false)
local function createElevator(part, movement, duration, style, direction, repeatCount, reverser)
part.Anchored = true -- Mouvement contrôlé, pas de gravité
part.CanCollide = true -- Le joueur peut monter dessus
elevators[part] = {
movement = movement or Vector3.new(0, 100, 0), -- Déplacement par défaut : +100 en Y
duration = duration or 10, -- Durée par défaut : 10 s
style = style or Enum.EasingStyle.Sine, -- Style par défaut : Sine
direction = direction or Enum.EasingDirection.InOut,-- Direction par défaut : InOut
repeatCount = repeatCount or -1, -- Répétition par défaut : infinie
reverser = reverser or true, -- Descente automatique par défaut
}
end
-- Ascenseur 1 : monte de 100 studs (tous les autres paramètres par défaut)
createElevator(elevator01, Vector3.new(0, 100, 0))
-- Ascenseur 2 : recule de 200 studs sur l'axe X (un pont mobile horizontal !)
createElevator(elevator02, Vector3.new(-200, 0, 0))
-- Parcourir le tableau et créer + lancer UN TWEEN PAR ASCENSEUR
for part, properties in pairs(elevators) do
-- Construire les règles de l'animation avec les paramètres de CET ascenseur
local tweenInfo = TweenInfo.new(
properties.duration,
properties.style,
properties.direction,
properties.repeatCount,
properties.reverser
)
-- Créer le Tween : cible = position actuelle + le déplacement demandé
local tween = tweenService:Create(
part,
tweenInfo,
{Position = part.Position + properties.movement}
)
-- Lancer l'animation
tween:Play()
end
Explications du Script 2
1. La fonction createElevator : une fiche par ascenseur
Même architecture que le tutoriel précédent (les tableaux de cooldowns, de checkpoints…) :
Clé = la Part.
Valeur = une fiche de paramètres (table).
Rappel : movement or Vector3.new(0, 100, 0) = si le paramètre n’est pas fourni, on prend la valeur par défaut.
2. Deux ascenseurs, deux comportements, UN code
createElevator(elevator01, Vector3.new(0, 100, 0)) -- Monte de 100 studs
createElevator(elevator02, Vector3.new(-200, 0, 0)) -- Recule de 200 studs
Ascenseur 1 : vertical (comme un vrai ascenseur).
Ascenseur 2 : horizontal (comme un pont mobile ou un tapis géant).
La cible est calculée dans la boucle : part.Position + properties.movement → fonctionne pour n’importe quelle Part, n’importe où !
3. La boucle pairs : créer et lancer tous les Tweens
for part, properties in pairs(elevators) do
local tweenInfo = TweenInfo.new(...)
local tween = tweenService:Create(part, tweenInfo, {Position = ...})
tween:Play()
end
On parcourt toutes les fiches, et pour chacune on construit sonTweenInfopersonnalisé.
Chaque Tween tourne indépendamment : l’ascenseur 1 mettra 10 s pour monter, l’ascenseur 2 aussi mais dans l’autre sens, chacun son rythme, sans se gêner !
Ajouter un 3ème ascenseur = 1 seule ligne :luaCopierlocal elevator03 = folder:WaitForChild("Part03") createElevator(elevator03, Vector3.new(0, 0, 150), 20, Enum.EasingStyle.Bounce) -- Va-et-vient avec rebonds !
QCM : Teste ta compréhension !
Sur TweenService et TweenInfo :
À quoi sert TweenService ?
a) À créer des animations automatiques de propriétés (position, couleur, transparence…).
b) À détecter les collisions.
c) À afficher des messages dans le chat.
Que signifie -1 en 4ème paramètre de TweenInfo.new ?
a) L’animation se répète à l’infini.
b) L’animation dure -1 seconde.
c) L’animation est supprimée.
Que fait le paramètre Reverser = true ?
a) Après l’aller, l’animation rejoue en sens inverse : descente automatique !
b) La Part tourne sur elle-même.
c) La Part devient invisible.
Quel EasingStyle donne un mouvement doux au départ et à l’arrivée, comme un vrai ascenseur ?
a) Enum.EasingStyle.Sine
b) Enum.EasingStyle.Bounce
c) Enum.EasingStyle.Linear
Quel EasingStyle fait rebondir la Part à l’arrivée ?
a) Enum.EasingStyle.Bounce
b) Enum.EasingStyle.Sine
c) Enum.EasingStyle.InOut
Sur la création du Tween :
Que contient le 3ème argument de tweenService:Create ?
a) Une table avec les propriétés à animer et leur valeur finale (la cible).
b) La durée de l’animation.
c) Le nom du joueur.
Pourquoi calcule-t-on la cible avec part.Position + properties.movement ?
a) Pour que le script fonctionne où que soit placée la Part dans le niveau.
b) Pour aller plus vite.
c) Pour changer la couleur de la Part.
Que faut-il penser à faire pour que la Part animée ne tombe pas à cause de la gravité ?
a) L’ancrer (part.Anchored = true, comme dans createElevator).
b) La peindre en rouge.
c) La rendre transparente.
Sur le Script 2 :
Quel est l’avantage de la fonction createElevator par rapport au Script 1 ?
a) On peut créer autant d’ascenseurs différents qu’on veut sans dupliquer le code (1 ligne par ascenseur).
b) Les animations vont plus vite.
c) Il n’y a aucun avantage.
Que fait movement = movement or Vector3.new(0, 100, 0) ?
a) Si aucun mouvement n’est fourni, on utilise le déplacement par défaut (+100 en Y).
b) On additionne les deux vecteurs.
c) On supprime le mouvement.
Dans le Script 2, comment s’appellent les deux paramètres corrigés par rapport à l’original ?
a) movement (au lieu de mouvment) et repeatCount (au lieu de nbrRepeat).
b) vitesse et duree.
c) up et down.
Comment ajouter un 3ème ascenseur qui avance sur l’axe Z en 20 secondes ?
a) createElevator(elevator03, Vector3.new(0, 0, 150), 20) — une seule ligne suffit !
b) Il faut recopier tout le script.
c) C’est impossible.
Comparaison : Heartbeat (tutoriel précédent) vs TweenService
Critère
Boucle Heartbeat
TweenService
Quantité de code
Beaucoup (direction, elapsed, conditions…).
Très peu.
Pause entre les trajets
✅ Facile (task.delay + direction = 0).
❌ Pas prévu par TweenInfo (à gérer soi-même avec tween.Completed).
Chaque ascenseur différent
✅ Fiches de paramètres.
✅ Fiches de paramètres aussi !
Styles d’animation (rebond, élastique…)
❌ À coder entièrement à la main.
✅ Intégrés (EasingStyle) !
Annuler / reprendre
Compliqué (déconnecter, recalculer).
✅ tween:Cancel(), tween:Pause() !
Conclusion
Puissant et flexible (pauses, conditions).
Permet le déplacement du joueur sur la part dans un déplacement sur X ou Z
Simple et rapide pour des allers-retours classiques.
La leçon du programmeur : avant de coder un mouvement à la main, demande-toi si Roblox n’a pas déjà un outil intégré ! Pour des animations simples, TweenService gagne. Pour des comportements complexes (pauses, étages, conditions), la boucle Heartbeat reste reine.
Idées pour aller plus loin
1. Animer d’autres propriétés que la Position
Objectif : Faire clignoter ou changer la couleur des ascenseurs.
Comment faire ?luaCopiertweenService:Create(part, TweenInfo.new(2, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, -1, true), {Color = Color3.fromRGB(255, 0, 0)}):Play()On peut animer plusieurs propriétés en même temps : {Position = ..., Color = ..., Transparency = 0.5} !
2. Ajouter une pause entre les trajets
Objectif : Combiner TweenService avec la pause du tutoriel précédent.
Comment faire ? Utiliser l’événement tween.Completed (attention : avec Reverser, il ne se déclenche qu’à la toute fin) :luaCopierlocal info = TweenInfo.new(10, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, 0, true) -- 0 répétition local tween = tweenService:Create(part, info, {Position = part.Position + properties.movement}) tween.Completed:Connect(function() task.wait(3) -- Pause de 3 secondes à l'arrivée tween:Play() -- Et on repart ! end) tween:Play()
3. Contrôler le Tween en direct
Objectif : Arrêter ou mettre en pause l’ascenseur (ex: bouton d’arrêt d’urgence !).
Comment faire ?tween:Pause() -- Met en pause (l'animation reprendra où elle s'est arrêtée) tween:Play() -- Reprend tween:Cancel() -- Annule et remet la Part à sa position d'origine
4. Un son d’ascenseur à chaque départ
Comment faire ?luaCopierlocal sound = part:FindFirstChildOfClass("Sound") if sound then sound:Play() endAssocie-le à un ClickDetector (rappel du tutoriel des messages) pour un bouton « Appeler l’ascenseur » !
Résumé des concepts clés
Concept
Description
Exemple
TweenService
Service qui anime automatiquement les propriétés.
game:GetService("TweenService")
TweenInfo.new
Les règles : durée, style, direction, répétitions, reverser.
avec déplacement fluide de la part avec RunService.Heartbeat
avec déplacement du joueur sur la part avec AssemblyLinearVelocity
En utilisant les concepts appris dans les deux tutoriels précédents, tu vas apprendre à déplacer de manière fluide les parts avec RunService.Heartbeat tout en proposer un déplacement du joueur sur la part sur les axes X et Z avec AssemblyLinearVelocity. On va garder la Partancrée pour un mouvement 100% contrôlé et précis, mais on informe le moteur physique de la vitesse réelle du déplacement
Tutoriel 2 : AssemblyLinearVelocity avec Anchored = false
On confie le déplacement au moteur physique.
Oui… mais la plateforme subit la gravité et pivote sous le poids du joueur
L’astuce de ce tutoriel : le meilleur des deux mondes !
On garde la Partancrée (Anchored = true) pour un mouvement 100% contrôlé et précis, mais on informe le moteur physique de la vitesse réelle du déplacement avec :
part.AssemblyLinearVelocity = speed * direction
Pourquoi ça marche ?
Roblox utilise la vélocité d’une surface pour savoir comment déplacer les personnages debout dessus.
En donnant la bonne vélocité (même à une Part ancrée), Roblox « sait » que le sol bouge, et entraîne le joueur avec lui !
C’est exactement la formule de la physique : vitesse = distance / temps.
Aspect
Tutoriel 1 (Position seule)
Tutoriel 2 (Vélocité + non ancré)
Ce tutoriel (hybride)
Précision du mouvement
✅ Parfaite
❌ La physique peut dévier
✅ Parfaite
Transport du joueur
❌ Non
✅ Oui
✅ Oui
Gravité / collisions parasites
✅ Aucune (ancrée)
❌ Oui (non ancrée)
✅ Aucune (ancrée)
Apprendre à créer une fonction paramétrable pour déplacer une Part de manière fluide en utilisant RunService.Heartbeat. Ce tutoriel explique :
Comment utiliser RunService.Heartbeat pour des mouvements fluides.
Comment créer une fonction paramétrable pour contrôler le déplacement.
Comment calculer la distance parcourue avec Magnitude.
Préparation dans Roblox Studio
Pour tester ce script, suis ces étapes :
Créer un dossier :
Dans Workspace, crée un dossier nommé MovementsFolder.
Ajouter une Part :
Ajoute une Part dans Folder.
Nomme-la Part (ou modifie le nom dans le script).
Configurer la Part :
Assure-toi que la Part a une taille visible (ex: Size = Vector3.new(4, 4, 4)).
Place-la à une position centrale (ex: Position = Vector3.new(0, 10, 0)).
Ajouter le script :
Crée un Script dans ServerScriptService et copie-y le code fourni.
Script pour faire monter :
local folder = workspace:WaitForChild("MovementsFolder")
local ascenseur = folder:WaitForChild("Part")
task.wait(3)
ascenseur.Position += Vector3.new(0, 10, 0)
Pourquoi utiliser RunService.Heartbeat ?
Dans Roblox, RunService.Heartbeat est un événement qui se déclenche à chaque frame (environ 60 fois par seconde). Cela permet de :
Créer des mouvements fluides (ex: une animation progressive).
Contrôler précisément le déplacement d’un objet.
Arrêter le mouvement quand une condition est remplie (ex: une distance parcourue).
Dans ce tutoriel, on va déplacer une Part sur l’axe Y jusqu’à ce qu’elle ait parcouru une distance donnée.
Faire montrer progressivement la part :
local RunService = game:GetService("RunService")
local folder = workspace:WaitForChild("MovementsFolder")
local ascenseur = folder:WaitForChild("Part")
ascenseur.Anchored = true
task.wait(5)
local connection
connection = RunService.Heartbeat:Connect(function(deltaTime)
ascenseur.Position += Vector3.new(0, +10,0)
end)
Faire monter la parte en contrôlant sa vitesse de montée :
speed : vitesse du déplacement en stud
direction : direction du déplacement 1 monter -1 descendre
local runService = game:GetService("RunService")
local folder = workspace:WaitForChild("MovementsFolder")
local ascenseur = folder:WaitForChild("Part")
ascenseur.Anchored = true
task.wait(5)
local speed = 10
local direction = 1 -- 1 monter -1 descendre
local connection
connection = runService.Heartbeat:Connect(function(deltatime)
ascenseur.Position += Vector3.new(0, (direction * speed * deltatime) , 0)
end)
Faire monter puis descendre la part en contrôlant la vitesse et la hauteur :
starty : point de départ sur l’axe Y
targety : point d’arrivée sur l’axe Y
local runService = game:GetService("RunService")
local folder = workspace:WaitForChild("MovementsFolder")
local ascenseur = folder:WaitForChild("Part")
ascenseur.Anchored = true
task.wait(5)
local speed = 10
local direction = 1 -- 1 monter -1 descendre
local startY = ascenseur.Position.Y
local targetY = startY + 50
local connection
connection = runService.Heartbeat:Connect(function(deltatime)
ascenseur.Position += Vector3.new(0, (direction * speed * deltatime) , 0)
if ascenseur.Position.Y >= targetY then
direction = -1
elseif ascenseur.Position.Y <= startY then
direction = 1
end
end)
Monter et descendre avec un arrêt :
pause_duration = temps de l’arrêt en seconde
local runService = game:GetService("RunService")
local folder = workspace:WaitForChild("MovementsFolder")
local ascenseur = folder:WaitForChild("Part")
ascenseur.Anchored = true
task.wait(5)
local speed = 10
local direction = 1 -- 1 monter -1 descendre
local startY = ascenseur.Position.Y
local targetY = startY + 50
local pause_duration = 5
local connection
connection = runService.Heartbeat:Connect(function(deltatime)
ascenseur.Position += Vector3.new(0, (direction * speed * deltatime) , 0)
if direction ~= 0 and ascenseur.Position.Y >= targetY then
direction = 0
task.delay(pause_duration, function()
direction = -1
end)
elseif direction ~= 0 and ascenseur.Position.Y <= startY then
direction = 0
task.delay(pause_duration, function()
direction = 1
end)
end
end)
Parcourir sur une certaine distance en transportant le joueur :
On garde la Partancrée (Anchored = true) pour un mouvement 100% contrôlé et précis, mais on informe le moteur physique de la vitesse réelle du déplacement avec :
Roblox utilise la vélocité d’une surface pour savoir comment déplacer les personnages debout dessus.
En donnant la bonne vélocité (même à une Part ancrée), Roblox « sait » que le sol bouge, et entraîne le joueur avec lui !
.Magnitude : distance totale parcourue depuis le départ (Pythagore 3D : √(x² + y² + z²)).
local runService = game:GetService("RunService")
local folder = workspace:WaitForChild("MovementsFolder")
local ascenseur = folder:WaitForChild("Part")
local speed = 20
local direction = 1 -- 1 monter -1 descendre
local start = ascenseur.Position
local distance = 200
local pause_duration = 5
ascenseur.Anchored = true
task.wait(5)
local connection
connection = runService.Heartbeat:Connect(function(deltatime)
ascenseur.Position += Vector3.new((direction * speed * deltatime),
0 ,
0)
if direction == 0 then
ascenseur.AssemblyLinearVelocity = Vector3.new(0, 0, 0)
else
ascenseur.AssemblyLinearVelocity = Vector3.new(speed * direction,
5,
0)
end
if direction ~= 0 and and (ascenseur.Position - start).Magnitude > distance then
direction = 0
task.delay(pause_duration, function()
direction = -1
end)
elseif direction ~= 0 and and (ascenseur.Position - start).Magnitude < 1 then
direction = 0
task.delay(pause_duration, function()
direction = 1
end)
end
end)
Parcourir sur une certaine distance dans toutes les directions :
local runService = game:GetService("RunService")
local folder = workspace:WaitForChild("MovementsFolder")
local ascenseur = folder:WaitForChild("Part")
local speed = Vector3.new(20, 20, 20)
local direction = 1 -- 1 monter -1 descendre
local start = ascenseur.Position
local distance = 200
local pause_duration = 5
ascenseur.Anchored = true
task.wait(5)
local connection
connection = runService.Heartbeat:Connect(function(deltatime)
ascenseur.Position += speed * direction * deltatime
if direction == 0 then
ascenseur.AssemblyLinearVelocity = Vector3.new(0, 0, 0)
else
ascenseur.AssemblyLinearVelocity = Vector3.new(speed.X * direction,
5 ,
speed.Z * direction)
end
if direction ~= 0 and and (ascenseur.Position - start).Magnitude > distance then
direction = 0
task.delay(pause_duration, function()
direction = -1
end)
elseif direction ~= 0 and and (ascenseur.Position - start).Magnitude < 1 then
direction = 0
task.delay(pause_duration, function()
direction = 1
end)
end
end)
Parcourir pendant un certain temps dans toutes les directions :
local runService = game:GetService("RunService")
local folder = workspace:WaitForChild("MovementsFolder")
local ascenseur = folder:WaitForChild("Part")
local speed = Vector3.new(20, 20, 20)
local direction = 1 -- 1 monter -1 descendre
local elapsed = 0
local duration = 10
local pause_duration = 5
ascenseur.Anchored = true
task.wait(5)
local connection
connection = runService.Heartbeat:Connect(function(deltatime)
ascenseur.Position += speed * direction * deltatime
if direction == 0 then
ascenseur.AssemblyLinearVelocity = Vector3.new(0, 0, 0)
else
ascenseur.AssemblyLinearVelocity = Vector3.new(speed.X*direction,
5 ,
speed.Z*direction)
end
elapsed += deltatime * direction
if direction ~= 0 and elapsed >= duration then
direction = 0
task.delay(pause_duration, function()
direction = -1
end)
elseif direction ~= 0 and elapsed <= 0 then
direction = 0
task.delay(pause_duration, function()
direction = 1
end)
end
end)
Créer des Ascenseurs Automatiques en Aller-Retour avec Pause.
Apprendre à créer plusieurs ascenseurs qui montent, marquent une pause, redescendent, repartent… en boucle infinie ! Ce tutoriel explique :
Comment stocker les paramètres de chaque ascenseur dans un tableau (une fiche d’identité par ascenseur !).
La boucle for ... in pairs() pour gérer plusieurs ascenseurs en même temps avec un seul Heartbeat.
La variable elapsed (temps écoulé) pour savoir où en est l’ascenseur.
La direction (1, 0, -1) pour piloter montée, pause et descente.
La protection contre la double connexion au Heartbeat.
Ce script réunit des briques vues dans les tutoriels précédents : Heartbeat, deltaTime, AssemblyLinearVelocity pour transporter les joueurs, et task.delay pour les pauses !
Comment fonctionne un ascenseur ?
Un vrai ascenseur fait un cycle :
Montée (direction = 1)
Pause à l’étage (direction = 0) — les portes s’ouvrent !
Descente (direction = -1)
Pause en bas (direction = 0)
Et on recommence !
Le défi du jour : gérer deux ascenseurs avec des vitesses différentes (l’un monte en diagonale, l’autre avance sur l’axe X), mais avec une seule boucle Heartbeat pour tout le monde — c’est plus efficace que de créer une boucle par ascenseur !
-- Récupérer le service RunService pour utiliser Heartbeat
local RunService = game:GetService("RunService")
-- Récupérer le dossier et les deux ascenseurs
local folder = workspace:WaitForChild("MovementsFolder")
local elevator01 = folder:WaitForChild("Part")
local elevator02 = folder:WaitForChild("Part02")
-- Variable pour stocker la connexion à Heartbeat (UNE SEULE pour tous les ascenseurs)
local connection
-- Fonction qui démarre la boucle de mouvement pour TOUS les ascenseurs
-- Paramètre : elevators = le tableau contenant tous les ascenseurs et leurs paramètres
local function startMovement(elevators)
-- PROTECTION : si une connexion existe déjà, on ne fait rien
-- (évite de connecter DEUX fois Heartbeat, ce qui doublerait la vitesse !)
if connection then return end connection = RunService.Heartbeat:Connect(function(deltaTime)
-- Parcourir le tableau des ascenseurs avec pairs()
-- Pour chaque ascenseur (part) et sa fiche de paramètres (properties) :
for part, properties in pairs(elevators) do
-- Ignorer si l'objet n'est pas une BasePart (sécurité)
if not part:IsA("BasePart") then continue end
if properties.direction ~= 0 then
-- Déplacer l'ascenseur : position += vitesse * direction * temps
-- direction = 1 (monte) : avance normalement
-- direction = -1 (descend) : avance à l'envers (vitesse négative)
-- direction = 0 (pause) : ne bouge plus (vitesse * 0 = 0)
part.Position += properties.speed * properties.direction * deltaTime
-- Donner la vélocité réelle pour TRANSPORTER LES JOUEURS
-- (technique du tutoriel précédent : vitesse = déplacement / temps)
if properties.direction == 0 then
part.AssemblyLinearVelocity = Vector3.new(0, 0, 0) -- Arrêt propre
else
part.AssemblyLinearVelocity = properties.speed * properties.direction
end
-- Mise à jour du temps écoulé :
-- si direction = 1 : elapsed augmente (montée)
-- si direction = -1 : elapsed DIMINUE (descente)
-- si direction = 0 : elapsed ne change plus (pause)
properties.elapsed += deltaTime * properties.direction
end
-- ARRIVÉE EN HAUT : elapsed atteint la durée du trajet
if properties.direction ~= 0 and properties.elapsed >= properties.duration then
properties.direction = 0 -- Stop : pause en haut !
task.delay(properties.pause_duration, function()
properties.direction = -1 -- Après la pause : descente
end)
-- ARRIVÉE EN BAS : elapsed revient à 0
elseif properties.direction ~= 0 and properties.elapsed <= 0 then
properties.direction = 0 -- Stop : pause en bas !
task.delay(properties.pause_duration, function()
properties.direction = 1 -- Après la pause : montée
end)
end
end
end)
end
-- Attendre 5 secondes avant de démarrer
task.wait(5)
-- Tableau qui contiendra tous les ascenseurs et leurs paramètres
local elevators = {}
-- Fonction pour créer un ascenseur et l'enregistrer dans le tableau
-- Chaque ascenseur reçoit SA fiche de paramètres (sa "fiche d'identité")
local function createElevator(part, speed, duration, pauseDuration)
part.Anchored = true -- Mouvement 100% contrôlé par le script
part.CanCollide = true -- Le joueur peut monter dessus
elevators[part] = {
connection = nil,
speed = speed or Vector3.new(20, 20, 20), -- Vitesse par défaut si non fournie
duration = duration or 10, -- Durée du trajet par défaut : 10 s
pause_duration = pauseDuration or 3, -- Durée de la pause par défaut : 3 s
direction = 1, -- Direction de départ : 1 = monte
elapsed = 0, -- Temps écoulé : on part du bas (0)
}
end
-- Créer les deux ascenseurs :
-- Ascenseur 1 : vitesse par défaut (diagonale 20,20,20), durée et pause par défaut
createElevator(elevator01)
-- Ascenseur 2 : avance sur l'axe X seulement (Vector3.new(20, 0, 0))
createElevator(elevator02, Vector3.new(20, 0, 0))
-- Démarrer le mouvement de tous les ascenseurs
startMovement(elevators)
Explications Détaillées
1. La fiche d’identité : un tableau DANS un tableau !
elevators est un tableau associatif dont la clé est la Part :luaCopierelevators = { [Part] = { speed = ..., direction = ..., ... }, [Part02] = { speed = ..., direction = ..., ... } }
Chaque ascenseur a sa propre fiche avec ses paramètres. C’est la même technique que les tableaux cooldowns des tutoriels précédents : une clé unique par objet, une valeur dédiée.
L’astuce valeur or défaut :luaCopierspeed = speed or Vector3.new(20, 20, 20),
Si on donne une vitesse → on l’utilise.
Si on n’en donne pas (comme createElevator(elevator01)) → speed vaut nil, et nil or Vector3.new(20, 20, 20) prend la valeur par défaut.
C’est comme un jeu vidéo : si tu ne choisis pas la difficulté, le mode Normal s’active tout seul !
2. La boucle for ... in pairs() : gérer tous les ascenseurs d’un coup
for part, properties in pairs(elevators) do
...
end
Jusqu’ici, tu connaissais ipairs pour les listes numérotées (1, 2, 3…).
pairs parcourt un tableau associatif : il donne successivement chaque clé (part) et chaque valeur (properties).
Avantage énorme : un seul Heartbeat met à jour tous les ascenseurs à chaque frame. Si tu ajoutes un 3ème, 4ème… 10ème ascenseur, aucune ligne de la boucle ne change !
3. La direction : le chef d’orchestre (1, 0, -1)
La variable properties.direction peut valoir trois états :
direction
Signification
Effet sur le mouvement
Effet sur elapsed
1
Montée
Avance à pleine vitesse
Augmente
0
Pause
Immobile (vitesse × 0 = 0)
Ne bouge plus
‘-1
Descente
Avance « à l’envers »
Diminue
La magie des signes : speed * direction * deltaTime :
Pendant la montée : elapsedaugmente (0 → 1 → 2 → … → duration).
Pendant la descente : elapseddiminue (duration → … → 2 → 1 → 0).
Pendant la pause : elapsedne change pas (car direction = 0).
Deux conditions de retournement :luaCopierif properties.elapsed >= properties.duration then -- En HAUT elseif properties.elapsed <= 0 then -- En BAS
Pourquoi un chronomètre plutôt qu’une distance ? Avec des vitesses en Vector3 (diagonales possibles), mesurer un temps est plus simple et plus fiable que mesurer une distance 3D à chaque frame !
On coupe d’abord la direction (0), puis on programme la suite avec task.delay.
Pourquoi pas task.wait ? On est dans une boucle Heartbeat ! Un task.wait(3)bloquerait toute la boucle pendant 3 secondes… et tous les autres ascenseurs seraient figés aussi ! task.delay programme l’action sans rien bloquer.
6. La protection contre la double connexion
if connection then return end
Le danger : si on appelle startMovement(elevators)deux fois (erreur de copier-coller par exemple), on aurait deux boucles Heartbeat actives en même temps.
Résultat catastrophique : chaque frame déplacerait les ascenseurs deux fois → vitesse doublée, elapsed doublé, chaos total !
La protection : si connection existe déjà (pas nil), la fonction s’arrête immédiatement. Un seul Heartbeat possible, garanti. C’est une variante du principe du cooldown !
7. La vélocité pour transporter les joueurs (rappel !)
Technique du script précédent : même si la Part est ancrée, Roblox lit sa vélocité pour entraîner les joueurs debout dessus.
En pause, on remet la vélocité à zéro (Vector3.new(0, 0, 0)) : arrêt propre, personne ne glisse.
Détail important : ici la vitesse est un Vector3 (ex: Vector3.new(20, 20, 20)), donc l’ascenseur 1 monte en diagonale et le 2 avance horizontalement — la même fonction gère les deux cas !
QCM : Teste ta compréhension !
Sur le tableau des ascenseurs :
Que stocke elevators[part] ?
a) Une fiche de paramètres (vitesse, durée, pause, direction, temps écoulé) propre à chaque ascenseur.
b) Le nom du joueur.
c) La couleur de la Part.
Que fait speed = speed or Vector3.new(20, 20, 20) ?
a) Si aucune vitesse n’est fournie, on utilise la vitesse par défaut Vector3.new(20, 20, 20).
b) On additionne les deux vitesses.
c) On supprime la vitesse.
Quel est l’avantage de stocker tous les ascenseurs dans le tableau elevators ?
a) Une seule boucle Heartbeat gère tous les ascenseurs, même si on en ajoute 10 de plus.
b) Le jeu va plus vite.
c) Les ascenseurs sont plus colorés.
Sur la boucle pairs :
Que fait for part, properties in pairs(elevators) do ?
a) Parcourt le tableau associatif et donne chaque clé (part) et sa valeur (properties).
b) Parcourt uniquement les nombres de 1 à 10.
c) Supprime le tableau.
Quelle est la différence entre ipairs et pairs ?
a) ipairs parcourt les listes numérotées (1, 2, 3…), pairs parcourt les tableaux avec n’importe quelle clé (comme des Parts).
b) ipairs est plus rapide.
c) pairs ne fonctionne qu’avec des joueurs.
Sur la direction :
Que se passe-t-il quand properties.direction = -1 ?
a) L’ascenseur descend (vitesse multipliée par -1) et elapsed diminue.
b) L’ascenseur s’arrête.
c) L’ascenseur double de vitesse.
Pourquoi un seul calcul speed * direction * deltaTime gère-t-il montée, descente ET pause ?
a) Car multiplier par 1 donne la vitesse, par -1 l’inverse, et par 0 rien du tout.
b) Car Lua devine automatiquement quoi faire.
c) Car les ascenseurs sont intelligents.
Sur le chronomètre elapsed :
À quoi sert la variable elapsed ?
a) À compter le temps écoulé depuis le bas, pour savoir quand faire demi-tour.
b) À compter les joueurs sur l’ascenseur.
c) À afficher l’heure.
Que se passe-t-il quand elapsed >= duration ?
a) L’ascenseur est en haut : il se met en pause, puis repartira en descente.
b) Le jeu s’arrête.
c) L’ascenseur est détruit.
Sur les pauses et la protection :
Pourquoi utilise-t-on task.delay plutôt que task.wait pour la pause ?
a) task.wait bloquerait la boucle Heartbeat et figerait TOUS les ascenseurs ; task.delay programme la suite sans rien bloquer.
b) task.delay est plus court à écrire.
c) task.wait n’existe plus.
Que risque-t-on si on supprime la ligne if connection then return end et qu’on appelle startMovement deux fois ?
a) Deux boucles Heartbeat déplaceraient chaque ascenseur deux fois par frame : vitesse doublée et chaos.
b) Rien, c’est juste une décoration.
c) Le jeu planterait immédiatement.
Pourquoi met-on AssemblyLinearVelocity à zéro quand direction = 0 ?
a) Pour un arrêt propre : le joueur ne glisse pas pendant la pause de l’ascenseur.
Apprendre à déplacer une Part en utilisant la physique de Roblox avec les propriétés AssemblyLinearVelocity et AssemblyAngularVelocity. Contrairement au tutoriel précédent où on modifiait directement la Position et l’Orientation, ici on utilise les vitesse linéaire et angulaire pour un mouvement plus réaliste et dynamique.
Introduction : Pourquoi utiliser la physique ?
Dans Roblox, les objets peuvent bouger naturellement grâce à la physique (gravité, collisions, etc.). En utilisant AssemblyLinearVelocity et AssemblyAngularVelocity, on peut :
Simuler des mouvements réalistes (ex: une balle qui roule, un objet qui glisse).
Créer des effets dynamiques (ex: une voiture qui accélère, un objet qui tourne).
Contrôler la vitesse et la rotation de manière fluide.
Dans ce tutoriel, on va lancer une Part dans différentes directions et la faire tourner en utilisant la physique.
Préparation dans Roblox Studio
Pour tester ce script, suis ces étapes :
Créer un dossier pour les mouvements :
Dans Workspace, crée un dossier nommé Folder.
Ajouter une Part :
Ajoute une Part dans Folder.
Nomme-la Part (ou modifie le nom dans le script).
Configurer la Part :
Assure-toi que la Part a une taille visible (ex: Size = Vector3.new(4, 4, 4)).
Place-la à une position centrale (ex: Position = Vector3.new(0, 10, 0)).
Ajouter le script :
Crée un Script dans ServerScriptService et copie-y le code fourni.
Lancer le jeu :
Observe la Part :
Après 5 secondes, elle commence à se déplacer vers l’avant (Z).
Elle recule, tourne, monte, et se déplace en diagonale.
Voici le script commenté :
-- Récupérer le dossier "Folder" dans le Workspace
local folder = workspace:WaitForChild("Folder")
-- Récupérer la Part à déplacer dans le dossier
local movingPart = folder:WaitForChild("Part")
-- Désactiver l'ancrage pour permettre à la Part de bouger avec la physique
movingPart.Anchored = false
-- Attendre 5 secondes avant de commencer les mouvements
task.wait(5)
-- Appliquer une vitesse linéaire de 100 unités/seconde vers l'avant (axe Z)
movingPart.AssemblyLinearVelocity = Vector3.new(0, 0, 100)
task.wait(1) -- Attendre 1 seconde
-- Appliquer une vitesse linéaire de -100 unités/seconde vers l'arrière (axe Z)
movingPart.AssemblyLinearVelocity = Vector3.new(0, 0, -100)
task.wait(1)
-- Appliquer une vitesse angulaire de 10 degrés/seconde autour de l'axe Y (rotation droite/gauche)
movingPart.AssemblyAngularVelocity = Vector3.new(0, 10, 0)
task.wait(1)
-- Appliquer une vitesse angulaire de -10 degrés/seconde autour de l'axe Y (rotation gauche/droite)
movingPart.AssemblyAngularVelocity = Vector3.new(0, -10, 0)
task.wait(1)
-- Appliquer une vitesse linéaire de 100 unités/seconde vers le haut (axe Y)
movingPart.AssemblyLinearVelocity = Vector3.new(0, 100, 0)
task.wait(1)
-- Appliquer une vitesse linéaire de 100 unités/seconde en diagonale (axe Y et Z)
movingPart.AssemblyLinearVelocity = Vector3.new(0, 100, 100)
task.wait(1)
-- Appliquer une vitesse angulaire de 10 degrés/seconde autour de l'axe Y (rotation)
movingPart.AssemblyAngularVelocity = Vector3.new(0, 10, 0)
Explications Détaillées
1. Désactiver l’ancrage (Anchored = false)
movingPart.Anchored = false
Anchored = false :
Permet à la Part de bouger librement sous l’effet de la physique (gravité, collisions, vitesses appliquées).
Sans cela, la Part resterait fixe et les vitesses n’auraient aucun effet.
Pourquoi est-ce important ?
Si Anchored = true, la Part ne pourrait pas bouger, même avec AssemblyLinearVelocity ou AssemblyAngularVelocity.
Apprendre à déplacer une Part dans Roblox en utilisant les propriétés Position et Orientation. Ce tutoriel explique :
Comment accéder à une Part dans le Workspace.
Comment déplacer une Part en modifiant sa Position.
Comment faire tourner une Part en modifiant son Orientation.
Comment utiliser task.wait() pour créer des délais entre les mouvements.
Introduction : Pourquoi déplacer une Part ?
Dans Roblox, les Part sont les éléments de base pour construire des objets. Savoir les déplacer et les faire tourner permet de :
Créer des animations (ex: une porte qui s’ouvre, un ascenseur qui monte).
Simuler des mouvements (ex: un objet qui se déplace automatiquement).
Contrôler des éléments du jeu (ex: une plateforme qui bouge).
Dans ce tutoriel, on va déplacer une Part dans différentes directions et la faire tourner autour des axes X, Y et Z.
Préparation dans Roblox Studio
Pour tester ce script, suis ces étapes :
Créer un dossier pour les mouvements :
Dans Workspace, crée un dossier nommé MovementsFolder.
Ajouter une Part :
Ajoute une Part dans MovementsFolder.
Nomme-la Part (ou modifie le nom dans le script).
Ajouter le script :
Crée un Script dans ServerScriptService et copie-y le code fourni.
Lancer le jeu :
Observe la Part :
Après 5 secondes, elle commence à se déplacer.
Elle se déplace sur les axes X, Y et Z, puis tourne autour des axes X, Y et Z.
Voici le script commenté sous ServerScriptService :
-- Récupérer le dossier "MovementsFolder" dans le Workspace
local movementsFolder = workspace:WaitForChild("MovementsFolder")
-- Récupérer la Part à déplacer dans le dossier
local movingPart = movementsFolder:WaitForChild("Part")
-- Empêcher la Part de bouger à cause des collisions ou de la gravité
movingPart.Anchored = true
-- Attendre 5 secondes avant de commencer les mouvements
task.wait(5)
-- Déplacer la Part de +50 unités sur l'axe X (droite)
movingPart.Position += Vector3.new(50, 0, 0)
task.wait(1) -- Attendre 1 seconde
-- Déplacer la Part de -50 unités sur l'axe X (gauche, retourne à la position initiale)
movingPart.Position += Vector3.new(-50, 0, 0)
task.wait(1)
-- Déplacer la Part de +50 unités sur l'axe Z (avant)
movingPart.Position += Vector3.new(0, 0, 50)
task.wait(1)
-- Déplacer la Part de -50 unités sur l'axe Z (arrière, retourne à la position initiale)
movingPart.Position += Vector3.new(0, 0, -50)
task.wait(1)
-- Déplacer la Part de +50 unités sur l'axe Y (haut)
movingPart.Position += Vector3.new(0, 50, 0)
task.wait(1)
-- Déplacer la Part de -50 unités sur l'axe Y (bas, retourne à la position initiale)
movingPart.Position += Vector3.new(0, -50, 0)
task.wait(1)
-- Faire tourner la Part de +10 degrés autour de l'axe Y (rotation vers la droite)
movingPart.Orientation += Vector3.new(0, 10, 0)
task.wait(1)
-- Faire tourner la Part de -10 degrés autour de l'axe Y (rotation vers la gauche, retourne à l'orientation initiale)
movingPart.Orientation += Vector3.new(0, -10, 0)
task.wait(1)
-- Faire tourner la Part de +10 degrés autour de l'axe Z (rotation vers le haut)
movingPart.Orientation += Vector3.new(0, 0, 10)
task.wait(1)
-- Faire tourner la Part de -10 degrés autour de l'axe Z (rotation vers le bas, retourne à l'orientation initiale)
movingPart.Orientation += Vector3.new(0, 0, -10)
task.wait(1)
-- Faire tourner la Part de +10 degrés autour de l'axe X (rotation vers l'avant)
movingPart.Orientation += Vector3.new(10, 0, 0)
task.wait(1)
-- Faire tourner la Part de -10 degrés autour de l'axe X (rotation vers l'arrière, retourne à l'orientation initiale)
movingPart.Orientation += Vector3.new(-10, 0, 0)
Explications Détaillées
1. Accéder à une Part dans le Workspace
local movementsFolder = workspace:WaitForChild("MovementsFolder")
local movingPart = movementsFolder:WaitForChild("Part")
workspace:WaitForChild("MovementsFolder") :
Attend que le dossier MovementsFolder existe dans le Workspace.
Si le dossier n’existe pas encore, le script attend qu’il soit créé.
movementsFolder:WaitForChild("Part") :
Attend que la Part existe dans le dossier MovementsFolder.
Si la Part n’existe pas encore, le script attend qu’elle soit créée.
Pourquoi utiliser WaitForChild ?
Cela évite les erreurs si le dossier ou la Part ne sont pas encore chargés quand le script s’exécute.
2. Empêcher la Part de bouger (Anchored)
movingPart.Anchored = true
Anchored = true :
Empêche la Part de bouger à cause de la gravité ou des collisions.
Sans cela, la Part tomberait ou serait poussée par d’autres objets.
Pourquoi est-ce important ?
Si Anchored = false, la Part serait soumise à la physique (gravité, collisions), ce qui rendrait les mouvements imprévisibles.
3. Déplacer une Part avec Position
movingPart.Position += Vector3.new(50, 0, 0)
Position :
Propriété qui stocke la position de la Part dans l’espace 3D (coordonnées X, Y, Z).
Exemple : Vector3.new(50, 0, 0) signifie 50 unités sur l’axe X, 0 sur Y, 0 sur Z.
+= :
Ajoute un Vector3 à la position actuelle.
Exemple : Si movingPart.Position = Vector3.new(0, 0, 0), alors après += Vector3.new(50, 0, 0), la nouvelle position sera Vector3.new(50, 0, 0).
Axes dans Roblox : Axe Direction Exemple de mouvement X Gauche/Droite Vector3.new(50, 0, 0) → Déplacement vers la droite Y Haut/Bas Vector3.new(0, 50, 0) → Déplacement vers le haut Z Avant/Arrière Vector3.new(0, 0, 50) → Déplacement vers l’avant
4. Faire tourner une Part avec Orientation
movingPart.Orientation += Vector3.new(0, 10, 0)
Orientation :
Propriété qui stocke la rotation de la Part autour des axes X, Y et Z (en degrés).
Exemple : Vector3.new(0, 10, 0) signifie 10 degrés autour de l’axe Y.
+= :
Ajoute une rotation à l’orientation actuelle.
Exemple : Si movingPart.Orientation = Vector3.new(0, 0, 0), alors après += Vector3.new(0, 10, 0), la nouvelle orientation sera Vector3.new(0, 10, 0).
Axes de rotation : Axe Rotation Exemple X Inclinaison avant/arrière Vector3.new(10, 0, 0) → Rotation vers l’avant Y Rotation gauche/droite Vector3.new(0, 10, 0) → Rotation vers la droite Z Rotation autour de l’axe vertical Vector3.new(0, 0, 10) → Rotation dans le sens horaire
5. Créer des délais avec task.wait()
task.wait(5) -- Attendre 5 secondes
task.wait(durée) :
Pause l’exécution du script pendant durée secondes.
Exemple : task.wait(1) attend 1 seconde avant de continuer.
Pourquoi utiliser task.wait() ?
Pour espacer les mouvements et les rendre visibles.
Sans délai, les mouvements seraient trop rapides pour être vus.
QCM : Teste ta compréhension !
Sur l’accès aux objets :
Que fait workspace:WaitForChild("MovementsFolder") ?
a) Attend que le dossier MovementsFolder existe dans le Workspace.
b) Crée un nouveau dossier.
c) Supprime le dossier.
Pourquoi utilise-t-on WaitForChild ?
a) Pour éviter les erreurs si l’objet n’existe pas encore.
b) Pour accélérer le script.
c) Pour changer la couleur de la Part.
Sur le déplacement :
Que fait movingPart.Position += Vector3.new(50, 0, 0) ?
a) Déplace la Part de 50 unités vers la droite (axe X).
b) Déplace la Part de 50 unités vers le haut (axe Y).
c) Déplace la Part de 50 unités vers l’avant (axe Z).
Que fait Vector3.new(0, 50, 0) ?
a) Crée un vecteur pour déplacer la Part de 50 unités vers le haut.
b) Crée un vecteur pour faire tourner la Part.
c) Crée un vecteur pour changer la couleur de la Part.
Pourquoi utilise-t-on Anchored = true ?
a) Pour empêcher la Part de bouger à cause de la gravité ou des collisions.
b) Pour rendre la Part invisible.
c) Pour supprimer la Part.
Sur la rotation :
Que fait movingPart.Orientation += Vector3.new(0, 10, 0) ?
a) Fait tourner la Part de 10 degrés autour de l’axe Y (droite/gauche).
b) Fait tourner la Part de 10 degrés autour de l’axe X (avant/arrière).
c) Fait tourner la Part de 10 degrés autour de l’axe Z (sens horaire/anti-horaire).
Que fait Vector3.new(10, 0, 0) pour l’orientation ?
a) Fait tourner la Part de 10 degrés autour de l’axe X (avant/arrière).
b) Fait tourner la Part de 10 degrés autour de l’axe Y (droite/gauche).
c) Fait tourner la Part de 10 degrés autour de l’axe Z.
Sur les délais :
À quoi sert task.wait(5) ?
a) Attendre 5 secondes avant de continuer le script.
b) Accélérer le script.
c) Supprimer la Part.
Pourquoi utilise-t-on task.wait(1) entre chaque mouvement ?
a) Pour espacer les mouvements et les rendre visibles.
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)
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.
Comment parcourir les checkpoints dans un dossier avec une boucle for.
Comment stocker le dernier checkpoint pour chaque joueur.
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 :
Créer un dossier pour les checkpoints :
Dans Workspace, crée un dossier nommé CheckpointsFolder.
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.
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 :
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.
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.
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 :
À 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.
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.
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 :
À quoi sert player.CharacterAdded:Connect(...) ?
a) Exécuter une fonction quand un joueur réapparaît dans la partie.
La voiture robotisée UNIHIKER K10 est une plateforme d’apprentissage conçue pour t’initier à la programmation et à l’intelligence artificielle. Elle associe le châssis Maqueen Plus V3 à la carte de contrôle principale UNIHIKER K10, intégrant des technologies telles que le contrôle, l’affichage graphique, la reconnaissance vocale, la synthèse vocale, le traitement d’images et la communication sans fil. Elle te permet de progresser au codage des robots en maîtrisant l’interaction avec le matériel, les applications de capteurs et d’autres compétences clés.
Cette voiture robotisée excelle non seulement dans la conduite et la perception de l’environnement, mais elle prend également en charge des interactions multimodales telles que la lumière, le son et l’affichage, rendant l’apprentissage plus ludique et immersif.
L’objectif est le pilotage de ton maqueen piloté par l carte micro:bit avec le gamepad équipé d’une micro:bit
Introduction au matériel
1. Châssis intelligent Maqueen Plus V3
5 capteurs de suivi de ligne : Prend en charge la reconnaissance des lignes noires et le suivi de trajectoire pour les tâches de suivi de ligne intelligentes.
2 capteurs de lumière : détectent la luminosité ambiante pour un éclairage intelligent ou un contrôle du comportement sensible à la lumière.
Capteur laser matriciel : utilise 64 points laser pour l’évitement d’obstacles et la détection de falaises avec une précision millimétrique.
Phares et éclairage d’ambiance RGB pour voiture : 16 millions de couleurs personnalisables pour une meilleure visibilité et un retour d’information précis.
Buzzer : Émet des alertes sonores pour une meilleure interaction homme-machine.
Moteurs métalliques détachables : Parfaitement adaptés pour une rotation fluide sans calage.
Introduction au logiciel
Mind+ est un logiciel de programmation graphique facile à utiliser. Compatible avec de nombreuses plateformes matérielles, il propose un large éventail de modules et de ressources de programmation.
Interface graphique intuitive : Mind+ propose une interface glisser-déposer qui permet de créer des programmes sans écrire de code complexe. Cette conception intuitive facilite grandement la prise en main et permet aux débutants de se familiariser rapidement avec le logiciel.
Compatibilité matérielle étendue : Mind+ prend en charge une variété de périphériques, notamment le Maqueen Plus V3 et l’UNIHIKER K10.
Modules de programmation riches : Le logiciel propose un ensemble varié de modules couvrant le contrôle de mouvement, le traitement des données de capteurs, l’affichage graphique, la lecture audio, et bien plus encore.
L’interface de Mind+ comporte 8 zones principales : barre de menu, sélecteur de mode, outils rapides, blocs de commandes, zone de script, zone de code, extensions et moniteur série.
Apprendre à programmer deux robots (un Gamepad et un Maqueen) pour qu’ils communiquent sans fil via la radio Micro:bit. Tu vas :
Utiliser les entrées du Gamepad (boutons et joystick) pour contrôler le Maqueen.
Envoyer des commandes depuis le Gamepad (avec une Micro:bit).
Recevoir et exécuter ces commandes sur le Maqueen (avec une autre Micro:bit).
Matériel nécessaire
Élément
Quantité
Rôle
Micro:bit
2
Une pour le Gamepad, une pour le Maqueen.
Robot Maqueen
1
Robot à piloter.
Gamepad
1
Contrôleur avec boutons et joystick (ex: Micro:bit Gamepad ou un Gamepad externe compatible).
Piles
2 x 2 (AAA)
Alimentation des Micro:bit.
Câbles USB
2
Pour programmer les Micro:bit.
Étape 1 : Comprendre la communication radio Micro:bit
La Micro:bit permet d’envoyer et recevoir des messages sans fil via un canal radio (de 1 à 7).
Un seul canal peut être utilisé à la fois par un groupe de Micro:bit.
Si plusieurs groupes travaillent en même temps, chaque groupe doit choisir un canal différent (ex: groupe 1 = canal 1, groupe 2 = canal 2, etc.).
Instructions radio de base :
Programmer le Gamepad (Émetteur)
Passez en mode téléchargement : tous les projets de ce cours utilisent ce mode.
Ajouter la carte de contrôle principale : « Extensions » > « Cartes » > « MICRO:BIT »
Ajoutez la carte d’extension : « Extensions » > «User Ext » > «gamepad »
Le Gamepad va envoyer des commandes au Maqueen en fonction des boutons et du joystick.
Active la radio et définit le canal 1 (à adapter selon ton groupe).
Détecte les boutons pressés du gamepad :
Sur le gamepad utilise les instructions (NEW) button pour envoyer la commande sur l’appui d’un bouton ou l’utilisation du joystick :
Envoie des commandes comme « forward » pour avancer.
Ajoute une instruction d’affichage pour vérifier :
A toi de trouver le programme pour piloter ton robot.
avancer
reculer
tourner à droite
tourner à gauche
Programmer le Maqueen (Récepteur)
Le Maqueen va recevoir les commandes du Gamepad et agir en conséquence (avancer, reculer, tourner, etc.).
Ajoute les extensions :.
Ajouter la carte de contrôle principale : « Extensions » > « Cartes » > « MICRO:BIT »
Ajoutez la carte d’extension : « Extensions » > « Carte d’extension » ou « shield board » > « Maqueen Plus V2/V3 »
Utilise les mêmes instructions de transmission des ordres par radio sauf que tu vas utiliser une instruction de réception when received.
Active la radio et définit le canal 1 (à adapter selon ton groupe).
Appelle when received la fonction puis serial in stringquand un message est reçu.
Puis teste la commande reçue en l’occurrence forward :
Vérifie la bonne réception du message reçu en utilisant une instruction pour activer les LEDs de la micro:bit.
Utilise ces commandes pour actionner les moteurs du Maqueen :
Par exemple pour accepter la commande forward et faire avancer le robot :
A toi de trouver comment programmer le Maqueen pour le faire reculer, tourner à droite, tourner à gauche ….
Utilise tes connaissances pour améliorer ton robot en utilisant le Joystick pour piloter le robot, rajoute une commande pour l’arrêter, allumer les LEDs …