Module 05 · Leçon 4 sur 6
Créer des interfaces lisibles partout
Construis le compteur de pièces et la boutique de l’Obby des Nuages avec ScreenGui, Scale, AnchorPoint et les layouts, pour une interface lisible sur PC comme sur téléphone.
- ⏱️ 40 min
- 📝 Quiz de 6 questions
- 🔄 Vérifié le 24 octobre 2026
Sur cette page
- Les briques d’une interface
- ResetOnSpawn : survivre aux chutes
- Scale ou Offset : la clé de l’adaptation
- AnchorPoint : le point d’accroche
- Les contraintes qui sauvent ta mise en page
- Les layouts : ranger automatiquement
- Le texte : lisible sans exagérer
- Les zones de sécurité des écrans
- Construire l’interface de l’Obby des Nuages
- Le LocalScript qui relie tout
- Tester sur plusieurs écrans
- Quiz de fin de leçon
🎯 Dans cette leçon, tu vas apprendre à…
- Construire une interface avec ScreenGui, Frame, TextLabel et TextButton
- Rendre l’interface adaptable à toutes les tailles d’écran avec Scale, AnchorPoint et les contraintes
- Respecter les zones de sécurité des écrans mobiles
- Relier l’interface au jeu avec un LocalScript
Ton Obby des Nuages a des pièces et une boutique… mais pour l’instant, il faut la Command Bar pour acheter ! Dans cette leçon, tu construis une interface : un compteur de pièces toujours visible et une fenêtre de boutique. Surtout, tu apprends à la rendre lisible partout : sur un grand écran de PC comme sur un petit téléphone.
Les briques d’une interface
Une interface à l’écran se construit avec des objets « GUI » (Graphical User Interface, interface graphique) :
| Objet | Rôle |
|---|---|
ScreenGui |
le conteneur : tout ce qu’il contient s’affiche à l’écran |
Frame |
un cadre rectangulaire, pour regrouper d’autres éléments |
TextLabel |
un texte non cliquable |
TextButton |
un bouton avec du texte |
ImageLabel |
une image (icône de pièce, par exemple) |
Les ScreenGui se rangent dans StarterGui. Quand le personnage d’un joueur apparaît, Roblox copie leur contenu dans le dossier PlayerGui de ce joueur. Chaque joueur a donc sa propre copie de l’interface, gérée sur son ordinateur (côté client).
ResetOnSpawn : survivre aux chutes
Par défaut, un ScreenGui a ResetOnSpawn = true : il est supprimé et recopié à chaque réapparition du personnage. Dans un obby, on tombe sans arrêt ! Pour notre interface, mets ResetOnSpawn à false : elle n’est créée qu’une fois, et la boutique ne se referme pas toute seule à chaque chute.
Scale ou Offset : la clé de l’adaptation
La position (Position) et la taille (Size) d’un élément sont des UDim2, qui contiennent quatre nombres : {Scale X, Offset X}, {Scale Y, Offset Y}.
- Scale : une fraction de la taille du parent.
0.5= 50 %. - Offset : un nombre de pixels.
Les deux s’additionnent. Un bouton de taille {0, 200}, {0, 50} fait 200 × 50 pixels sur tous les écrans : correct sur PC, mais il peut prendre la moitié d’un téléphone. Avec {0.2, 0}, {0.08, 0}, il occupe toujours 20 % de la largeur et 8 % de la hauteur.
AnchorPoint : le point d’accroche
L’AnchorPoint indique quel point de l’élément est placé à la Position. Par défaut (0, 0) : le coin supérieur gauche. Pour centrer une fenêtre, mets AnchorPoint = (0.5, 0.5) et Position = {0.5, 0}, {0.5, 0} : le centre de la fenêtre se place au centre de l’écran. Pour un élément collé en bas à droite : AnchorPoint = (1, 1) et Position = {1, 0}, {1, 0}.
Les contraintes qui sauvent ta mise en page
Le Scale seul a un défaut : sur un écran très large, un bouton carré devient un rectangle étiré. Les modificateurs règlent ça. On les ajoute comme enfants d’un élément :
UIAspectRatioConstraint: impose un rapport largeur/hauteur (AspectRatio = 1pour un carré,3pour un bandeau trois fois plus large que haut) ;UITextSizeConstraint: impose une taille de texte minimale et maximale ;UICorner: arrondit les coins ;UIPadding: ajoute une marge intérieure.
Les layouts : ranger automatiquement
Un layout place tout seul les éléments frères :
UIListLayout: en ligne ou en colonne ;UIGridLayout: en grille de cases de même taille (CellSize), idéal pour une boutique.
Avec un layout, plus besoin de placer chaque bouton à la main : ajoute un objet au catalogue, et il trouve sa place.
Le texte : lisible sans exagérer
La propriété TextScaled agrandit ou réduit le texte pour remplir son cadre. Utile, mais à utiliser avec modération : sur un petit cadre, le texte devient minuscule ; sur un grand écran, énorme. Associe-le à un UITextSizeConstraint. La documentation déconseille une MinTextSize inférieure à 9, illisible pour beaucoup de joueurs.
Pense aussi au contraste : du texte blanc sur un fond clair est pénible à lire. Un contour (UIStroke) ou un fond plus sombre aident beaucoup.
Les zones de sécurité des écrans
Les téléphones modernes ont des encoches (caméra) et des bords arrondis, et Roblox affiche ses propres boutons en haut de l’écran (menu, chat…). La propriété ScreenInsets d’un ScreenGui indique quelle zone ton interface doit respecter. D’après la documentation, au moment de la rédaction :
| Valeur | Effet | Usage conseillé |
|---|---|---|
CoreUISafeInsets (par défaut) |
évite la barre du haut de Roblox et les encoches | interfaces avec des boutons |
DeviceSafeInsets |
évite les encoches, mais pas la barre de Roblox | |
TopbarSafeInsets |
place le contenu dans la barre du haut, à droite des boutons de Roblox | petits indicateurs dans la barre |
None |
aucune marge : tout l’écran | fonds d’écran, éléments non interactifs |
Deux autres propriétés du ScreenGui existent : ClipToDeviceSafeArea (activée par défaut, elle coupe ce qui déborde de la zone sûre de l’appareil) et SafeAreaCompatibility, un mode de compatibilité pour les anciennes interfaces plein écran, que la documentation conseille d’éviter pour un nouveau projet au profit de ScreenInsets. Pour notre interface : laisse CoreUISafeInsets. On reviendra sur le mobile au module 10.
Construire l’interface de l’Obby des Nuages
Dans StarterGui, crée cette hiérarchie. Pour chaque objet, survole son futur parent dans l’Explorer, clique sur ⊕ (ou clic droit › Insert Object) et choisis le type indiqué entre parenthèses. Renomme ensuite l’objet exactement comme dans le schéma : le script les retrouve par leur nom.
StarterGui
└── InterfaceObby (ScreenGui, ResetOnSpawn = false)
├── CompteurPieces (Frame)
│ ├── UICorner
│ ├── UIAspectRatioConstraint (AspectRatio = 3)
│ └── Texte (TextLabel)
│ └── UITextSizeConstraint (MinTextSize = 12)
├── BoutonBoutique (TextButton, Text = « Boutique »)
├── Boutique (Frame, Visible = false)
│ ├── UICorner
│ ├── UIPadding
│ └── Liste (Frame transparent)
│ └── UIGridLayout
└── ScriptInterface (LocalScript)
Réglages conseillés (sélectionne l’objet, puis modifie ses propriétés dans la fenêtre Properties) :
- InterfaceObby : décoche
ResetOnSpawn. - CompteurPieces :
AnchorPoint = (0, 0),Position = {0.02, 0}, {0.03, 0},Size = {0.2, 0}, {0.08, 0}. LeUIAspectRatioConstraintle garde trois fois plus large que haut. - Texte :
Size = {1, 0}, {1, 0}(tout le cadre),BackgroundTransparency = 1,TextScaled = true, et son enfantUITextSizeConstraintavecMinTextSize = 12. - BoutonBoutique :
AnchorPoint = (0, 0.5),Position = {0.02, 0}, {0.5, 0},Size = {0.15, 0}, {0.08, 0},Text = Boutique: sur le bord gauche, à mi-hauteur. Évite les coins inférieurs : d’après la documentation, sur mobile, Roblox y affiche le joystick (en bas à gauche) et le bouton de saut (en bas à droite), et un bouton placé là serait caché par le pouce ou touché par erreur. On approfondira le mobile au module 10. - Boutique :
AnchorPoint = (0.5, 0.5),Position = {0.5, 0}, {0.5, 0},Size = {0.6, 0}, {0.6, 0}, et décocheVisible(la fenêtre est cachée au départ). - Liste :
Size = {1, 0}, {1, 0},BackgroundTransparency = 1. Dans son UIGridLayout :CellSize = {0.3, 0}, {0.4, 0}etCellPadding = {0.03, 0}, {0.03, 0}.
Les boutons des objets ne sont pas créés à la main : le script les fabrique à partir du Catalogue (leçon 3).
Le LocalScript qui relie tout
L’interface est côté client : on utilise donc un LocalScript. Placé dans un ScreenGui de StarterGui, il s’exécute une fois copié dans le PlayerGui du joueur. Crée le LocalScript ScriptInterface directement dans InterfaceObby et colle ce code. Tu peux aussi supprimer le LocalScript TestInventaire de la leçon 3 : l’interface le remplace.
-- LocalScript « ScriptInterface » dans StarterGui > InterfaceObby (côté client)
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Catalogue = require(ReplicatedStorage:WaitForChild("Modules"):WaitForChild("Catalogue"))
local remotes = ReplicatedStorage:WaitForChild("Remotes")
local acheterObjet = remotes:WaitForChild("AcheterObjet") :: RemoteEvent
local equiperObjet = remotes:WaitForChild("EquiperObjet") :: RemoteEvent
local joueur = Players.LocalPlayer
local interface = script.Parent
local texteCompteur = interface:WaitForChild("CompteurPieces"):WaitForChild("Texte") :: TextLabel
local boutonBoutique = interface:WaitForChild("BoutonBoutique") :: TextButton
local fenetreBoutique = interface:WaitForChild("Boutique") :: Frame
local liste = fenetreBoutique:WaitForChild("Liste") :: Frame
-- 1. LE COMPTEUR : on lit les leaderstats (créées par le serveur)
local pieces = joueur:WaitForChild("leaderstats"):WaitForChild("Pieces") :: IntValue
local function majCompteur()
texteCompteur.Text = `Pièces : {pieces.Value}`
end
pieces.Changed:Connect(majCompteur) -- à chaque changement de valeur
majCompteur() -- et une première fois au démarrage
-- 2. OUVRIR / FERMER LA BOUTIQUE
-- Activated fonctionne au clic de souris comme au toucher sur mobile
boutonBoutique.Activated:Connect(function()
fenetreBoutique.Visible = not fenetreBoutique.Visible
end)
-- 3. LES BOUTONS DES OBJETS, fabriqués à partir du catalogue
local boutons: { [string]: TextButton } = {}
-- Texte d'un bouton selon l'état publié par le serveur (attributs, leçon 3)
local function texteBouton(idObjet: string): string
local objet = Catalogue[idObjet]
if joueur:GetAttribute("TrailEquipe") == idObjet then
return `{objet.nom}\nÉquipé`
elseif joueur:GetAttribute("Possede_" .. idObjet) == true then
return `{objet.nom}\nÉquiper`
end
return `{objet.nom}\n{objet.prix} pièces`
end
local function majBoutons()
for idObjet, bouton in boutons do
bouton.Text = texteBouton(idObjet)
end
end
for idObjet, objet in Catalogue do
local bouton = Instance.new("TextButton")
bouton.Name = idObjet
bouton.BackgroundColor3 = objet.couleurDebut
bouton.TextColor3 = Color3.fromRGB(30, 30, 50) -- texte foncé : bon contraste
bouton.TextScaled = true
local coins = Instance.new("UICorner")
coins.Parent = bouton
local tailleTexte = Instance.new("UITextSizeConstraint")
tailleTexte.MinTextSize = 12
tailleTexte.MaxTextSize = 28
tailleTexte.Parent = bouton
-- Le client DEMANDE ; c'est le serveur qui vérifie et décide
bouton.Activated:Connect(function()
if joueur:GetAttribute("TrailEquipe") == idObjet then
equiperObjet:FireServer("") -- déjà équipé : on retire
elseif joueur:GetAttribute("Possede_" .. idObjet) == true then
equiperObjet:FireServer(idObjet)
else
acheterObjet:FireServer(idObjet)
end
end)
bouton.Parent = liste -- le UIGridLayout le range automatiquement
boutons[idObjet] = bouton
joueur:GetAttributeChangedSignal("Possede_" .. idObjet):Connect(majBoutons)
end
joueur:GetAttributeChangedSignal("TrailEquipe"):Connect(majBoutons)
majBoutons()
Remarque bien : ce script n’ajoute jamais de pièces et ne donne jamais d’objet. Il affiche ce que le serveur a décidé (leaderstats, attributs) et envoie des demandes. Même si un exploiteur modifie ce script, il ne peut que demander, et le serveur refuse ce qui n’est pas valide.
Tester sur plusieurs écrans
Studio peut afficher ton jeu comme sur un téléphone ou une tablette, en portrait et en paysage, avec le Device Simulator : une barre d’outils placée au-dessus de la vue 3D, que tu ouvres depuis le menu Test › Device Simulator (au moment de la rédaction, octobre 2026). Son fonctionnement, son statut (sorti de bêta selon l’annonce officielle du 16 octobre 2026) et ses limites sont détaillés au module 10, dans Penser mobile d’abord. Vérifie au minimum :
- que le compteur et le bouton restent visibles et ne passent pas sous la barre de Roblox, ni sous le joystick ou le bouton de saut ;
- que le texte reste lisible sur le plus petit appareil ;
- que les boutons sont assez grands pour un pouce.
Ce qu’il faut retenir
- Un
ScreenGuidans StarterGui est copié dans le PlayerGui de chaque joueur ; metsResetOnSpawn = falsepour une interface qui doit survivre aux chutes. - Le Scale (fraction du parent) rend l’interface adaptable ; l’Offset (pixels) est à réserver aux petits ajustements.
AnchorPointchoisit le point d’accroche ;UIAspectRatioConstraint,UITextSizeConstraint,UICorner,UIPaddinget les layouts font le reste.ScreenInsets = CoreUISafeInsets(par défaut) protège tes boutons des encoches et de la barre de Roblox.- Le LocalScript d’interface affiche l’état décidé par le serveur et envoie des demandes, sans jamais rien décider.
Sources et pour aller plus loin
- Position and size UI objects (dont les zones réservées aux contrôles tactiles) — documentation Roblox
- On-screen UI containers (ScreenInsets, ResetOnSpawn) — documentation Roblox
- ScreenGui — référence API
- Size modifiers and constraints — documentation Roblox
- List and flex layouts — documentation Roblox
- Grid and table layouts (UIGridLayout) — documentation Roblox
- Buttons — documentation Roblox
- Device Simulator — documentation Roblox
- New Device Simulator Toolbar and Network Simulator — annonce officielle de l’équipe Studio (DevForum, mise à jour du 16 octobre 2026)
- Rojo — Project Format (
$path,$ignoreUnknownInstances) - Rojo — Sync Details (
init.meta.json, fichiers.model.json) - Studio MCP server (outils
list_roblox_studios,search_game_tree,inspect_instance,script_read…) — documentation Roblox