Créer un jeu sur Roblox, inventer une expérience interactive pour les joueurs. tu vas construire un véritable espace de salles de cinéma interactives dans Roblox Studio.
Le joueur peut se déplacer librement d’une salle à l’autre, découvrir différents écrans et interagir directement avec eux grâce à la souris. Chaque salle pourra proposer une ambiance différente, des boutons interactifs ou des animations qui réagissent aux actions du joueur.
Par script, tu iras encore plus loin en découvrant comment modifier la caméra du joueur pour rendre l’expérience plus immersive. Selon les situations, la caméra permettra :
- de passer automatiquement en vue First Person lorsque le joueur entre dans une salle ;
- ou de rapprocher la caméra du personnage pour donner un effet de cinéma ou de jeu narratif ;
- et même de changer la caméra avec une touche du clavier.
À travers ce projet, tu utilisera plusieurs outils importants de Roblox Studio :
- la création d’interfaces et d’écrans interactifs sur des parts;
- les scripts en langage Lua ;
- la gestion des déplacements du joueur ;
- les événements déclenchés par le clavier ou les collisions ;
- et le contrôle de la caméra pour améliorer l’immersion du jeu.
A toi de réfléchir à partir de ces scripts pour programmer un jeu comme de vrais créateurs de jeux vidéo : comment guider le joueur, rendre une salle intéressante et créer une ambiance unique grâce à la caméra et aux interactions.

Crée la structure de la salle de cinéma avec une boite de collision hit box et un écran sur le lequel tu positionnes un surfaceGui. Sur le surfaceGui crée un textButton que l’on fera bouger :


Le joueur interagit sur le bouton.

Crée et modifie le script sous surfaceGui pour déplacer le bouton et interagir avec la souris :

-- récupération du frame
local frame = script.Parent.Frame
-- récupération du service de tween
local tweenService = game:GetService("TweenService")
-- récupération du bouton
local button = frame.TextButton
-- variable de bascule entre pause et reprendre le déplacement
local pause = false
-- couleur de base du bouton
local colorBase = button.BackgroundColor3
-- déplacement horizontal du bouton avec un tweenService
local tween = tweenService:Create(button,
TweenInfo.new(10,
Enum.EasingStyle.Linear,
Enum.EasingDirection.InOut, -1, false),
{Position = button.Position + UDim2.new(1, 0, 0, 0)})
tween:Play()
-- action sur le click de souris
button.MouseButton1Click:Connect(function()
--click de la souris pour mettre en pause ou reprendre le tween
pause = not pause
if pause then
tween:Pause()
button.BackgroundColor3 = Color3.fromRGB(0, 255, 0)
else
tween:Play()
button.BackgroundColor3 = colorBase
end
end)
Sous ReplicatedStorage crée un remoteEvent, ce remoteEvent est utilisé pour prévenir un scriptLocal du joueur afin de changer son comportement :

La hitbox est une Part qui occupe tout l’intérieur de la salle. Elle est transparente et sans CanCollide. Elle sert à gérer la collision lorsque le joueur pénètre dans la salle.
Crée et modifie ce script pour gérer la collision avec le joueur quand celui ci rentre ou sort de la salle pour envoyer un signal au script local du joueur :

