Dans ce tutoriel, tu vas créer un jeu où le joueur doit détruire une pyramide de briques en lançant une balle.
Voici ce que tu vas apprendre :
- Construire une pyramide dynamiquement avec des tailles aléatoires.
- Détecter les interactions (quand le joueur entre dans une zone, appuie sur un bouton, etc.).
- Lancer une balle et vérifier si la pyramide est détruite.
- Gérer des effets comme le recul du joueur ou la caméra en première personne.


Étape 1 : Comprendre le jeu avant de coder
But : Visualiser le jeu et comprendre son fonctionnement.
Concepts clés : Logique de jeu, objets 3D.
Explications
Avant de coder, il faut imaginer le jeu :
- Une pyramide de briques est générée automatiquement au début.
- Le joueur entre dans une zone de lancer (hitbox).
- En appuyant sur un bouton (ProximityPrompt), il lance une balle.
- Si la balle détruit toutes les briques de la pyramide, le joueur gagne des points et est éjecté de la zone.
- Sinon, il perd un point et peut réessayer.
Objets nécessaires :
- Une hitbox (zone invisible pour détecter le joueur).
- Un modèle de balle (à cloner pour chaque lancer).
- Un modèle de brique (pour construire la pyramide).
- Un ProximityPrompt (bouton pour lancer la balle).
- Un détecteur de pyramide (zone pour vérifier si des briques restent debout).
À toi de jouer !
- Dans Roblox Studio, ajoute :
- Une Part (pour la hitbox) dans
Workspace. - Un Modèle de balle (
Partavec une forme de sphère) dansWorkspace. - Un Modèle de brique (
Partcubique) dansWorkspace. - Un ProximityPrompt (attache-le à la hitbox).
- Une Part (pour la hitbox) dans
- Teste : Déplace ton personnage dans la hitbox et imagine le gameplay.


QCM / Questions
Quels objets sont nécessaires pour construire la pyramide ?
- a) Une hitbox, une balle, un ProximityPrompt.
- b) Un modèle de brique, un détecteur de pyramide.
- c) Un script, une image, un son.
Documentation Roblox Lua :
Étape 2 : Créer la structure des objets dans l’Explorateur
But : Organiser les objets du jeu dans l’Explorateur.
Concepts clés : Hiérarchie des objets, organisation.
Explications
Dans Roblox, les objets sont organisés comme un arbre :
- Workspace : Contient tous les objets visibles dans le jeu (pyramide, hitbox, balle, etc.).
- ServerScriptService : Contient les scripts côté serveur (pour la logique du jeu).
- ReplicatedStorage : Contient les modèles réutilisables (comme la balle ou la brique).
- StarterPack : Contient des objets donnés au joueur au démarrage.
Structure recommandée :
Workspace
├── BreakPyramid (Folder)
│ ├── HitBox (Part)
│ │ └── Attachment (avec ProximityPrompt)
│ ├── Ball (Part)
│ ├── Part (Part, modèle de brique)
│ └── ControlPyramid (Part, détecteur de pyramide)
ServerScriptService
└── Script (pour la logique du jeu)
À toi de jouer !
- Crée un dossier
BreakPyramiddansWorkspace. - Ajoute les objets suivants dans
BreakPyramid:- Une Part nommée
HitBox. - Une Part nommée
Ball(forme de sphère). - Une Part nommée
Part(modèle de brique). - Une Part nommée
ControlPyramid(pour détecter les briques restantes).
- Une Part nommée
- Ajoute un Attachment à
HitBoxet un ProximityPrompt à l’Attachment.
Étape 3 : Construire dynamiquement une pyramide de briques
But : Créer une fonction qui génère une pyramide avec des briques de tailles aléatoires.
Concepts clés : Fonctions, boucles for, nombres aléatoires, clonage d’objets, CFrame.
Explications
Pour construire une pyramide dynamiquement (sans tout faire à la main), on utilise :
- Une boucle
forpour répéter la création de briques. math.random()pour générer des tailles aléatoires.partTemplate:Clone()pour créer des copies de la brique de base.CFramepour positionner et orienter les briques.
Exemple concret :
- La première brique est grande.
- Chaque brique suivante est plus petite (pour former une pyramide).
- Les briques sont empilées verticalement.