local ReplicatedStorage = game:GetService("ReplicatedStorage")
-- récupération du remoteEvent
local kioskEvent = ReplicatedStorage:WaitForChild("KioskEvent")
-- récupération des services Debris
local Debris = game:GetService("Debris")
-- récupération de la hitbox
local hitbox = script.Parent
-- nom de l'action
local actionName = "KioskLocked"
--- durée du cooldown en secondes
local COOLDOWN_DURATION = 2
-- locker du kiosk
local function KioskLocked(character)
-- si le joueur est déjà dans la salle, ne rien faire
if character:FindFirstChild(actionName) then return false end
-- création d'un tag temporaire pour indiquer que le joueur est dans la salle
local tag = Instance.new("Folder")
tag.Name = actionName
tag.Parent = character
Debris:AddItem(tag, COOLDOWN_DURATION)
return true
end
-- détection du joueur qui entre dans la salle
hitbox.Touched:Connect(function(hit)
local player = game.Players:GetPlayerFromCharacter(hit.Parent)
if player then
local character = player.Character
if not character then return end
-- Envoyer au client concerné uniquement
if KioskLocked(character) then
kioskEvent:FireClient(player, true)
end
end
end)
-- détection du joueur qui sort de la salle
hitbox.TouchEnded:Connect(function(hit)
local player = game.Players:GetPlayerFromCharacter(hit.Parent)
if player then
local character = player.Character
if not character then return end
-- Envoyer au client concerné uniquement
if KioskLocked(character) then
kioskEvent:FireClient(player, false)
end
end
end)
Crée un localScript sous StarterPlayer pour gérer une touche pour le changement de caméra sur le joueur ou pour gérer le remoteEvent venant du serveur :

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local kioskEvent = ReplicatedStorage:WaitForChild("KioskEvent")
local CinemaEvent = ReplicatedStorage:WaitForChild("CinemaEvent")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local player = Players.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local humanoid = char:FindFirstChildOfClass("Humanoid")
local head = char:WaitForChild("Head")
local hrp = char:WaitForChild("HumanoidRootPart")
local cam = workspace.CurrentCamera
local angleY = 0
local angleX = 0
local DISTANCE = -0.5
local HEIGHT = 0
local KEY_ROTATION_SPEED = 2
local isLocked = false
local connection = nil -- stocker la connexion pour pouvoir la couper
local function enableLockedCam(firstPerson, viewAngle, distance, height)
-- Paramètres par défaut
if firstPerson == nil then
firstPerson = true
end
viewAngle = viewAngle or {0,0}
distance = distance or DISTANCE
height = height or HEIGHT
cam.CameraType = Enum.CameraType.Custom
if firstPerson then
UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
else
UserInputService.MouseBehavior = Enum.MouseBehavior.Default
end
-- Initialiser l'angle sur la rotation actuelle du personnage
-- Correction : ToEulerAnglesYXZ retourne (X, Y, Z), l'angle horizontal est le 2ème
local currentAngleX, currentAngleY, _ = hrp.CFrame:ToEulerAnglesYXZ()
angleY = math.deg(currentAngleY)
angleX = math.deg(currentAngleX)
local initangleY = angleY
local initangleX = angleX
connection = RunService.RenderStepped:Connect(function()
local delta = UserInputService:GetMouseDelta()
-- Rotation clavier (flèches ou Q/D)
local keyDeltaX = 0
if UserInputService:IsKeyDown(Enum.KeyCode.Left) or UserInputService:IsKeyDown(Enum.KeyCode.Q) then
keyDeltaX = -KEY_ROTATION_SPEED
elseif UserInputService:IsKeyDown(Enum.KeyCode.Right) or UserInputService:IsKeyDown(Enum.KeyCode.D) then
keyDeltaX = KEY_ROTATION_SPEED
end
local keyDeltaY = 0
if UserInputService:IsKeyDown(Enum.KeyCode.Up) then
keyDeltaY = KEY_ROTATION_SPEED
elseif UserInputService:IsKeyDown(Enum.KeyCode.Down) then
keyDeltaY = -KEY_ROTATION_SPEED
end
-- Fusionner souris + clavier
local totalDeltaX = delta.X + keyDeltaX
local totalDeltaY = delta.Y + keyDeltaY
if viewAngle[1] > 0 then
angleY = math.clamp(angleY - totalDeltaX, -viewAngle[1]+initangleY, viewAngle[1]+initangleY)
else
angleY = angleY - totalDeltaX * 0.3
end
if viewAngle[2] > 0 then
angleX = math.clamp(angleX - totalDeltaY, -viewAngle[2]+initangleX, viewAngle[2]+initangleX)
else
angleX = 0
end
-- Caméra placée dans la tête, regardant vers l'avant
local rotation = CFrame.new(head.Position) * CFrame.Angles(math.rad(angleX), math.rad(angleY), 0)
-- Reculer la caméra derrière la tête (ajuste la valeur selon le rendu)
local camCFrame = rotation * CFrame.new(0, height, distance)
cam.CFrame = camCFrame
-- Tourner le personnage avec la caméra
hrp.CFrame = CFrame.new(hrp.Position) * CFrame.Angles(0, math.rad(angleY), 0)
end)
end
local function disableLockedCam()
-- Couper le RenderStepped
if connection then
task.spawn(function()
RunService.RenderStepped:Wait()
connection:Disconnect()
connection = nil
end)
end
-- Restaurer le comportement normal de Roblox
local cam = workspace.CurrentCamera
cam.CameraType = Enum.CameraType.Custom
-- 2. Reassigner le sujet (crucial !)
if humanoid then
cam.CameraSubject = humanoid
end
-- 3. Laisser Roblox reprendre le contrôle au prochain frame
RunService.RenderStepped:Wait()
UserInputService.MouseBehavior = Enum.MouseBehavior.Default
end
-- Toggle avec F
UserInputService.InputBegan:Connect(function(input, gameProcessed)
if gameProcessed then return end
if input.KeyCode == Enum.KeyCode.F then
print("F",isLocked)
isLocked = not isLocked
if isLocked then
enableLockedCam(false, {120,10},5, 2)
else
disableLockedCam()
end
end
end)
screen.Enabled = false
-- Écouter l'événement envoyé par le serveur
kioskEvent.OnClientEvent:Connect(function(entered)
print("KioskEvent reçu :", entered)
if entered then
enableLockedCam(false, {0,0},-1, 1)
else
disableLockedCam()
end
end)
Vue derrière le joueur :
enableLockedCam(false, {120,10},5, 2)
{angle de vision horizontal, angle de vision vertical, 5 studs en arrière, 2 au dessus de la tête

Vue devant le joueur :
enableLockedCam(false, {120,0},-1, 0)
{angle de vision horizontal, angle de vision vertical, 1 stud en avant de la tête, 0 au dessus de la tête

Vue firstperson :
enableLockedCam(true)