Code Lua
Crée un Script dans ServerScriptService et copie ce code :
-- ==================== SERVICES ====================
local Workspace = game:GetService("Workspace")
local ServerStorage = game:GetService("ServerStorage")
-- ==================== CONFIGURATION ====================
local PYRAMID_PARTS_COUNT = 8 -- Nombre de briques dans la pyramide
local PYRAMID_MIN_SIZE_STEP = 0.2 -- Réduction minimale de la taille à chaque brique
local PYRAMID_MAX_SIZE_STEP = 0.5 -- Réduction maximale de la taille à chaque brique
-- ==================== RÉFÉRENCES SCÈNE ====================
local breakPyramidFolder = Workspace:WaitForChild("BreakPyramid")
local pyramidPartTemplate = breakPyramidFolder:WaitForChild("Part")
local ballTemplate = breakPyramidFolder:WaitForChild("Ball")
-- on retire le modèle du workspace, il ne sert que de gabarit à cloner
ballTemplate.Parent = ServerStorage
-- ==================== FONCTION : CONSTRUIRE LA PYRAMIDE ====================
-- (Re)construit la pyramide de briques à partir du gabarit
local function rebuildPyramid(partTemplate)
local baseHeight = partTemplate.Position.Y + partTemplate.Size.Y / 2
local parentFolder = partTemplate.Parent
-- Supprime l'ancienne pyramide si elle existe
local existingFolder = parentFolder:FindFirstChild("PyramidParts")
if existingFolder then
existingFolder:Destroy()
end
-- Crée un dossier pour les briques de la pyramide
local folder = Instance.new("Folder")
folder.Name = "PyramidParts"
folder.Parent = parentFolder
-- Taille initiale de la brique (entre minSize et maxSize)
local minSize = partTemplate.Size.X / 2
local maxSize = partTemplate.Size.X
local currentHeight = baseHeight
-- 1) Construction : toutes les briques sont créées ANCRÉES et SANS collision
for i = 1, PYRAMID_PARTS_COUNT do
local part = partTemplate:Clone()
local partHeight = math.random(1, 3) -- Hauteur aléatoire entre 1 et 3
currentHeight = currentHeight + partHeight / 2
part.Name = "pyramid" -- Nom pour identifier les briques de la pyramide
part.Anchored = true -- Empêche la brique de bouger pendant la construction
part.CanCollide = false -- Désactive les collisions pendant la construction
part.CanTouch = false -- Désactive la détection de contact
part.Transparency = 0 -- Rend la brique visible
part.Size = Vector3.new(
math.random(minSize, maxSize), -- Largeur aléatoire
partHeight, -- Hauteur aléatoire
math.random(minSize, maxSize) -- Profondeur aléatoire
)
-- Positionne la brique au centre de la pyramide, avec une rotation aléatoire
part.CFrame = CFrame.new(
partTemplate.Position.X,
currentHeight,
partTemplate.Position.Z
) * CFrame.Angles(0, math.rad(math.random(0, 360)), 0) -- Rotation aléatoire autour de l'axe Y
-- Copie les propriétés visuelles du modèle
part.BrickColor = partTemplate.BrickColor
part.Material = partTemplate.Material
-- Ajoute la brique au dossier
part.Parent = folder
-- Réduit la taille pour les prochaines briques
minSize = minSize - PYRAMID_MIN_SIZE_STEP
maxSize = maxSize - PYRAMID_MAX_SIZE_STEP
currentHeight = currentHeight + partHeight / 2
end
-- 2) Activation : une fois la pyramide construite, on active la physique
task.wait(0.1) -- Petit délai pour s'assurer que tout est bien positionné
for _, part in ipairs(folder:GetChildren()) do
part.CanCollide = true -- Active les collisions
part.CanTouch = true -- Active la détection de contact
part.Anchored = false -- Permet à la brique de bouger (physique)
end
end
-- ==================== INITIALISATION ====================
rebuildPyramid(pyramidPartTemplate) -- Construit la pyramide au démarrage
Explications du code
| Ligne | Explication |
|---|---|
for i = 1, PYRAMID_PARTS_COUNT do | Boucle qui répète la création de briques 8 fois. |
math.random(1, 3) | Génère un nombre aléatoire entre 1 et 3 (hauteur de la brique). |
partTemplate:Clone() | Crée une copie du modèle de brique. |
part.Size = Vector3.new(...) | Définit la taille de la brique (largeur, hauteur, profondeur). |
CFrame.new(x, y, z) | Positionne la brique à un endroit précis. |
CFrame.Angles(...) | Applique une rotation aléatoire à la brique. |
part.Anchored = true | Empêche la brique de bouger pendant la construction. |
task.wait(0.1) | Attend 0.1 seconde pour que tout soit bien positionné. |
part.Anchored = false | Permet à la brique de bouger (physique activée). |
À toi de jouer !
- Copie le code dans un Script dans
ServerScriptService. - Teste :
- Lance le jeu : une pyramide de 8 briques doit apparaître.
- Observe les tailles et les rotations aléatoires.
- Modifie :
- Change
PYRAMID_PARTS_COUNTà5pour avoir une pyramide plus petite. - Change
PYRAMID_MIN_SIZE_STEPetPYRAMID_MAX_SIZE_STEPà0.3pour que les briques rétrécissent plus vite.
- Change
QCM / Questions
À quoi sert la boucle for i = 1, PYRAMID_PARTS_COUNT do ?
- a) À créer une seule brique.
- b) À répéter la création de briques
PYRAMID_PARTS_COUNTfois. - c) À détruire la pyramide.
Que fait partTemplate:Clone() ?
- a) Supprime le modèle de brique.
- b) Crée une copie du modèle de brique.
- c) Change la couleur de la brique.
Pourquoi utilise-t-on task.wait(0.1) avant d’activer la physique ?
- a) Pour attendre que toutes les briques soient bien positionnées.
- b) Pour ralentir le jeu.
- c) Pour afficher un message.
Pour aller plus loin
- Ajoute des couleurs aléatoires aux briques avec
part.BrickColor = BrickColor.new(math.random()). - Fais en sorte que les briques soient empilées en spirale en modifiant leur position.
Documentation Roblox Lua :
Étape 4 : Gérer une hitbox pour détecter l’arrivée du joueur
But : Détecter quand un joueur entre dans la zone de lancer.
Concepts clés : Événements, fonctions, détection de collision, ProximityPrompt.
Explications
Une hitbox est une zone invisible qui détecte quand un joueur entre ou sort.
En Lua, on utilise :
- L’événement
.Touchedpour savoir quand un objet touche la hitbox. - L’événement
.TouchEndedpour savoir quand un objet quitte la hitbox. ProximityPromptpour afficher un bouton quand le joueur est dans la zone.
Exemple concret :
- Quand le joueur entre dans la hitbox, on peut changer sa caméra ou activer un bouton.
Code Lua
Ajoute ce code au Script précédent :
-- ==================== SERVICES ====================
local Workspace = game:GetService("Workspace")
local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")
-- ==================== CONFIGURATION ====================
local PYRAMID_PARTS_COUNT = 8 -- Nombre de briques dans la pyramide
local PYRAMID_MIN_SIZE_STEP = 0.2 -- Réduction minimale de la taille à chaque brique
local PYRAMID_MAX_SIZE_STEP = 0.5 -- Réduction maximale de la taille à chaque brique
-- ==================== RÉFÉRENCES SCÈNE ====================
local breakPyramidFolder = Workspace:WaitForChild("BreakPyramid")
local pyramidPartTemplate = breakPyramidFolder:WaitForChild("Part")
local ballTemplate = breakPyramidFolder:WaitForChild("Ball")
local hitbox = breakPyramidFolder:WaitForChild("HitBox")
local prompt = hitbox.Attachment:WaitForChild("ProximityPrompt")
-- ==================== ÉTAT DU JEU ====================
-- playersData[player] = { inZone = bool, nbrPoints = number }
local playersData = {}
-- on retire le modèle du workspace, il ne sert que de gabarit à cloner
ballTemplate.Parent = ServerStorage
-- ==================== FONCTION : CONSTRUIRE LA PYRAMIDE ====================
-- (Re)construit la pyramide de briques à partir du gabarit
local function rebuildPyramid(partTemplate)
local baseHeight = partTemplate.Position.Y + partTemplate.Size.Y / 2
local parentFolder = partTemplate.Parent
-- Supprime l'ancienne pyramide si elle existe
local existingFolder = parentFolder:FindFirstChild("PyramidParts")
if existingFolder then
existingFolder:Destroy()
end
-- Crée un dossier pour les briques de la pyramide
local folder = Instance.new("Folder")
folder.Name = "PyramidParts"
folder.Parent = parentFolder
-- Taille initiale de la brique (entre minSize et maxSize)
local minSize = partTemplate.Size.X / 2
local maxSize = partTemplate.Size.X
local currentHeight = baseHeight
-- 1) Construction : toutes les briques sont créées ANCRÉES et SANS collision
for i = 1, PYRAMID_PARTS_COUNT do
local part = partTemplate:Clone()
local partHeight = math.random(1, 3) -- Hauteur aléatoire entre 1 et 3
currentHeight = currentHeight + partHeight / 2
part.Name = "pyramid" -- Nom pour identifier les briques de la pyramide
part.Anchored = true -- Empêche la brique de bouger pendant la construction
part.CanCollide = false -- Désactive les collisions pendant la construction
part.CanTouch = false -- Désactive la détection de contact
part.Transparency = 0 -- Rend la brique visible
part.Size = Vector3.new(
math.random(minSize, maxSize), -- Largeur aléatoire
partHeight, -- Hauteur aléatoire
math.random(minSize, maxSize) -- Profondeur aléatoire
)
-- Positionne la brique au centre de la pyramide, avec une rotation aléatoire
part.CFrame = CFrame.new(
partTemplate.Position.X,
currentHeight,
partTemplate.Position.Z
) * CFrame.Angles(0, math.rad(math.random(0, 360)), 0) -- Rotation aléatoire autour de l'axe Y
-- Copie les propriétés visuelles du modèle
part.BrickColor = partTemplate.BrickColor
part.Material = partTemplate.Material
-- Ajoute la brique au dossier
part.Parent = folder
-- Réduit la taille pour les prochaines briques
minSize = minSize - PYRAMID_MIN_SIZE_STEP
maxSize = maxSize - PYRAMID_MAX_SIZE_STEP
currentHeight = currentHeight + partHeight / 2
end
-- 2) Activation : une fois la pyramide construite, on active la physique
task.wait(0.1) -- Petit délai pour s'assurer que tout est bien positionné
for _, part in ipairs(folder:GetChildren()) do
part.CanCollide = true -- Active les collisions
part.CanTouch = true -- Active la détection de contact
part.Anchored = false -- Permet à la brique de bouger (physique)
end
end
-- ==================== UTILITAIRES ====================
-- Récupère le joueur à partir d'une partie touchée
local function getPlayerFromTouchedPart(hit)
local character = hit.Parent
if not character then return nil end
local humanoid = character:FindFirstChildOfClass("Humanoid")
if not humanoid then return nil end
return Players:GetPlayerFromCharacter(character)
end
-- ==================== ÉVÉNEMENTS : ZONE DE JEU ====================
-- Quand un joueur touche la hitbox
hitbox.Touched:Connect(function(hit)
local player = getPlayerFromTouchedPart(hit)
if not player then return end
-- Anti-spam : ignore si le joueur est déjà dans la zone
if playersData[player] and playersData[player].inZone then return end
playersData[player] = { inZone = true, nbrPoints = 5 } -- 5 points de départ
print(player.Name .. " est entré dans la zone de lancer !")
end)
-- Quand un joueur quitte la hitbox
hitbox.TouchEnded:Connect(function(hit)
local player = getPlayerFromTouchedPart(hit)
if not player then return end
if playersData[player] and playersData[player].inZone==false then return end
-- Attend 0.5 seconde pour éviter les faux positifs (si le joueur touche encore la hitbox avec une autre partie du corps)
task.wait(0.5)
-- Vérifie qu'aucune partie du personnage ne touche encore la hitbox
local character = player.Character
local stillTouching = false
if character then
for _, part in pairs(hitbox:GetTouchingParts()) do
if part.Parent == character then
stillTouching = true
break
end
end
end
if stillTouching then return end
if playersData[player] and playersData[player].inZone==false then return end
-- Le joueur a vraiment quitté la zone
playersData[player].inZone = false
print(player.Name .. " a quitté la zone de lancer.")
end)
-- ==================== INITIALISATION ====================
rebuildPyramid(pyramidPartTemplate) -- Construit la pyramide au démarrage
Explications du code
| Ligne | Explication |
|---|---|
hitbox.Touched:Connect(...) | Écoute l’événement Touched sur la hitbox. |
getPlayerFromTouchedPart(hit) | Vérifie si l’objet qui a touché est un personnage de joueur. |
playersData[player] | Stocke des informations sur le joueur (ex: s’il est dans la zone, son nombre de points). |
hitbox.TouchEnded:Connect(...) | Écoute l’événement TouchEnded pour détecter quand le joueur quitte la hitbox. |
hitbox:GetTouchingParts() | Récupère toutes les parties qui touchent la hitbox. |
task.wait(0.5) | Attend 0.5 seconde pour éviter les faux positifs (ex: si le joueur bouge rapidement). |
À toi de jouer !
- Copie le code dans le Script existant.
- Teste :
- Entre dans la hitbox avec ton personnage.
- Ouvre la fenêtre de sortie (
Affichage > Sortie) pour voir les messages.
- Modifie :
- Change le nombre de points de départ (
nbrPoints = 10). - Ajoute un
printpour afficher le nombre de points du joueur quand il entre dans la zone.
- Change le nombre de points de départ (
QCM / Questions
À quoi sert hitbox.Touched:Connect(...) ?
- a) À détruire la hitbox.
- b) À exécuter du code quand un objet touche la hitbox.
- c) À changer la couleur de la hitbox.
Pourquoi utilise-t-on task.wait(0.5) dans TouchEnded ?
- a) Pour attendre que le joueur ait vraiment quitté la zone.
- b) Pour ralentir le jeu.
- c) Pour afficher un message.
Que fait playersData[player] = { inZone = true, nbrPoints = 5 } ?
- a) Supprime les données du joueur.
- b) Stocke des informations sur le joueur (s’il est dans la zone et son nombre de points).
- c) Change le nom du joueur.
Pour aller plus loin
- Affiche un message à l’écran quand le joueur entre dans la zone (utilise un
ScreenGuiet unTextLabel). - Joue un son quand le joueur entre dans la zone.
Documentation Roblox Lua :
Étape 5 : Changer la vision du joueur en première personne
But : Passer en vue première personne quand le joueur entre dans la zone de lancer.
Concepts clés : Propriétés des objets, fonctions utilitaires, CameraMode.
Explications
En Roblox, on peut modifier la caméra du joueur pour :
- LockFirstPerson : Vue à la première personne (comme dans un FPS).
- Classic : Vue classique (derrière le personnage).
Exemple concret :
- Quand le joueur entre dans la zone, on passe en première personne pour mieux viser.
- Quand il quitte la zone, on revient en vue classique.
Code Lua
Ajoute ces fonctions au Script :
-- ==================== UTILITAIRES ====================
-- Applique une caméra first person (vue première personne verrouillée et zoomée)
local function lockFirstPersonCamera(player)
player.CameraMode = Enum.CameraMode.LockFirstPerson
player.CameraMinZoomDistance = 0.5
player.CameraMaxZoomDistance = 0.5
end
-- Restaure la caméra classique du joueur
local function resetCamera(player)
player.CameraMode = Enum.CameraMode.Classic
player.CameraMaxZoomDistance = 400
task.wait(0.1) -- Attend 0.1 seconde pour que la caméra se réinitialise correctement
player.CameraMinZoomDistance = 10
end
Puis modifie les événements Touched et TouchEnded :
-- ==================== SERVICES ====================
local Workspace = game:GetService("Workspace")
local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")
-- ==================== CONFIGURATION ====================
local PYRAMID_PARTS_COUNT = 8 -- Nombre de briques dans la pyramide
local PYRAMID_MIN_SIZE_STEP = 0.2 -- Réduction minimale de la taille à chaque brique
local PYRAMID_MAX_SIZE_STEP = 0.5 -- Réduction maximale de la taille à chaque brique
-- ==================== RÉFÉRENCES SCÈNE ====================
local breakPyramidFolder = Workspace:WaitForChild("BreakPyramid")
local pyramidPartTemplate = breakPyramidFolder:WaitForChild("Part")
local ballTemplate = breakPyramidFolder:WaitForChild("Ball")
local hitbox = breakPyramidFolder:WaitForChild("HitBox")
local prompt = hitbox.Attachment:WaitForChild("ProximityPrompt")
-- ==================== ÉTAT DU JEU ====================
-- playersData[player] = { inZone = bool, nbrPoints = number }
local playersData = {}
-- on retire le modèle du workspace, il ne sert que de gabarit à cloner
ballTemplate.Parent = ServerStorage
-- ==================== FONCTION : CONSTRUIRE LA PYRAMIDE ====================
-- (Re)construit la pyramide de briques à partir du gabarit
local function rebuildPyramid(partTemplate)
local baseHeight = partTemplate.Position.Y + partTemplate.Size.Y / 2
local parentFolder = partTemplate.Parent
-- Supprime l'ancienne pyramide si elle existe
local existingFolder = parentFolder:FindFirstChild("PyramidParts")
if existingFolder then
existingFolder:Destroy()
end
-- Crée un dossier pour les briques de la pyramide
local folder = Instance.new("Folder")
folder.Name = "PyramidParts"
folder.Parent = parentFolder
-- Taille initiale de la brique (entre minSize et maxSize)
local minSize = partTemplate.Size.X / 2
local maxSize = partTemplate.Size.X
local currentHeight = baseHeight
-- 1) Construction : toutes les briques sont créées ANCRÉES et SANS collision
for i = 1, PYRAMID_PARTS_COUNT do
local part = partTemplate:Clone()
local partHeight = math.random(1, 3) -- Hauteur aléatoire entre 1 et 3
currentHeight = currentHeight + partHeight / 2
part.Name = "pyramid" -- Nom pour identifier les briques de la pyramide
part.Anchored = true -- Empêche la brique de bouger pendant la construction
part.CanCollide = false -- Désactive les collisions pendant la construction
part.CanTouch = false -- Désactive la détection de contact
part.Transparency = 0 -- Rend la brique visible
part.Size = Vector3.new(
math.random(minSize, maxSize), -- Largeur aléatoire
partHeight, -- Hauteur aléatoire
math.random(minSize, maxSize) -- Profondeur aléatoire
)
-- Positionne la brique au centre de la pyramide, avec une rotation aléatoire
part.CFrame = CFrame.new(
partTemplate.Position.X,
currentHeight,
partTemplate.Position.Z
) * CFrame.Angles(0, math.rad(math.random(0, 360)), 0) -- Rotation aléatoire autour de l'axe Y
-- Copie les propriétés visuelles du modèle
part.BrickColor = partTemplate.BrickColor
part.Material = partTemplate.Material
-- Ajoute la brique au dossier
part.Parent = folder
-- Réduit la taille pour les prochaines briques
minSize = minSize - PYRAMID_MIN_SIZE_STEP
maxSize = maxSize - PYRAMID_MAX_SIZE_STEP
currentHeight = currentHeight + partHeight / 2
end
-- 2) Activation : une fois la pyramide construite, on active la physique
task.wait(0.1) -- Petit délai pour s'assurer que tout est bien positionné
for _, part in ipairs(folder:GetChildren()) do
part.CanCollide = true -- Active les collisions
part.CanTouch = true -- Active la détection de contact
part.Anchored = false -- Permet à la brique de bouger (physique)
end
end
-- ==================== UTILITAIRES ====================
-- Applique une caméra first person (vue première personne verrouillée et zoomée)
local function lockFirstPersonCamera(player)
player.CameraMode = Enum.CameraMode.LockFirstPerson
player.CameraMinZoomDistance = 0.5
player.CameraMaxZoomDistance = 0.5
end
-- Restaure la caméra classique du joueur
local function resetCamera(player)
player.CameraMode = Enum.CameraMode.Classic
player.CameraMaxZoomDistance = 400
task.wait(0.1) -- Attend 0.1 seconde pour que la caméra se réinitialise correctement
player.CameraMinZoomDistance = 10
end
-- Récupère le joueur à partir d'une partie touchée
local function getPlayerFromTouchedPart(hit)
local character = hit.Parent
if not character then return nil end
local humanoid = character:FindFirstChildOfClass("Humanoid")
if not humanoid then return nil end
return Players:GetPlayerFromCharacter(character)
end
-- ==================== ÉVÉNEMENTS : ZONE DE JEU ====================
-- Quand un joueur touche la hitbox
hitbox.Touched:Connect(function(hit)
local player = getPlayerFromTouchedPart(hit)
if not player then return end
-- Anti-spam : ignore si le joueur est déjà dans la zone
if playersData[player] and playersData[player].inZone then return end
playersData[player] = { inZone = true, nbrPoints = 5 } -- 5 points de départ
print(player.Name .. " est entré dans la zone de lancer !")
lockFirstPersonCamera(player)
end)
-- Quand un joueur quitte la hitbox
hitbox.TouchEnded:Connect(function(hit)
local player = getPlayerFromTouchedPart(hit)
if not player then return end
if playersData[player] and playersData[player].inZone==false then return end
-- Attend 0.5 seconde pour éviter les faux positifs (si le joueur touche encore la hitbox avec une autre partie du corps)
task.wait(0.5)
-- Vérifie qu'aucune partie du personnage ne touche encore la hitbox
local character = player.Character
local stillTouching = false
if character then
for _, part in pairs(hitbox:GetTouchingParts()) do
if part.Parent == character then
stillTouching = true
break
end
end
end
if stillTouching then return end
if playersData[player] and playersData[player].inZone==false then return end
-- Le joueur a vraiment quitté la zone
playersData[player].inZone = false
print(player.Name .. " a quitté la zone de lancer.")
resetCamera(player)
end)
-- ==================== INITIALISATION ====================
rebuildPyramid(pyramidPartTemplate) -- Construit la pyramide au démarrage
Explications du code
| Ligne | Explication |
|---|---|
player.CameraMode = Enum.CameraMode.LockFirstPerson | Force la vue à la première personne. |
player.CameraMinZoomDistance = 0.5 | Définit la distance minimale de zoom. |
player.CameraMaxZoomDistance = 0.5 | Définit la distance maximale de zoom. |
task.wait(0.1) | Attend 0.1 seconde pour éviter les bugs de caméra. |
resetCamera(player) | Réinitialise la caméra en vue classique. |
À toi de jouer !
- Copie le code dans le Script.
- Teste :
- Entre dans la hitbox : la vue doit passer en première personne.
- Quitte la hitbox : la vue doit revenir en classique.
- Modifie :
- Change
CameraMinZoomDistanceà1.0et observe la différence. - Essaie de désactiver
LockFirstPersonet utiliseEnum.CameraMode.FirstPersonpour voir la différence.
- Change
QCM / Questions
Que fait player.CameraMode = Enum.CameraMode.LockFirstPerson ?
- a) Passe en vue à la troisième personne.
- b) Passe en vue à la première personne (verrouillée).
- c) Désactive la caméra.
Pourquoi utilise-t-on task.wait(0.1) dans resetCamera ?
- a) Pour attendre que la caméra se réinitialise correctement.
- b) Pour ralentir le jeu.
- c) Pour afficher un message.
Documentation Roblox Lua :
Étape 6 : Proposer le lancement d’une balle avec un ProximityPrompt
But : Permettre au joueur de lancer une balle en appuyant sur un bouton.
Concepts clés : ProximityPrompt, clonage d’objets, physique, RemoteEvent (optionnel).
Explications
Un ProximityPrompt est un bouton qui apparaît quand le joueur est proche d’un objet.
Quand le joueur appuie sur le bouton (par défaut, la touche E), on peut :
- Cloner la balle depuis
ReplicatedStorage. - Positionner la balle devant le joueur.
- Appliquer une force pour la lancer.
Exemple concret :
- Le joueur voit un bouton « Lancer la balle » quand il est dans la hitbox.
- En appuyant sur E, une balle est lancée devant lui.
Code Lua
Ajoute ce code au Script :
-- ==================== UTILITAIRES ====================
-- Fait apparaître une balle devant le joueur et lui applique une impulsion
local function fireBall(player)
local character = player.Character or player.CharacterAdded:Wait()
local hrp = character:WaitForChild("HumanoidRootPart")
local ball = ballTemplate:Clone()
ball.Parent = workspace
ball.CFrame = hrp.CFrame * CFrame.new(-2, 2, 0) -- Position devant le joueur
-- Applique une vitesse initiale vers l'avant + vers le haut
ball.AssemblyLinearVelocity = hrp.CFrame.LookVector * 60 + Vector3.new(0, 60, 0)
-- Détruit la balle après 2 secondes
game:GetService("Debris"):AddItem(ball, 2)
end
-- ==================== ÉVÉNEMENT : PROXIMITY PROMPT ====================
prompt.Triggered:Connect(function(player)
local data = playersData[player]
if not data or not data.inZone then return end -- Vérifie que le joueur est bien dans la zone
fireBall(player)
print(player.Name .. " a lancé une balle !")
end)
Exemple du code modifié :
-- ==================== SERVICES ====================
local Workspace = game:GetService("Workspace")
local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")
-- ==================== CONFIGURATION ====================
local PYRAMID_PARTS_COUNT = 8 -- Nombre de briques dans la pyramide
local PYRAMID_MIN_SIZE_STEP = 0.2 -- Réduction minimale de la taille à chaque brique
local PYRAMID_MAX_SIZE_STEP = 0.5 -- Réduction maximale de la taille à chaque brique
-- ==================== RÉFÉRENCES SCÈNE ====================
local breakPyramidFolder = Workspace:WaitForChild("BreakPyramid")
local pyramidPartTemplate = breakPyramidFolder:WaitForChild("Part")
local ballTemplate = breakPyramidFolder:WaitForChild("Ball")
local hitbox = breakPyramidFolder:WaitForChild("HitBox")
local prompt = hitbox.Attachment:WaitForChild("ProximityPrompt")
-- ==================== ÉTAT DU JEU ====================
-- playersData[player] = { inZone = bool, nbrPoints = number }
local playersData = {}
-- on retire le modèle du workspace, il ne sert que de gabarit à cloner
ballTemplate.Parent = ServerStorage
-- ==================== FONCTION : CONSTRUIRE LA PYRAMIDE ====================
-- (Re)construit la pyramide de briques à partir du gabarit
local function rebuildPyramid(partTemplate)
local baseHeight = partTemplate.Position.Y + partTemplate.Size.Y / 2
local parentFolder = partTemplate.Parent
-- Supprime l'ancienne pyramide si elle existe
local existingFolder = parentFolder:FindFirstChild("PyramidParts")
if existingFolder then
existingFolder:Destroy()
end
-- Crée un dossier pour les briques de la pyramide
local folder = Instance.new("Folder")
folder.Name = "PyramidParts"
folder.Parent = parentFolder
-- Taille initiale de la brique (entre minSize et maxSize)
local minSize = partTemplate.Size.X / 2
local maxSize = partTemplate.Size.X
local currentHeight = baseHeight
-- 1) Construction : toutes les briques sont créées ANCRÉES et SANS collision
for i = 1, PYRAMID_PARTS_COUNT do
local part = partTemplate:Clone()
local partHeight = math.random(1, 3) -- Hauteur aléatoire entre 1 et 3
currentHeight = currentHeight + partHeight / 2
part.Name = "pyramid" -- Nom pour identifier les briques de la pyramide
part.Anchored = true -- Empêche la brique de bouger pendant la construction
part.CanCollide = false -- Désactive les collisions pendant la construction
part.CanTouch = false -- Désactive la détection de contact
part.Transparency = 0 -- Rend la brique visible
part.Size = Vector3.new(
math.random(minSize, maxSize), -- Largeur aléatoire
partHeight, -- Hauteur aléatoire
math.random(minSize, maxSize) -- Profondeur aléatoire
)
-- Positionne la brique au centre de la pyramide, avec une rotation aléatoire
part.CFrame = CFrame.new(
partTemplate.Position.X,
currentHeight,
partTemplate.Position.Z
) * CFrame.Angles(0, math.rad(math.random(0, 360)), 0) -- Rotation aléatoire autour de l'axe Y
-- Copie les propriétés visuelles du modèle
part.BrickColor = partTemplate.BrickColor
part.Material = partTemplate.Material
-- Ajoute la brique au dossier
part.Parent = folder
-- Réduit la taille pour les prochaines briques
minSize = minSize - PYRAMID_MIN_SIZE_STEP
maxSize = maxSize - PYRAMID_MAX_SIZE_STEP
currentHeight = currentHeight + partHeight / 2
end
-- 2) Activation : une fois la pyramide construite, on active la physique
task.wait(0.1) -- Petit délai pour s'assurer que tout est bien positionné
for _, part in ipairs(folder:GetChildren()) do
part.CanCollide = true -- Active les collisions
part.CanTouch = true -- Active la détection de contact
part.Anchored = false -- Permet à la brique de bouger (physique)
end
end
-- ==================== UTILITAIRES ====================
-- Fait apparaître une balle devant le joueur et lui applique une impulsion
local function fireBall(player)
local character = player.Character or player.CharacterAdded:Wait()
local hrp = character:WaitForChild("HumanoidRootPart")
local ball = ballTemplate:Clone()
ball.Parent = workspace
ball.CFrame = hrp.CFrame * CFrame.new(-2, 2, 0) -- Position devant le joueur
-- Applique une vitesse initiale vers l'avant + vers le haut
ball.AssemblyLinearVelocity = hrp.CFrame.LookVector * 60 + Vector3.new(0, 60, 0)
-- Détruit la balle après 2 secondes
game:GetService("Debris"):AddItem(ball, 2)
end
-- Applique une caméra first person (vue première personne verrouillée et zoomée)
local function lockFirstPersonCamera(player)
player.CameraMode = Enum.CameraMode.LockFirstPerson
player.CameraMinZoomDistance = 0.5
player.CameraMaxZoomDistance = 0.5
end
-- Restaure la caméra classique du joueur
local function resetCamera(player)
player.CameraMode = Enum.CameraMode.Classic
player.CameraMaxZoomDistance = 400
task.wait(0.1) -- Attend 0.1 seconde pour que la caméra se réinitialise correctement
player.CameraMinZoomDistance = 10
end
-- Récupère le joueur à partir d'une partie touchée
local function getPlayerFromTouchedPart(hit)
local character = hit.Parent
if not character then return nil end
local humanoid = character:FindFirstChildOfClass("Humanoid")
if not humanoid then return nil end
return Players:GetPlayerFromCharacter(character)
end
-- ==================== ÉVÉNEMENTS : ZONE DE JEU ====================
-- Quand un joueur touche la hitbox
hitbox.Touched:Connect(function(hit)
local player = getPlayerFromTouchedPart(hit)
if not player then return end
-- Anti-spam : ignore si le joueur est déjà dans la zone
if playersData[player] and playersData[player].inZone then return end
playersData[player] = { inZone = true, nbrPoints = 5 } -- 5 points de départ
print(player.Name .. " est entré dans la zone de lancer !")
lockFirstPersonCamera(player)
prompt.Enabled = true
end)
-- Quand un joueur quitte la hitbox
hitbox.TouchEnded:Connect(function(hit)
local player = getPlayerFromTouchedPart(hit)
if not player then return end
if playersData[player] and playersData[player].inZone==false then return end
-- Attend 0.5 seconde pour éviter les faux positifs (si le joueur touche encore la hitbox avec une autre partie du corps)
task.wait(0.5)
-- Vérifie qu'aucune partie du personnage ne touche encore la hitbox
local character = player.Character
local stillTouching = false
if character then
for _, part in pairs(hitbox:GetTouchingParts()) do
if part.Parent == character then
stillTouching = true
break
end
end
end
if stillTouching then return end
if playersData[player] and playersData[player].inZone==false then return end
-- Le joueur a vraiment quitté la zone
playersData[player].inZone = false
print(player.Name .. " a quitté la zone de lancer.")
resetCamera(player)
prompt.Enabled = false
end)
-- ==================== ÉVÉNEMENT : PROXIMITY PROMPT ====================
prompt.Triggered:Connect(function(player)
local data = playersData[player]
if not data or not data.inZone then return end -- Vérifie que le joueur est bien dans la zone
fireBall(player)
print(player.Name .. " a lancé une balle !")
end)
-- ==================== INITIALISATION ====================
rebuildPyramid(pyramidPartTemplate) -- Construit la pyramide au démarrage
prompt.Enabled = false -- Masque le prompt au démarrage
Explications du code
| Ligne | Explication |
|---|---|
ballTemplate.Parent = ServerStorage | Déplace le modèle de balle dans ServerStorage pour le cloner plus tard. |
prompt.Triggered:Connect(...) | Écoute l’événement quand le joueur appuie sur le bouton. |
ballTemplate:Clone() | Crée une copie de la balle. |
ball.CFrame = hrp.CFrame * CFrame.new(-2, 2, 0) | Positionne la balle devant le joueur (2 unités devant, 2 unités au-dessus). |
ball.AssemblyLinearVelocity = ... | Applique une vitesse à la balle (60 unités vers l’avant + 60 unités vers le haut). |
Debris:AddItem(ball, 2) | Détruit la balle après 2 secondes. |
À toi de jouer !
- Déplace le modèle de balle dans
ServerStorage(si ce n’est pas déjà fait).- local ServerStorage = game:GetService(« ServerStorage »)
- local ballTemplate = breakPyramidFolder:WaitForChild(« Ball »)r
- ballTemplate.Parent = ServerStorage
- Copie le code dans le Script.
- Teste :
- Entre dans la hitbox.
- Appuie sur E (ou la touche définie pour le ProximityPrompt) : une balle doit être lancée !
- Modifie :
- Change la position de la balle (
CFrame.new(-2, 2, 0)enCFrame.new(-3, 1, 0)). - Change la vitesse de la balle (
60en80pour un lancer plus fort).
- Change la position de la balle (
QCM / Questions
À quoi sert prompt.Triggered:Connect(...) ?
- a) À détecter quand le joueur appuie sur le bouton du ProximityPrompt.
- b) À détruire le ProximityPrompt.
- c) À changer la couleur du bouton.
Que fait ball.AssemblyLinearVelocity = hrp.CFrame.LookVector * 60 + Vector3.new(0, 60, 0) ?
- a) Change la taille de la balle.
- b) Détruit la balle.
- c) Applique une vitesse à la balle vers l’avant et vers le haut.
Pour aller plus loin
- Ajoute un son quand la balle est lancée.
Documentation Roblox Lua :
Étape 7 : Détecter que la pyramide est détruite
But : Vérifier si toutes les briques de la pyramide ont été détruites.
Concepts clés : Détection de collision, boucles for, conditions if, compteur.
Explications
Pour vérifier si la pyramide est détruite, on peut :
- Compter le nombre de briques encore debout dans la zone de détection (
ControlPyramid). - Comparer ce nombre à 0 : si aucune brique ne reste, la pyramide est détruite.
Exemple concret :
- Après chaque lancer, on vérifie si des briques touchent encore
ControlPyramid. - Si aucune brique ne touche
ControlPyramid, le joueur a réussi !
Code Lua
Ajoute ces fonctions au Script :
-- ==================== UTILITAIRES ====================
-- Compte le nombre de briques de la pyramide encore présentes dans la zone de détection
local function countStandingPyramidParts()
local touchingParts = workspace:GetPartsInPart(pyramidDetector)
local total = 0
for _, part in ipairs(touchingParts) do
if part.Name == "pyramid" then
total += 1
end
end
return total
end
-- Applique un recul physique au joueur (utilisé après un strike réussi)
local function knockbackPlayer(player, force)
local character = player.Character
if not character then return end
local hrp = character:FindFirstChild("HumanoidRootPart")
if not hrp then return end
hrp.AssemblyLinearVelocity = hrp.CFrame.LookVector * -force
end
-- Fait sortir proprement un joueur de la zone : reset caméra + pyramide + état
local function exitZone(player)
local data = playersData[player]
if not data or not data.inZone then return end
data.inZone = false
prompt.Enabled = true -- Réactive le ProximityPrompt
resetCamera(player)
rebuildPyramid(pyramidPartTemplate) -- Reconstruit la pyramide
end
Exemple du code modifié :
-- ==================== SERVICES ====================
local Workspace = game:GetService("Workspace")
local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")
-- ==================== CONFIGURATION ====================
local PYRAMID_PARTS_COUNT = 8 -- Nombre de briques dans la pyramide
local PYRAMID_MIN_SIZE_STEP = 0.2 -- Réduction minimale de la taille à chaque brique
local PYRAMID_MAX_SIZE_STEP = 0.5 -- Réduction maximale de la taille à chaque brique
-- ==================== RÉFÉRENCES SCÈNE ====================
local breakPyramidFolder = Workspace:WaitForChild("BreakPyramid")
local pyramidPartTemplate = breakPyramidFolder:WaitForChild("Part")
local ballTemplate = breakPyramidFolder:WaitForChild("Ball")
local hitbox = breakPyramidFolder:WaitForChild("HitBox")
local prompt = hitbox.Attachment:WaitForChild("ProximityPrompt")
local pyramidDetector = breakPyramidFolder:WaitForChild("ControlPyramid") -- zone qui détecte les briques encore debout
-- ==================== ÉTAT DU JEU ====================
-- playersData[player] = { inZone = bool, nbrPoints = number }
local playersData = {}
-- on retire le modèle du workspace, il ne sert que de gabarit à cloner
ballTemplate.Parent = ServerStorage
-- ==================== FONCTION : CONSTRUIRE LA PYRAMIDE ====================
-- (Re)construit la pyramide de briques à partir du gabarit
local function rebuildPyramid(partTemplate)
local baseHeight = partTemplate.Position.Y + partTemplate.Size.Y / 2
local parentFolder = partTemplate.Parent
-- Supprime l'ancienne pyramide si elle existe
local existingFolder = parentFolder:FindFirstChild("PyramidParts")
if existingFolder then
existingFolder:Destroy()
end
-- Crée un dossier pour les briques de la pyramide
local folder = Instance.new("Folder")
folder.Name = "PyramidParts"
folder.Parent = parentFolder
-- Taille initiale de la brique (entre minSize et maxSize)
local minSize = partTemplate.Size.X / 2
local maxSize = partTemplate.Size.X
local currentHeight = baseHeight
-- 1) Construction : toutes les briques sont créées ANCRÉES et SANS collision
for i = 1, PYRAMID_PARTS_COUNT do
local part = partTemplate:Clone()
local partHeight = math.random(1, 3) -- Hauteur aléatoire entre 1 et 3
currentHeight = currentHeight + partHeight / 2
part.Name = "pyramid" -- Nom pour identifier les briques de la pyramide
part.Anchored = true -- Empêche la brique de bouger pendant la construction
part.CanCollide = false -- Désactive les collisions pendant la construction
part.CanTouch = false -- Désactive la détection de contact
part.Transparency = 0 -- Rend la brique visible
part.Size = Vector3.new(
math.random(minSize, maxSize), -- Largeur aléatoire
partHeight, -- Hauteur aléatoire
math.random(minSize, maxSize) -- Profondeur aléatoire
)
-- Positionne la brique au centre de la pyramide, avec une rotation aléatoire
part.CFrame = CFrame.new(
partTemplate.Position.X,
currentHeight,
partTemplate.Position.Z
) * CFrame.Angles(0, math.rad(math.random(0, 360)), 0) -- Rotation aléatoire autour de l'axe Y
-- Copie les propriétés visuelles du modèle
part.BrickColor = partTemplate.BrickColor
part.Material = partTemplate.Material
-- Ajoute la brique au dossier
part.Parent = folder
-- Réduit la taille pour les prochaines briques
minSize = minSize - PYRAMID_MIN_SIZE_STEP
maxSize = maxSize - PYRAMID_MAX_SIZE_STEP
currentHeight = currentHeight + partHeight / 2
end
-- 2) Activation : une fois la pyramide construite, on active la physique
task.wait(0.1) -- Petit délai pour s'assurer que tout est bien positionné
for _, part in ipairs(folder:GetChildren()) do
part.CanCollide = true -- Active les collisions
part.CanTouch = true -- Active la détection de contact
part.Anchored = false -- Permet à la brique de bouger (physique)
end
end
-- ==================== UTILITAIRES ====================
-- Fait apparaître une balle devant le joueur et lui applique une impulsion
local function fireBall(player)
local character = player.Character or player.CharacterAdded:Wait()
local hrp = character:WaitForChild("HumanoidRootPart")
local ball = ballTemplate:Clone()
ball.Parent = workspace
ball.CFrame = hrp.CFrame * CFrame.new(-2, 2, 0) -- Position devant le joueur
-- Applique une vitesse initiale vers l'avant + vers le haut
ball.AssemblyLinearVelocity = hrp.CFrame.LookVector * 60 + Vector3.new(0, 60, 0)
-- Détruit la balle après 2 secondes
game:GetService("Debris"):AddItem(ball, 2)
end
-- Applique une caméra first person (vue première personne verrouillée et zoomée)
local function lockFirstPersonCamera(player)
player.CameraMode = Enum.CameraMode.LockFirstPerson
player.CameraMinZoomDistance = 0.5
player.CameraMaxZoomDistance = 0.5
end
-- Restaure la caméra classique du joueur
local function resetCamera(player)
player.CameraMode = Enum.CameraMode.Classic
player.CameraMaxZoomDistance = 400
task.wait(0.1) -- Attend 0.1 seconde pour que la caméra se réinitialise correctement
player.CameraMinZoomDistance = 10
end
-- Récupère le joueur à partir d'une partie touchée
local function getPlayerFromTouchedPart(hit)
local character = hit.Parent
if not character then return nil end
local humanoid = character:FindFirstChildOfClass("Humanoid")
if not humanoid then return nil end
return Players:GetPlayerFromCharacter(character)
end
-- Compte le nombre de briques de la pyramide encore présentes dans la zone de détection
local function countStandingPyramidParts()
local touchingParts = workspace:GetPartsInPart(pyramidDetector)
local total = 0
for _, part in ipairs(touchingParts) do
if part.Name == "pyramid" then
total += 1
end
end
return total
end
-- Applique un recul physique au joueur (utilisé après un strike réussi)
local function knockbackPlayer(player, force)
local character = player.Character
if not character then return end
local hrp = character:FindFirstChild("HumanoidRootPart")
if not hrp then return end
hrp.AssemblyLinearVelocity = hrp.CFrame.LookVector * -force
end
-- Fait sortir proprement un joueur de la zone : reset caméra + pyramide + état
local function exitZone(player)
local data = playersData[player]
if not data or not data.inZone then return end
data.inZone = false
prompt.Enabled = true -- Réactive le ProximityPrompt
resetCamera(player)
end
-- ==================== ÉVÉNEMENTS : ZONE DE JEU ====================
-- Quand un joueur touche la hitbox
hitbox.Touched:Connect(function(hit)
local player = getPlayerFromTouchedPart(hit)
if not player then return end
-- Anti-spam : ignore si le joueur est déjà dans la zone
if playersData[player] and playersData[player].inZone then return end
playersData[player] = { inZone = true, nbrPoints = 5 } -- 5 points de départ
print(player.Name .. " est entré dans la zone de lancer !")
lockFirstPersonCamera(player)
prompt.Enabled = true
end)
-- Quand un joueur quitte la hitbox
hitbox.TouchEnded:Connect(function(hit)
local player = getPlayerFromTouchedPart(hit)
if not player then return end
if playersData[player] and playersData[player].inZone==false then return end
-- Attend 0.5 seconde pour éviter les faux positifs (si le joueur touche encore la hitbox avec une autre partie du corps)
task.wait(0.5)
-- Vérifie qu'aucune partie du personnage ne touche encore la hitbox
local character = player.Character
local stillTouching = false
if character then
for _, part in pairs(hitbox:GetTouchingParts()) do
if part.Parent == character then
stillTouching = true
break
end
end
end
if stillTouching then return end
if playersData[player] and playersData[player].inZone==false then return end
-- Le joueur a vraiment quitté la zone
playersData[player].inZone = false
print(player.Name .. " a quitté la zone de lancer.")
resetCamera(player)
prompt.Enabled = false
end)
-- ==================== ÉVÉNEMENT : PROXIMITY PROMPT ====================
prompt.Triggered:Connect(function(player)
local data = playersData[player]
if not data or not data.inZone then return end -- Vérifie que le joueur est bien dans la zone
fireBall(player)
-- Attend 2 secondes pour laisser le temps à la balle de toucher les briques
prompt.Enabled = false
task.wait(1)
prompt.Enabled = true
if countStandingPyramidParts() > 0 then
-- Raté : il reste des briques debout
if data.nbrPoints > 0 then
data.nbrPoints -= 1
print(player.Name .. " a raté ! Il lui reste " .. data.nbrPoints .. " points.")
end
prompt.Enabled = true -- Réactive le bouton
else
-- Strike : plus aucune brique debout
print(player.Name .. " a détruit la pyramide !")
knockbackPlayer(player, 150) -- Applique un recul au joueur
exitZone(player) -- Fait sortir le joueur de la zone
task.wait(2)
rebuildPyramid(pyramidPartTemplate) -- Reconstruit la pyramide
end
end)
-- ==================== INITIALISATION ====================
rebuildPyramid(pyramidPartTemplate) -- Construit la pyramide au démarrage
prompt.Enabled = false -- Masque le prompt au démarrage
Explications du code
| Ligne | Explication |
|---|---|
workspace:GetPartsInPart(pyramidDetector) | Récupère toutes les parties qui touchent ControlPyramid. |
for _, part in ipairs(touchingParts) do | Parcourt toutes les parties en contact avec ControlPyramid. |
if part.Name == "pyramid" then | Vérifie si la partie est une brique de la pyramide. |
countStandingPyramidParts() | Compte le nombre de briques encore debout. |
knockbackPlayer(player, 150) | Applique un recul au joueur (force de 150). |
exitZone(player) | Fait sortir le joueur de la zone et reconstruit la pyramide. |
À toi de jouer !
- Copie le code dans le Script.
- Teste :
- Entre dans la hitbox et lance des balles jusqu’à détruire la pyramide.
- Observe le recul du joueur quand il réussit.
- Modifie :
- Change la force du recul (
150en200). - Change le nombre de points perdus en cas d’échec (
data.nbrPoints -= 2).
- Change la force du recul (
QCM / Questions
À quoi sert workspace:GetPartsInPart(pyramidDetector) ?
- a) À détruire
ControlPyramid. - b) À récupérer toutes les parties qui touchent
ControlPyramid. - c) À changer la couleur de
ControlPyramid.
Que fait knockbackPlayer(player, 150) ?
- a) Applique un recul au joueur avec une force de 150.
- b) Détruit le joueur.
- c) Affiche un message.
Pourquoi utilise-t-on task.wait(2) après fireBall(player) ?
- a) Pour attendre que la balle ait le temps de toucher les briques.
- b) Pour ralentir le jeu.
- c) Pour afficher un message.
Pour aller plus loin
- Ajoute un système de score : Utilise
ScoreManagerpour ajouter des points au joueur quand il réussit. - Affiche un message de victoire à l’écran quand le joueur détruit la pyramide.
Documentation Roblox Lua :
