Catégories
Jeu vidéo ROBLOX ROBLOX-NIVEAU02

Crée un tableau de scores

Objectif : Créé un tableau de scores

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)

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)

Un système de score avec un ModuleScript

1. Créer un ModuleScript pour gérer les scores

-- ModuleScript dans ServerScriptService : "ScoreManager"
local ScoreManager = {}

-- Initialise le Leaderstats pour un joueur
function ScoreManager.initPlayer(player)
    local leaderstats = Instance.new("Folder", player)
    leaderstats.Name = "leaderstats"

    local points = Instance.new("IntValue", leaderstats)
    points.Name = "Score"
    points.Value = 0
end

-- Met à jour le score d'un joueur
function ScoreManager.addPoints(player, points)
    local leaderstats = player:FindFirstChild("leaderstats")
    if leaderstats then
        local score = leaderstats:FindFirstChild("Score")
        if score then
            score.Value = score.Value + points
        end
    end
end

return ScoreManager

Appel dans scriptServeur pour rajouter des points :

-- Script dans ServerScriptService
local ScoreManager = require(game:GetService("ServerScriptService"):WaitForChild("ScoreManager"))

-- Initialiser le Leaderstats pour chaque joueur
game.Players.PlayerAdded:Connect(function(player)
	ScoreManager.initPlayer(player)
end)

local part = workspace.Part -- La Part qui déclenche l'événement

-- Exemple : Ajouter 10 points à un joueur
part.Touched:Connect(function(otherPart)
	-- Vérifie que otherPart fait partie d'un personnage
	local humanoid = otherPart.Parent:FindFirstChild("Humanoid")
	if humanoid then
		-- Récupère le joueur associé au personnage
		local player = game.Players:GetPlayerFromCharacter(otherPart.Parent)
		if player then            
			ScoreManager.addPoints(player, 10)
			part:Destroy() -- Supprime la Part après utilisation

		end
	end
end)
Catégories
Jeu vidéo ROBLOX ROBLOX-NIVEAU02

Plaque rebondissante

As-tu déjà rêvé de faire bondir les joueurs à plusieurs mètres de hauteur dans ton jeu Roblox ? Elles peuvent servir à franchir un obstacle, atteindre une plateforme cachée ou simplement ajouter une touche amusante à un niveau. Dans ce tutoriel, tu vas découvrir comment transformer un simple part en véritable trampoline interactif. Tu verras également comment régler la puissance du rebond pour obtenir différents effets de jeu.

Rebond du joueur sur la plaque

Crée un part et dessous un script :

Saisie ce code dans le script :

local TweenService = game:GetService("TweenService")

local BOUNCE_SPEED = 120    -- vitesse verticale imposée (studs/s)
local COOLDOWN     = 0.3   -- évite les rebonds multiples par contact

local trampoline  = script.Parent
local lastBounce   = {}     -- cooldown par joueur

local function squish(trampoline, bounceSpeed, squishTime)
	
	if bounceSpeed==nil then bounceSpeed = BOUNCE_SPEED end
	
	-- Remplace directement la vélocité verticale
	local vel = trampoline.AssemblyLinearVelocity
	trampoline.AssemblyLinearVelocity = Vector3.new(vel.X, bounceSpeed, vel.Z)
	
end

-- Appliquer des propriétés physiques pour que la part soit glissante
trampoline.CustomPhysicalProperties = PhysicalProperties.new(
	0.7, -- Density
	1,   -- Friction
	1,   -- Elasticity
	1,   -- FrictionWeight
	1    -- ElasticityWeight
)
-- Appliquer un matériau glissant comme de la glace
trampoline.Material = Enum.Material.Carpet

trampoline.Touched:Connect(function(hit)
	local character = hit.Parent
	local humanoid  = character:FindFirstChildWhichIsA("Humanoid")
	if not humanoid or humanoid.Health <= 0 then return end

	local rootPart = character:FindFirstChild("HumanoidRootPart")
	if not rootPart then return end

	-- Cooldown par personnage
	local now = tick()
	if lastBounce[character] and (now - lastBounce[character]) < COOLDOWN then return end
	lastBounce[character] = now

	squish(trampoline)
end)

Ce script transforme une simple pièce Roblox en trampoline capable de faire rebondir les joueurs lorsqu’ils la touchent. Les variables BOUNCE_SPEED et COOLDOWN définissent respectivement la puissance du rebond et le temps d’attente avant qu’un même joueur puisse rebondir à nouveau. Les propriétés physiques et le matériau de la pièce sont modifiés pour lui donner l’apparence et le comportement d’une surface adaptée au rebond.

La fonction squish() applique une nouvelle vitesse verticale à la pièce afin de créer l’effet de propulsion vers le haut.

L’événement Touched détecte lorsqu’un objet entre en contact avec le trampoline et vérifie qu’il s’agit bien d’un personnage vivant possédant un Humanoid. Un système de cooldown mémorise l’instant du dernier rebond de chaque joueur afin d’éviter plusieurs déclenchements successifs lorsque le personnage reste en contact avec le trampoline.

Animation de la plaque comme un trampoline

Par rapport à la version précédente, le script suivant ajoute un effet visuel d’écrasement et de retour à la forme initiale, ce qui donne davantage l’impression qu’il s’agit d’un véritable trampoline.

Une nouvelle variable originalSize mémorise la taille initiale de la plaque afin de pouvoir la restaurer après l’animation. La constante SQUISH_TIME définit la durée de l’animation de compression et de retour à la normale. La table isSquishing empêche que plusieurs animations soient lancées en même temps sur la même plaque, ce qui éviterait des déformations incohérentes. Le service TweenService est utilisé pour créer une animation fluide plutôt qu’un changement instantané de taille.

Lorsqu’un joueur rebondit, la plaque s’aplatit : sa hauteur diminue tandis que sa largeur et sa longueur augmentent légèrement. Cela reproduit visuellement le comportement d’un trampoline qui se comprime sous le poids du joueur. Après un court délai, une seconde animation redonne progressivement à la plaque sa taille d’origine, donnant l’impression qu’elle reprend sa forme après avoir propulsé le joueur.

L’effet visuel est synchronisé avec le rebond du joueur, ce qui rend l’interaction plus réaliste et plus agréable à observer.

local TweenService = game:GetService("TweenService")

local BOUNCE_SPEED = 120    -- vitesse verticale imposée (studs/s)
local COOLDOWN     = 0.3   -- évite les rebonds multiples par contact
local SQUISH_TIME  = 0.08  -- durée de l'étirement en secondes

local trampoline  = script.Parent

local lastBounce   = {}     -- cooldown par joueur
local isSquishing  = {}		-- marquage de la part en état d'étirement

local function squish(trampoline, bounceSpeed, squishTime)
	
	if bounceSpeed==nil then bounceSpeed = BOUNCE_SPEED end
	if squishTime==nil then squishTime = SQUISH_TIME end

	local originalSize = trampoline.Size

	-- Remplace directement la vélocité verticale
	local vel = trampoline.AssemblyLinearVelocity
	trampoline.AssemblyLinearVelocity = Vector3.new(vel.X, bounceSpeed, vel.Z)
	
	if isSquishing[trampoline] then return end
	isSquishing[trampoline] = true
	local tweenInfo = TweenInfo.new(squishTime, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
	TweenService:Create(trampoline, tweenInfo, {
		Size = Vector3.new(originalSize.X * 1.05, originalSize.Y * 0.4, originalSize.Z * 1.05)
	}):Play()
	task.delay(SQUISH_TIME, function()
		TweenService:Create(trampoline, tweenInfo, { Size = originalSize }):Play()
		task.delay(SQUISH_TIME, function() isSquishing[trampoline] = false end)
	end)
end

-- Appliquer des propriétés physiques pour que la part soit glissante
trampoline.CustomPhysicalProperties = PhysicalProperties.new(
	0.7, -- Density
	1,   -- Friction
	1,   -- Elasticity
	1,   -- FrictionWeight
	1    -- ElasticityWeight
)
-- Appliquer un matériau glissant comme de la glace
trampoline.Material = Enum.Material.Carpet

trampoline.Touched:Connect(function(hit)
	local character = hit.Parent
	local humanoid  = character:FindFirstChildWhichIsA("Humanoid")
	if not humanoid or humanoid.Health <= 0 then return end

	local rootPart = character:FindFirstChild("HumanoidRootPart")
	if not rootPart then return end

	-- Cooldown par personnage
	local now = tick()
	if lastBounce[character] and (now - lastBounce[character]) < COOLDOWN then return end
	lastBounce[character] = now

	squish(trampoline)
end)

Système de plaques rebondissantes

Modifie la structure en créant un Folder, sous le folder ton script et la part, puis duplique la plaque rebondissante plusieurs fois :

Modifie ton script pour lire tous les parts rebondissants :

local TweenService = game:GetService("TweenService")

local BOUNCE_SPEED = 120    -- vitesse verticale imposée (studs/s)
local COOLDOWN     = 0.3   -- évite les rebonds multiples par contact
local SQUISH_TIME  = 0.08  -- durée de l'étirement en secondes

local trampolines  = script.Parent
local lastBounce   = {}     -- cooldown par joueur
local isSquishing  = {}		-- marquage de la part en état d'étirement

local function squish(trampoline, bounceSpeed, squishTime)

	if bounceSpeed==nil then bounceSpeed = BOUNCE_SPEED end
	if squishTime==nil then squishTime = SQUISH_TIME end
	
	local originalSize = trampoline.Size
	
	-- Remplace directement la vélocité verticale
	local vel = trampoline.AssemblyLinearVelocity
	trampoline.AssemblyLinearVelocity = Vector3.new(vel.X, bounceSpeed, vel.Z)

	if isSquishing[trampoline] then return end
	isSquishing[trampoline] = true
	local tweenInfo = TweenInfo.new(squishTime, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
	TweenService:Create(trampoline, tweenInfo, {
		Size = Vector3.new(originalSize.X * 1.05, originalSize.Y * 0.4, originalSize.Z * 1.05)
	}):Play()
	task.delay(SQUISH_TIME, function()
		TweenService:Create(trampoline, tweenInfo, { Size = originalSize }):Play()
		task.delay(SQUISH_TIME, function() isSquishing[trampoline] = false end)
	end)
end

for _, trampoline in ipairs(trampolines:GetChildren()) do
	if not trampoline:IsA("BasePart") then continue end

	-- Appliquer des propriétés physiques pour que la part soit glissante
	trampoline.CustomPhysicalProperties = PhysicalProperties.new(
		0.7, -- Density
		1,   -- Friction
		1,   -- Elasticity
		1,   -- FrictionWeight
		1    -- ElasticityWeight
	)
	-- Appliquer un matériau glissant comme de la glace
	trampoline.Material = Enum.Material.Carpet



	trampoline.Touched:Connect(function(hit)
		local character = hit.Parent
		local humanoid  = character:FindFirstChildWhichIsA("Humanoid")
		if not humanoid or humanoid.Health <= 0 then return end

		local rootPart = character:FindFirstChild("HumanoidRootPart")
		if not rootPart then return end

		-- Cooldown par personnage
		local now = tick()
		if lastBounce[character] and (now - lastBounce[character]) < COOLDOWN then return end
		lastBounce[character] = now

		squish(trampoline)
	end)
	
end

Catégories
Jeu vidéo ROBLOX ROBLOX-NIVEAU02

Plaque glissante pour le joueur

Dans beaucoup de jeux Roblox, il existe des zones spéciales qui changent complètement la manière de jouer. Imagine un sol où ton personnage se met à glisser tout seul, comme sur de la glace, sans pouvoir s’arrêter immédiatement. Ou encore une pente qui accélère ton déplacement, te propulsant vers une nouvelle plateforme. Ces effets simples transforment un niveau classique en un vrai parcours d’obstacles amusant et dynamique. Dans ce tutoriel, tu vas apprendre à créer ce type de mécanismes toi-même avec Lua dans Roblox Studio. Tu vas découvrir comment contrôler le comportement d’un joueur lorsqu’il touche une zone spéciale. Tu vas progresser étape par étape pour comprendre comment la physique du jeu peut être modifiée. À la fin, tu seras capable de concevoir tes propres zones de glisse comme dans les vrais jeux d’obby.

Ce tutoriel est organisé en trois parties :

  • La première te montrera comment créer une plaque glissante simple pour faire “patiner” un joueur.
  • La deuxième expliquera comment gérer une plaque en pente pour influencer la direction du déplacement.
  • Enfin, la troisième partie te permettra de combiner plusieurs plaques glissantes pour créer un parcours complet et dynamique.

Plaque glissante

Crée un part puis dessous un script :

Ce script transforme une Part en surface glissante grâce à des propriétés physiques qui réduisent les frottements et lui donnent l’apparence de la glace. Lorsqu’un joueur touche cette Part, le script vérifie qu’il s’agit bien d’un personnage et récupère son HumanoidRootPart, qui représente le centre de son déplacement. Il calcule ensuite la direction dans laquelle regarde le joueur à l’aide du LookVector. La Part reçoit alors une vitesse SPEED qui la fait glisser dans la direction choisie pendant une durée définie SLIDER_LENGTH. Enfin, après ce délai, la vitesse est remise à zéro pour arrêter la glissade.

-- Script pour une part qui glisse sur un joueur lorsqu'il la touche
local part = script.Parent

-- Appliquer des propriétés physiques pour que la part soit glissante
part.CustomPhysicalProperties = PhysicalProperties.new(
	0.7, -- Density
	0,   -- Friction
	0,   -- Elasticity
	0,   -- FrictionWeight
	1    -- ElasticityWeight
)
-- Appliquer un matériau glissant comme de la glace
part.Material = Enum.Material.Ice

-- Vitesse de déplacement de la glissade
local SPEED = 15
local SLIDER_LENGTH = 1

-- Fonction appelée lorsque la part est touchée
part.Touched:Connect(function(hit)
	-- Vérifier si l'objet touché est un personnage
	local character = hit:FindFirstAncestorOfClass("Model")
	if not character then return end
	-- Récupérer le joueur et sa racine
	local rootPart = character:FindFirstChild("HumanoidRootPart")
	if not rootPart then return end
    -- Récupérer la direction de la caméra du joueur
	local dir = rootPart.CFrame.LookVector
	-- Appliquer une impulsion sur la part pour faire glisser le joueur dans la direction de la caméra
	part.AssemblyLinearVelocity = dir * SPEED
	-- Arrêter la glissade après un délai
	task.spawn(function()
		task.wait(SLIDER_LENGTH)
		part.AssemblyLinearVelocity = Vector3.zero		
		end)

end)

Pente glissante

Modifie le code pour permettre à la plaque glissante de tenir compte de son inclinaison.

Une nouvelle fonction, getSurfaceInclination, calcule la direction naturelle de la pente à partir de la gravité et de la normale de la surface. La gravité indique toujours le bas, tandis que la normale renseigne sur l’orientation de la plaque. En combinant ces deux informations, le script détermine la direction dans laquelle un objet glisserait naturellement sur la pente.

Lorsque le joueur touche la plaque, le script calcule cette direction de glissade et vérifie si elle est suffisamment importante. Si la plaque est inclinée, la vitesse est appliquée dans le sens de la pente afin de simuler une descente naturelle. Si la plaque est horizontale, il n’y a pas de direction de pente significative : le joueur glisse alors dans la direction vers laquelle il regarde. Grâce à cet ajout, le même script peut gérer aussi bien une plaque plate qu’une plaque inclinée, ce qui rend le comportement plus réaliste et permet de créer des parcours plus variés.

-- Script pour une part qui glisse sur un joueur lorsqu'il la touche
local part = script.Parent

-- Appliquer des propriétés physiques pour que la part soit glissante
part.CustomPhysicalProperties = PhysicalProperties.new(
	0.7, -- Density
	0,   -- Friction
	0,   -- Elasticity
	0,   -- FrictionWeight
	1    -- ElasticityWeight
)
-- Appliquer un matériau glissant comme de la glace
part.Material = Enum.Material.Ice

-- Vitesse de déplacement de la glissade
local SPEED = 15
local SLIDER_LENGTH = 1

local function getSurfaceInclination(hit)
	-- Récupérer la direction de la gravité
	local gravity = Vector3.new(0, -1, 0)
	-- Récupérer la normale de la surface de la part
	-- la normale est un vecteur unitaire perpendiculaire à la surface
	-- qui indique “dans quel sens la surface est orientée"
	local normal = part.CFrame.UpVector
	-- enlève la composante perpendiculaire à la surface
	local slopeDirection = gravity - normal * gravity:Dot(normal)
	return slopeDirection.Unit
end

-- Fonction appelée lorsque la part est touchée
part.Touched:Connect(function(hit)
	-- Vérifier si l'objet touché est un personnage
	local character = hit:FindFirstAncestorOfClass("Model")
	if not character then return end
	-- Récupérer le joueur et sa racine
	local rootPart = character:FindFirstChild("HumanoidRootPart")
	if not rootPart then return end
    -- Récupérer la direction de la caméra du joueur
	local dir = rootPart.CFrame.LookVector
	-- Récuoération du sens de la pente de la part par rapport à la gravité
	local slopeDirection = getSurfaceInclination(part)

	-- Glissade en fonction si pente de la part ou part horizontale
	if slopeDirection.Magnitude > 0.1 then
		-- Appliquer une impulsion sur la part pour faire glisser le joueur dans la direction de la pente
		part.AssemblyLinearVelocity = slopeDirection * SPEED
	else
		-- Appliquer une impulsion sur la part pour faire glisser le joueur dans la direction de la caméra
		part.AssemblyLinearVelocity = dir * SPEED
		-- Arrêter la glissade après un délai
		task.spawn(function()
			task.wait(SLIDER_LENGTH)
			part.AssemblyLinearVelocity = Vector3.zero		
		end)
	end

end)

Systèmes de plaques et pentes glissantes

Dans cette nouvelle version, le script ne gère plus une seule plaque glissante mais un ensemble de plaques regroupées dans un dossier (Folder). Au démarrage, le script récupère tous les objets contenus dans ce dossier puis les parcourt un par un grâce à une boucle.

local folder = script.Parent
local parts = folder:GetChildren()

for _, part in pairs(parts) do

end

Une vérification est effectuée pour s’assurer que chaque objet est bien une BasePart afin d’éviter les erreurs avec d’autres types d’objets.

if not part:IsA("BasePart") then continue end

Pour chaque plaque trouvée, les propriétés physiques et le matériau de glace sont appliqués automatiquement. Cela évite de dupliquer le même script sur chaque plaque du parcours. La fonction de calcul de la pente est ensuite associée à chaque plaque afin que son inclinaison soit prise en compte individuellement. Enfin, un événement Touched est créé pour chacune d’elles : lorsqu’un joueur touche une plaque, le script utilise les caractéristiques propres à cette plaque (orientation, pente, vitesse de glisse) pour déterminer son déplacement.

Grâce à cette modification, il devient très simple de créer un parcours complet composé de nombreuses surfaces glissantes. Il suffit d’ajouter ou de supprimer des plaques dans le dossier pour que le script les prenne automatiquement en charge, sans aucune modification supplémentaire du code.

-- Script pour une part qui glisse sur un joueur lorsqu'il la touche
local folder = script.Parent
local parts = folder:GetChildren()

for _, part in pairs(parts) do
	
	if not part:IsA("BasePart") then continue end
	
	-- Appliquer des propriétés physiques pour que la part soit glissante
	part.CustomPhysicalProperties = PhysicalProperties.new(
		0.7, -- Density
		0,   -- Friction
		0,   -- Elasticity
		0,   -- FrictionWeight
		1    -- ElasticityWeight
	)
	-- Appliquer un matériau glissant comme de la glace
	part.Material = Enum.Material.Ice

	-- Vitesse de déplacement de la glissade
	local SPEED = 15
	local SLIDER_LENGTH = 3

	local function getSurfaceInclination(hit)
		-- Récupérer la direction de la gravité
		local gravity = Vector3.new(0, -1, 0)
		-- Récupérer la normale de la surface de la part
		-- la normale est un vecteur unitaire perpendiculaire à la surface
		-- qui indique “dans quel sens la surface est orientée"
		local normal = part.CFrame.UpVector
		-- enlève la composante perpendiculaire à la surface
		local slopeDirection = gravity - normal * gravity:Dot(normal)
		return slopeDirection.Unit
	end
	
	-- Fonction appelée lorsque la part est touchée
	part.Touched:Connect(function(hit)
		-- Vérifier si l'objet touché est un personnage
		local character = hit:FindFirstAncestorOfClass("Model")
		if not character then return end
		-- Récupérer le joueur et sa racine
		local rootPart = character:FindFirstChild("HumanoidRootPart")
		if not rootPart then return end
		-- Récupérer la direction de la caméra du joueur
		local dir = rootPart.CFrame.LookVector
		-- Récuoération du sens de la pente de la part par rapport à la gravité
		local slopeDirection = getSurfaceInclination(part)

		-- Glissade en fonction si pente de la part ou part horizontale
		if slopeDirection.Magnitude > 0.1 then
			-- Appliquer une impulsion sur la part pour faire glisser le joueur dans la direction de la pente
			part.AssemblyLinearVelocity = slopeDirection * SPEED
		else
			-- Appliquer une impulsion sur la part pour faire glisser le joueur dans la direction de la caméra
			part.AssemblyLinearVelocity = dir * SPEED
			-- Arrêter la glissade après un délai
			task.spawn(function()
				task.wait(SLIDER_LENGTH)
				part.AssemblyLinearVelocity = Vector3.zero		
			end)
		end

	end)

end
Catégories
Jeu vidéo ROBLOX ROBLOX-NIVEAU02

Créer une plaque de faible gravité

Dans ce tutoriel, tu vas créer une plaque spéciale qui modifie la gravité lorsque le joueur marche dessus.

Grâce à cette plaque, les personnages pourront :

  • sauter beaucoup plus haut ;
  • retomber plus lentement ;
  • atteindre des plateformes normalement inaccessibles.

Ce type de mécanisme est souvent utilisé dans les jeux de science-fiction, les parcours d’obstacles (Obby) ou les bases spatiales.

Comprendre la gravité

La gravité est la force qui attire les objets vers le sol.

Sur Terre, lorsque tu sautes :

  1. tu montes ;
  2. tu ralentis ;
  3. tu redescends.

Dans Roblox, la gravité agit exactement de la même manière.

Si on la diminue :

  • les sauts deviennent plus grands ;
  • les chutes sont plus lentes ;
  • les déplacements semblent plus légers.

Solution 1 : Modifier la gravité pour tout le monde

Dans cette version, lorsqu’un joueur active la plaque, la gravité du jeu entier est modifiée.

Conséquences

  • tous les joueurs sont affectés ;
  • tous les sauts deviennent plus grands ;
  • tous les objets physiques réagissent également à la nouvelle gravité.

Cette solution est simple à mettre en place mais peut rendre le jeu imprévisible si plusieurs joueurs jouent en même temps.

Exemple de situation

Imaginons :

  • Paul marche sur la plaque ;
  • la gravité est divisée par deux.

Même les autres joueurs situés à l’autre bout de la carte profiteront immédiatement de cet effet.

Créer une plaque de non gravité

Commence par construire une Part qui servira de plaque spéciale.

Tu peux lui donner :

  • une couleur vive ;
  • un matériau futuriste ;
  • un effet lumineux.

Les joueurs comprendront ainsi qu’il s’agit d’une zone particulière du parcours.

Détecter l’entrée du joueur

Lorsque le personnage marche sur la plaque, le jeu doit détecter le contact.

Cette détection permet de savoir :

  • quel joueur est entré dans la zone ;
  • quand appliquer l’effet de faible gravité.

C’est le même principe que pour une zone de téléportation ou un checkpoint.

Puis un script :

-- référence au part pour le changement de gravité
local part = script.Parent

-- détection du joueur qui touche la part
part.Touched:Connect(function(hit)
	local character = hit.Parent
	local humanoid = character and character:FindFirstChild("Humanoid")	
	if not humanoid then return end
	-- changement de gravité à 10 au moment de la collision
	workspace.Gravity = 10
end)

Créer une plaque pour retrouver la gravité

Commence par construire une Part qui servira de plaque spéciale .

Puis un script :

-- référence de la part pour retourner la gravité à 196.2
local part = script.Parent

-- détection du joueur qui touche la part
part.Touched:Connect(function(hit)
	local character = hit.Parent
	local humanoid = character and character:FindFirstChild("Humanoid")	
	if not humanoid then return end
	-- retour de la gravité à 196.2 au moment de la collision
	workspace.Gravity = 196.2
end)

Solution 2 : Modifier la gravité pour un seul joueur

Dans cette version, seul le joueur qui touche la plaque bénéficie de l’effet.

Les autres joueurs continuent à jouer normalement.

Cette méthode est souvent préférable dans un jeu multijoueur car chacun peut vivre sa propre expérience.

Comment simuler une faible gravité pour un joueur ?

Comme la gravité du monde est partagée par tous, on ne peut pas simplement changer la gravité globale pour un seul joueur.

On utilise donc une autre technique :

  • augmenter sa puissance de saut ;
  • ralentir sa descente ;
  • modifier certaines propriétés de déplacement.

Le résultat ressemble à une gravité plus faible sans affecter les autres joueurs.

Script à modifier pour la plaque de changement de gravité pour un seul joueur :

-- référence au part pour le changement de gravité
local part = script.Parent

-- détection du joueur qui touche la part
part.Touched:Connect(function(hit)
	local character = hit.Parent
	local hrp = character and character:WaitForChild("HumanoidRootPart")
	
	if not hrp then return end
	
	if hrp:FindFirstChild("GravityAttachment") then return end -- évite les doublons
	
	-- 1. Créer une pièce jointe (Attachment) requise pour VectorForce
	local attachment = Instance.new("Attachment")
	attachment.Name = "GravityAttachment"
	attachment.Parent = hrp

	-- 2. Créer la force physique (VectorForce)
	local vectorForce = Instance.new("VectorForce")
	vectorForce.Name = "CustomGravityForce"
	vectorForce.Attachment0 = attachment
	vectorForce.ApplyAtCenterOfMass = true
	vectorForce.RelativeTo = Enum.ActuatorRelativeTo.World

	-- 3. Calculer la masse totale du personnage
	local totalMass = 0
	for _, part in ipairs(character:GetDescendants()) do
		if part:IsA("BasePart") then
			totalMass = totalMass + part:GetMass()
		end
	end

	-- 4. Appliquer une force vers le haut pour réduire la gravité ressentie
	-- Exemple : contrer 60% de la gravité (le joueur se sentira plus léger)
	local gravityCounterFactor = 0.6 
	local upwardForce = totalMass * workspace.Gravity * gravityCounterFactor

	vectorForce.Force = Vector3.new(0, upwardForce, 0)
	vectorForce.Parent = hrp
end)

Script à modifier pour retrouver la gravité normal pour un seul joueur :

-- référence de la part pour retourner la gravité à 196.2
local part = script.Parent

-- détection du joueur qui touche la part
part.Touched:Connect(function(hit)
	local character = hit.Parent
	local hrp = character and character:FindFirstChild("HumanoidRootPart")
	if not hrp then return end
	
	-- Trouver et supprimer l'Attachment
	local attachment = hrp:FindFirstChild("GravityAttachment")
	if attachment then
		attachment:Destroy()
	end

	-- Trouver et supprimer le VectorForce
	local vectorForce = hrp:FindFirstChild("CustomGravityForce")
	if vectorForce then
		vectorForce:Destroy()
	end
	
end)
Catégories
Jeu vidéo ROBLOX ROBLOX-NIVEAU02

Créer une arme à ramasser et combattre des ennemis

Dans ce tutoriel, tu vas apprendre à créer une arme que le joueur pourra récupérer dans le monde du jeu puis utiliser pour combattre des ennemis.

L’objectif est de réaliser un système complet comprenant :

  • une arme posée au sol ;
  • le ramassage automatique par le joueur ;
  • l’utilisation de l’arme depuis l’inventaire ;
  • une animation de frappe ;
  • des effets visuels lors de l’attaque ;
  • la détection des ennemis touchés ;
  • l’application de dégâts.

À la fin du projet, ton personnage pourra se défendre contre des adversaires comme dans de nombreux jeux d’aventure ou de rôle.

Crée une arme avec l’objet Tool puis un part renommer « Handle » de roblox :

Choisis la matière et la couleur de ton arme :

Positionne l’arme dans la main du joueur :

Saisie ce code dans le script :

-- récupération de l'arme
local arm = script.Parent

-- récupération des services pour animer
local Debris = game:GetService("Debris")
local TweenService = game:GetService("TweenService")
local Debris = game:GetService("Debris")

-- 
-- CONFIGURATION DES ANIMATIONS
-- 
local CONFIG = {
	-- Particules
	nbEtincelles    = 50,
	-- Onde de choc
	ondeActive      = true,
	ondeCouleur     = Color3.fromRGB(255, 150, 0),
	-- Dégâts (rayon)
	rayonDegats     = 40,
	-- Flash
	flashActif      = true,
	sizeFlash       = Vector3.new(5, 5, 5),
	colorFlash      = Color3.fromRGB(255, 0, 0),

}

-- 
-- EFFET FLASH ET ONDE DE CHOC
-- 

local function creerFlash(position)
	local flash = Instance.new("Part")
	flash.Shape = Enum.PartType.Ball
	flash.Size = Vector3.new(0.1, 0.1, 0.1)
	flash.Position = position
	flash.Anchored = true
	flash.CanCollide = false
	flash.CastShadow = false
	flash.Material = Enum.Material.Neon
	flash.Color = CONFIG.colorFlash
	flash.Parent = workspace

	local tween = TweenService:Create(flash,
		TweenInfo.new(0.15, Enum.EasingStyle.Quad, Enum.EasingDirection.Out),
		{ Size = CONFIG.sizeFlash, Transparency = 1 }
	)
	tween:Play()
	Debris:AddItem(flash, 0.2)
end

local function creerOndeChoc(position)
	local onde = Instance.new("Part")
	onde.Shape = Enum.PartType.Ball
	onde.Size = Vector3.new(1, 1, 1)
	onde.Position = position
	onde.Anchored = true
	onde.CanCollide = false
	onde.CastShadow = false
	onde.Material = Enum.Material.Neon
	onde.Color = CONFIG.ondeCouleur
	onde.Transparency = 0.8
	onde.Parent = workspace

	local tween = TweenService:Create(onde,
		TweenInfo.new(0.4, Enum.EasingStyle.Quad, Enum.EasingDirection.Out),
		{ Size = Vector3.new(CONFIG.rayonDegats * 2, CONFIG.rayonDegats * 2, CONFIG.rayonDegats * 2), Transparency = 1 }
	)
	tween:Play()
	Debris:AddItem(onde, 0.5)
end
-- 
-- EFFET ETINCELLES
-- 
local function creerEtincelles(position)
	for i = 1, CONFIG.nbEtincelles do
		local etincelle = Instance.new("Part")
		etincelle.Shape = Enum.PartType.Ball
		-- taille des etincelles 
		etincelle.Size = Vector3.new(0.2, 0.2, 0.2)
		etincelle.Position = position
		etincelle.CanCollide = false
		etincelle.CastShadow = false
		etincelle.Material = Enum.Material.Neon
		-- Couleur aléatoire entre orange et jaune
		etincelle.Color = Color3.fromRGB(255, math.random(100, 255), 0)
		etincelle.Parent = workspace

		-- Direction aléatoire
		local direction = Vector3.new(
			math.random(-100, 100) / 100,
			math.random(20, 100) / 100,
			math.random(-100, 100) / 100
		).Unit
		-- vitesse aléatoire de propagation des étincelles
		local vitesse = math.random(20, 200)
		local vb = Instance.new("BodyVelocity")
		vb.Velocity = direction * vitesse
		vb.MaxForce = Vector3.new(1e4, 1e4, 1e4)
		vb.Parent = etincelle

		-- Disparition progressive
		local duree = math.random(5, 12) / 10
		local tween = TweenService:Create(etincelle,
			TweenInfo.new(duree, Enum.EasingStyle.Quad, Enum.EasingDirection.In),
			{ Transparency = 1, Size = Vector3.new(0.05, 0.05, 0.05) }
		)
		tween:Play()
		Debris:AddItem(etincelle, duree)
	end
end
-- 
-- limite le nombre de dégâts pendant un certain temps
-- 
local function withCooldown(hit)
	local tag = Instance.new("Folder")
	tag.Name = "ArmTag"
	tag.Parent = hit.Parent
	Debris:AddItem(tag, 0.4)	
	task.wait(0.4)
end
-- si le joueur est en cooldown, ne pas appliquer les dégâts
local function isCooldown(hit)
	return hit.Parent:FindFirstChild("ArmTag")
end
-- mouvement coup d'épée
local function swordStroke(arm)
	local tween = TweenService:Create(arm.Parent,
		TweenInfo.new(1, Enum.EasingStyle.Elastic, Enum.EasingDirection.Out),
		{ Grip = arm.Parent.Grip * CFrame.Angles(0, 0, math.rad(90)) }
	)
	tween:Play()	
end
-- l'arme touche un humanoid
arm.Touched:Connect(function(hit)
	local humanoid = hit and hit.Parent:FindFirstChild("Humanoid")
	local player = game.Players:GetPlayerFromCharacter(hit.Parent)
	if player then return end
	if not humanoid then return end
	if isCooldown(hit) then return end
	-- coup d'épée
	swordStroke(arm)
	-- dégâts
	humanoid:TakeDamage(10)
	-- effets
	if CONFIG.flashActif   then creerFlash(hit.Position)      end
	if CONFIG.ondeActive   then creerOndeChoc(hit.Position)   end
	creerEtincelles(hit.Position)
	-- cooldown pendant un certain temps
	withCooldown(hit)
end)

Rajoute un son laser

Insère un son dans l’arborescence du tool :

Rajoute dans ton script la référence du son :

local soundLaser = arm.Laser

Puis ajoute dans ton script la fonction pour jouer le son :

local function playSound(sound)
	if not sound then return end
	pcall(function() sound:Play() end)
end

Puis modifie la fonction arm.Touched pour jouer le son :

-- l'arme touche un humanoid
arm.Touched:Connect(function(hit)
	local humanoid = hit and hit.Parent:FindFirstChild("Humanoid")
	local player = game.Players:GetPlayerFromCharacter(hit.Parent)
	if player then return end
	if not humanoid then return end
	if isCooldown(hit) then return end
	-- coup d'épée
	playSound(soundLaser)
	swordStroke(arm)
	-- dégâts
	humanoid:TakeDamage(10)
	-- effets
	if CONFIG.flashActif   then creerFlash(hit.Position)      end
	if CONFIG.ondeActive   then creerOndeChoc(hit.Position)   end
	creerEtincelles(hit.Position)
	-- cooldown pendant un certain temps
	withCooldown(hit)
end)
Catégories
Jeu vidéo ROBLOX ROBLOX-NIVEAU02

Un système de Checkpoints

Tu es le maître dun jeu d’un parcours d’obstacles (un Obby). Ton rôle est de surveiller les joueurs, de noter leur progression, et de les renvoyer au bon endroit s’ils tombent dans le vide.

Crée dans ton jeu des CheckPoints sur ton parcours, les checkpoints seront visibles ou non, puis programme un script qui reconnaitre tous les checkpoints et notera pour chaque joueur sa progression. En cas de respawn le joueur reviendra sur le dernier checkpoint validé.

Au tout début du script, on trouve une boîte appelée CONFIG. C’est le « panneau de contrôle » du jeu. C’est ici que tu peux changer facilement les règles sans toucher au reste du code.

  1. Quand un joueur rejoint le jeu (PlayerAdded) :
    • On initialise ses données (il commence au Checkpoint 1).
    • On écoute quand son personnage apparaît (CharacterAdded) pour le téléporter au bon checkpoint (au cas où il meurt et respawn).
  2. Quand un joueur quitte le jeu (PlayerRemoving) :
    • On supprime ses données pour libérer de la mémoire.
  3. Au démarrage du script :
    • On initialise tous les joueurs déjà présents.
    • On connecte tous les checkpoints.

Tu places 5 checkpoints dans un dossier appelé « Checkpoints » dans Workspace :

  • Checkpoint1
  • Checkpoint2
  • Checkpoint3
  • Checkpoint4
  • Checkpoint5
  1. Un joueur (123CODAGE) rejoint le jeu :
    • Ses données : { indexActuel = 0, checkpointPart = Checkpoint1 }.
    • Il spawn au Checkpoint1.
  2. 123CODAGE touche Checkpoint2 :
    • Le script vérifie : indexActuel + 1 = 12 == 1 + 1OK !
    • indexActuel passe à 2.
    • Checkpoint2 devient vert.
    • Message : « 123CODAGE a atteint le checkpoint 2/5″.
  3. 123CODAGE tombe dans le vide :
    • Il respawn au Checkpoint2 (dernier validé).
  4. 123CODAGE touche Checkpoint4 sans faire le 3 :
    • Le script vérifie : indexActuel + 1 = 34 != 3Bloqué ! (car sauvegarderOrdre = true).
  5. 123CODAGE termine tous les checkpoints :
    • Message : « 123CODAGE a terminé le parcours ! » 🎉

Saisie ce script CheckpointsService sous ServerScriptService :

-- Script : GestionCheckpoints
local Players = game:GetService("Players")
local DialogueModule = require(game.ReplicatedStorage.DialogueModule)

-- ═══════════════════════════════════════
-- CONFIGURATION
-- ═══════════════════════════════════════
local CONFIG = {
	dossierCheckpoints = "Checkpoints",  -- nom du dossier dans Workspace
	offsetRespawn      = Vector3.new(0, 3, 0), -- hauteur au-dessus du checkpoint
	afficherMessages   = true,
	sauvegarderOrdre   = true,  -- respecte l'ordre numérique des checkpoints
	checkpointValidated = BrickColor.Green(),
	checkpointInitial = BrickColor.DarkGray()
}

-- ═══════════════════════════════════════
-- RÉCUPÉRATION DES CHECKPOINTS
-- ═══════════════════════════════════════
local dossier = workspace:WaitForChild(CONFIG.dossierCheckpoints)

local function getCheckpointsTries()
	local liste = {}
	for _, cp in ipairs(dossier:GetChildren()) do
		if cp:IsA("BasePart") or cp:IsA("Model") then
			table.insert(liste, cp)
		end
	end
	-- Trier par nom numérique (Checkpoint1, Checkpoint2...)
	table.sort(liste, function(a, b)
		local numA = tonumber(a.Name:match("%d+")) or 0
		local numB = tonumber(b.Name:match("%d+")) or 0
		return numA < numB
	end)
	return liste
end

local checkpoints = getCheckpointsTries()

-- ═══════════════════════════════════════
-- DONNÉES PAR JOUEUR
-- ═══════════════════════════════════════
local progressionJoueurs = {}
-- { [userId] = { indexActuel = 1, checkpointPart = part } }

local function getPositionCheckpoint(cp)
	if cp:IsA("Model") then
		local primary = cp.PrimaryPart or cp:FindFirstChildOfClass("BasePart")
		return primary and primary.Position or Vector3.new(0, 0, 0)
	end
	return cp.Position
end

-- ═══════════════════════════════════════
-- RESPAWN AU DERNIER CHECKPOINT
-- ═══════════════════════════════════════
local function respawnAuCheckpoint(player)

	local data = progressionJoueurs[player.UserId]
	if not data then return end

	local character = player.Character
	if not character then return end

	local rootPart = character:FindFirstChild("HumanoidRootPart")
	if not rootPart then return end

	local position = getPositionCheckpoint(data.checkpointPart)
	rootPart.CFrame = CFrame.new(position + CONFIG.offsetRespawn)

end

-- ═══════════════════════════════════════
-- VALIDATION D'UN CHECKPOINT
-- ═══════════════════════════════════════
local function validerCheckpoint(player, indexCP)
	local data = progressionJoueurs[player.UserId]
	if not data then return false end

	-- Vérifier l'ordre si activé
	if CONFIG.sauvegarderOrdre and indexCP ~= data.indexActuel + 1 then
		return false -- ignore si ce n'est pas le suivant
	end

	if indexCP > #checkpoints or indexCP <= data.indexActuel then return false end
		
	data.indexActuel     = indexCP
	data.checkpointPart  = checkpoints[indexCP]

	if CONFIG.afficherMessages then
		local character = player.Character
		DialogueModule.creerDialogue(character, "🏁 " .. player.Name .. " a atteint le checkpoint " .. indexCP .. "/" .. #checkpoints)
	end

	-- Dernier checkpoint = fin du parcours
	if indexCP == #checkpoints then
		if CONFIG.afficherMessages then
			local character = player.Character
			DialogueModule.creerDialogue(character, "🎉 " .. player.Name .. " a terminé le parcours !")
		end
		-- Ajoute ici ta logique de fin (récompense, téléportation...)
	end
	
	return true

end

-- ═══════════════════════════════════════
-- CONNEXION DES TOUCHES DE CHAQUE CHECKPOINT
-- ═══════════════════════════════════════
local function connecterCheckpoints()
	for index, cp in ipairs(checkpoints) do
		local part = cp:IsA("Model") and (cp.PrimaryPart or cp:FindFirstChildOfClass("BasePart")) or cp

		if part then
			-- Couleur initiale pour visualiser l'ordre
			if CONFIG.checkpointInitial then
				part.BrickColor = CONFIG.checkpointInitial
			end

			part.Touched:Connect(function(hit)
				local character = hit.Parent
				local player = Players:GetPlayerFromCharacter(character)
				if not player then return end

				local data = progressionJoueurs[player.UserId]
				if not data then return end

				-- Déjà validé
				if data.indexActuel >= index then return end

				if validerCheckpoint(player, index) then

					-- Allumer le checkpoint pour ce joueur (visuel global simplifié)
					if CONFIG.checkpointValidated then
						part.BrickColor = CONFIG.checkpointValidated
					end
				end
			end)
		end
	end
end

-- 
-- GESTION DES JOUEURS
-- 
local function initialiserJoueur(player)
	progressionJoueurs[player.UserId] = {
		indexActuel    = 0,
		checkpointPart = checkpoints[1], -- spawn initial = checkpoint 1
	}

	player.CharacterAdded:Connect(function(character)
		task.wait(0.2) -- laisser le personnage se charger
		respawnAuCheckpoint(player)
	end)
end

-- supprimer la progression du joueur
local function nettoyerJoueur(player)
	progressionJoueurs[player.UserId] = nil
end

-- 
-- LANCEMENT
--
Players.PlayerAdded:Connect(initialiserJoueur)
Players.PlayerRemoving:Connect(nettoyerJoueur)

for _, player in ipairs(Players:GetPlayers()) do
	initialiserJoueur(player)
end

connecterCheckpoints()

Rangement des Checkpoints (getCheckpointsTries)

Dans Roblox, quand le jeu se lance, les objets ne s’installent pas toujours dans l’ordre. Le script doit donc faire le tri.

  • Il va chercher tous les blocs dans le dossier « Checkpoints ».
  • Il regarde leur nom (ex: « Checkpoint1 », « Checkpoint2 », « Checkpoint3 »).
  • Il extrait les chiffres grâce à une formule magique (%d+) et les trie du plus petit au plus grand dans une liste ordonnée

 Le carnet de notes du jeu (progressionJoueurs)

Le jeu a besoin d’une mémoire pour savoir où en est chaque joueur. Pour cela, il utilise un tableau (comme une liste de classe) :

local progressionJoueurs = {}

Quand un joueur se connecte, le script lui crée une fiche :

  • Le bloc de réapparition (le tout premier checkpoint).
  • Son niveau actuel (commence à 0).

Le Respawn (La réapparition après une chute)

Quand ton personnage meurt ou réapparaît, la fonction respawnAuCheckpoint se déclenche :

  1. Le script cherche le nom du joueur dans son carnet de notes.
  2. Il trouve la position 3D (X, Y, Z) du dernier checkpoint validé.
  3. Il téléporte le joueur à cette position, en le surélevant légèrement (grâce à l’offset de 3 blocs défini dans la configuration) pour qu’il ne s’enfonce pas dans le bloc.

Toucher et Valider un Checkpoint (validerCheckpoint)

C’est ici que la magie opère quand tes pieds touchent une plaque :

  • Le détecteur (Touched) : Chaque checkpoint possède un capteur invisible. Dès qu’un joueur marche dessus, le script se réveille.
  • La vérification anti-triche : Si sauvegarderOrdre est activé, le script vérifie si le checkpoint touché est bien le suivant dans la liste (par exemple, passer du 2 au 3). Si tu essaies de sauter directement du 1 au 3, le jeu t’ignore !
  • La mise à jour : Si tout est bon :
    1. Le jeu met à jour ta fiche dans le carnet.
    2. Le checkpoint change de couleur (il devient vert pour te montrer visuellement que c’est bon).
    3. Un message s’affiche dans le chat grâce à un module de dialogue (ex:  » Joueur1 a atteint le checkpoint 3/5″).
    4. Si c’est le tout dernier checkpoint, une fête se déclenche ( » Joueur1 a terminé le parcours ! »).

L’arrivée et le départ des joueurs

Tout en bas du script, le jeu surveille les connexions :

  • Un joueur arrive (PlayerAdded) : On crée sa fiche de suivi et on prépare son personnage pour qu’il soit téléporté à son dernier checkpoint à chaque fois qu’il réapparaît.
  • Un joueur s’en va (PlayerRemoving) : On efface sa fiche du carnet de notes pour ne pas encombrer inutilement la mémoire du serveur du jeu (c’est le nettoyage).

Ce qu’il faut retenir (les concepts clés de programmation) :

  1. Les Variables (local ...) : Des boîtes pour ranger des informations (la couleur des blocs, les coordonnées…).
  2. Les Tableaux ({}) : Des listes pour ranger des groupes d’objets (les checkpoints dans l’ordre) ou des informations complexes (la liste des joueurs et leur niveau).
  3. Les Événements (.Touched.PlayerAdded) : Des déclencheurs qui disent au script : « Hé ! Quelque chose s’est passé, exécute le code maintenant ! »
Catégories
Jeu vidéo ROBLOX ROBLOX-NIVEAU02

Boîte de dialogue

Voici une explication simple et étape par étape pour créer un module Lua sur Roblox qui affiche une boîte de dialogue au-dessus de la tête des joueurs. C’est comme une bulle de BD qui apparaît quand un personnage parle !

Ce module permet d’afficher un texte (comme « Bonjour ! ») au-dessus de la tête d’un personnage dans Roblox, avec un design personnalisable (couleurs, taille, durée d’affichage, etc.).
Idéal pour :

  • Des quêtes ou dialogues dans ton jeu.
  • Des messages temporaires (ex : « Bravo ! »).
  • Des indications pour les joueurs.

Créer un module pour générer les boîtes de dialogue

Un module, c’est comme un générateur unique pour créer tes boîtes de dialogue :

  • Tu gagnes du temps (pas besoin de tout réécrire).
  • Tu évites les erreurs (tout est centralisé).
  • Tu peux améliorer ton jeu facilement (ajouter des animations, des sons, etc.).

« Un bon développeur est un développeur fainéant : il écrit le code une fois et le réutilise 1000 fois ! »

Où placer le ModuleScript pour la génération des boîtes de dialogue

EmplacementUsage
ReplicatedStorageAccessible côté client et serveur recommandé
ServerScriptServiceServeur uniquement
StarterPlayerScriptsClient uniquement

ReplicatedStorage est le meilleur choix pour une utilisation coté client et serveur. Placer un module dans ReplicatedStorage dans Roblox peut être pratique dans ce cas, mais cela comporte aussi des risques importants à connaître, surtout si ton module contient des fonctions sensibles ou des données critiques. Tout ce qui est dans ReplicatedStorage est téléchargé et exécutable côté client (par les joueurs).
Un joueur malveillant peut :

  • Exploiter des failles si ton module contient des appels non sécurisés
  • Lire tout le code de ton module (même si tu le caches, il peut être extrait avec des outils comme Roblox Studio ou des exploits).
  • Modifier localement le comportement du module (en utilisant des exploits ou des scripts clients).

Crée un ModuleScript :

local DialogueModule = {}
local TweenService = game:GetService("TweenService")

-- CONFIGURATION
DialogueModule.CONFIG = {
	largeur = 250,
	hauteur = 80,
	offsetY = 3,
	couleurFond = Color3.fromRGB(0, 0, 0),
	transparenceFond = 0.4,
	couleurTexte = Color3.fromRGB(255, 255, 255),
	couleurBordure = Color3.fromRGB(255, 255, 255),
	taillePolicee = 16,
	dureAffichage = 4,
}

function DialogueModule.creerDialogue(personnage, texte)
	local CONFIG = DialogueModule.CONFIG
	local head = personnage:WaitForChild("Head", 5)
	if not head then return end

	-- Supprimer l'ancienne boîte
	local ancien = head:FindFirstChild("DialogueGui")
	if ancien then ancien:Destroy() end

	-- Créer le BillboardGui
	local billboard = Instance.new("BillboardGui")
	billboard.Name = "DialogueGui"
	billboard.Adornee = head
	billboard.Size = UDim2.new(0, CONFIG.largeur, 0, CONFIG.hauteur)
        
        -- Pour le rebond
	billboard.StudsOffset = Vector3.new(0, CONFIG.offsetY - 2, 0) 
	billboard.AlwaysOnTop = true
	billboard.ResetOnSpawn = false
	billboard.Parent = head

	-- Fond
	local fond = Instance.new("Frame")
	fond.Size = UDim2.new(1, 0, 1, 0)
	fond.BackgroundColor3 = CONFIG.couleurFond
	fond.BackgroundTransparency = 1  -- Commence invisible
	fond.BorderSizePixel = 0
	fond.Parent = billboard

	-- Coins arrondis
	local coin = Instance.new("UICorner")
	coin.CornerRadius = UDim.new(0, 10)
	coin.Parent = fond

	-- Bordure
	local bordure = Instance.new("UIStroke")
	bordure.Color = CONFIG.couleurBordure
	bordure.Thickness = 1.5
	bordure.Transparency = 0.5
	bordure.Parent = fond

	-- Texte
	local label = Instance.new("TextLabel")
	label.Size = UDim2.new(1, -16, 1, -10)
	label.Position = UDim2.new(0, 8, 0, 5)
	label.BackgroundTransparency = 1
	label.TextColor3 = CONFIG.couleurTexte
	label.TextSize = CONFIG.taillePolicee
	label.Font = Enum.Font.GothamMedium
	label.Text = texte
	label.TextWrapped = true
	label.TextXAlignment = Enum.TextXAlignment.Center
	label.Parent = fond

	-- Flèche
	local fleche = Instance.new("Frame")
	fleche.Size = UDim2.new(0, 14, 0, 14)
	fleche.Position = UDim2.new(0.5, -7, 1, -7)
	fleche.BackgroundColor3 = CONFIG.couleurFond
	fleche.BackgroundTransparency = CONFIG.transparenceFond
	fleche.BorderSizePixel = 0
	fleche.Rotation = 45
	fleche.Parent = fond

	-- Suppression après délai
	if CONFIG.dureAffichage > 0 then
		task.delay(CONFIG.dureAffichage, function()
			if billboard and billboard.Parent then
				billboard:Destroy()
			end
		end)
	end

	return billboard
end

return DialogueModule

Génère la boîte de dialogue soit dans un localScript :

local Players = game:GetService("Players")
local player = Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()

local DialogueModule = require(game.ReplicatedStorage.DialogueModule)

-- Afficher
local character = game.Players.LocalPlayer.Character
DialogueModule.creerDialogue(character, "Bonjour !")

Ou dans un script sur le serveur par exemple lors d’une collision avec un part :

local part = script.Parent
local Players = game:GetService("Players")	
local DialogueModule = require(game.ReplicatedStorage.DialogueModule)

part.Touched:Connect(function(hit)
	local player = Players:GetPlayerFromCharacter(hit.Parent)
	if player then
		-- Afficher
		local character = player.Character
		DialogueModule.creerDialogue(character, "Bonjour !")
	end
end)

Comment modifier les paramètres de la boîte de dialogue :

-- Modifier la config si besoin
DialogueModule.CONFIG.dureAffichage = 6
DialogueModule.CONFIG.couleurFond = Color3.fromRGB(30, 30, 80)

Rajoute dans ton code une animation de rebonds avant la suppression :

	-- 1. Rebond de la boîte
	local tweenRebond = TweenService:Create(
		billboard,
		TweenInfo.new(0.3, Enum.EasingStyle.Bounce, Enum.EasingDirection.Out),
		{StudsOffset = Vector3.new(0, CONFIG.offsetY, 0)}
	)
	tweenRebond:Play()

Animation transparence du fond :

	-- 2. Fondu du fond
	local tweenFondu = TweenService:Create(
		fond,
		TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out),
		{BackgroundTransparency = CONFIG.transparenceFond}
	)
	tweenFondu:Play()

Animer le texte :

	-- 3. Texte qui pulse
	local tweenPulse = TweenService:Create(
		label,
		TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, -1, true),
		{TextSize = CONFIG.taillePolicee + 5}
	)
	tweenPulse:Play()

Bouger la flèche :

	-- 4. Flèche qui bouge
	local tweenFleche = TweenService:Create(
		fleche,
		TweenInfo.new(0.8, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut, -1, true),
		{Position = UDim2.new(0.5, -7, 1.2, -14)}
	)
	tweenFleche:Play()
Catégories
Jeu vidéo ROBLOX ROBLOX-NIVEAU02

Chemins invisibles

Dans ce tutoriel sur Roblox, tu vas pouvoir apprendre à créer un parcours de plateformes dynamique et dangereux. Le principe est simple : plusieurs chemins sont proposés au joueur pour atteindre la sortie du niveau. Mais attention, les différents chemins ne restent pas visibles éternellement ! Grâce à un script en Lua, certains chemins disparaissent régulièrement au fil du temps. Le joueur doit donc observer, réfléchir rapidement et changer de direction avant de tomber dans le vide.

Création de la structure des différents chemins

Dans un premier temps, créer une structure de différents chemins composés de plateformes.

Créer un Folder principal nommé PathsFinding puis des sous Folder qui représenteront tes différents chemins possibles Path01, Path02 … puis sous les différents chemins créer tes plateformes, puis un Script :

Programmation de l’animation des différents chemins

Saisie ce code dans ton script, ce script en Lua pour Roblox permet de créer plusieurs chemins de plateformes qui apparaissent et disparaissent automatiquement.

Au début, le programme récupère le service TweenService, utilisé pour créer des animations fluides comme les effets de disparition et d’apparition.

Les variables de configuration définissent combien de temps un chemin reste visible, le temps d’attente entre les transitions et la durée de l’animation :

  • local DISPLAY_DURATION = 3 — secondes d’affichage du chemin
  • local WAIT_TIME = 3 — secondes entre chaque transition
  • local FADE_DURATION = 0.8 — secondes pour le fade in/out

Le script récupère ensuite tous les dossiers contenant les chemins et les trie dans l’ordre (path1, path2, etc.).

Chaque plateforme est préparée : elle devient fixe (Anchored = true), invisible (Transparency = 1) et sans collision (CanCollide = false).

Les informations importantes des chemins sont stockées dans des tableaux pour rendre le script plus rapide et éviter des calculs inutiles.
La fonction fadeParts() sert à rendre les plateformes visibles ou invisibles grâce à une animation progressive appelée “fade”.
Au démarrage, seul le premier chemin apparaît et devient solide pour que le joueur puisse marcher dessus.

Ensuite, une boucle infinie fait apparaître le chemin suivant pendant que l’ancien disparaît progressivement.
Grâce à ce système, le joueur doit constamment changer de chemin pour éviter de tomber et réussir à trouver la sortie du niveau dans Roblox Studio.

local TweenService = game:GetService("TweenService")

-- Configuration
local DISPLAY_DURATION = 3    -- secondes d'affichage du chemin
local WAIT_TIME      = 3   -- secondes entre chaque transition
local FADE_DURATION    = 0.8  -- secondes pour le fade in/out
-- Récupérer tous les chemins du dossier
local pathsFinding   = script.Parent
-- trie des chemins par leur nom : path1, path2, path3, ...
local children = pathsFinding:GetChildren()
table.sort(children, function(a, b) return a.Name < b.Name end)
local maxPaths = 0
-- Cache des parts par niveau (évite GetChildren() en boucle)
local pathFinding = {}
-- Cache des données par niveau (évite GetAttribute à chaque frame)
local pathData = {}

-- Prépare les données des différents chemins
for i, path in ipairs(children) do
	if not path:IsA("Folder") then continue end
	local parts = {}
	for _, part in ipairs(path:GetChildren()) do
		if not part:IsA("BasePart") then continue end
		part.Anchored     = true
		part.CanCollide   = false
		part.Transparency = 1
		table.insert(parts, part)
	end
	maxPaths += 1
	pathFinding[maxPaths] = parts
	-- Stocke les attibuts en mémoire
	pathData[maxPaths] = {
		displayDuration 	= path:GetAttribute("DisplayDuration") 	or DISPLAY_DURATION,
		waitTime  		= path:GetAttribute("WaitTime") or WAIT_TIME,
	}
end

-- TweenInfo créé une seule fois
local tweenInfo = TweenInfo.new(FADE_DURATION, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut)

-- Rend visible ou invisible tous les les parts d'un chemin
local function fadeParts(parts, targetTransparency, canCollide)
	for _, part in ipairs(parts) do
		TweenService:Create(part, tweenInfo, {
			Transparency = targetTransparency
		}):Play()
		if canCollide ~= nil then
			part.CanCollide = canCollide
		end
	end
end

-- Affiche le premier chemin au démarrage
fadeParts(pathFinding[1], 0, true)

local currentIndex = 1
while true do
	-- Attendre avant de rendre in le chemin actuel
	task.wait(pathData[currentIndex].displayDuration)
	-- Calcule l'index du prochain chemin (boucle)
	local nextIndex = (currentIndex % maxPaths) + 1
	-- Transition simultanée : fade out ancien + fade in nouveau
	fadeParts(pathFinding[nextIndex],    0, true)	
	-- Attendre avant de rendre invisible le chemin actuel
	task.wait(pathData[currentIndex].waitTime)
	fadeParts(pathFinding[currentIndex], 1, false)
	-- Attendre le temps du fadout avant de continuer
	task.wait(FADE_DURATION)
	-- Mise à jour l'index pour la prochaine itération
	currentIndex = nextIndex

end

Paramétrage de l’animation

Saisir les deux attributs sur chaque Path :

  • DisplayDuration — secondes d’affichage du chemin
  • WaitTime — secondes entre chaque transition

Catégories
Jeu vidéo ROBLOX ROBLOX-NIVEAU02

Créer des textures

Dans Roblox, les textures servent à donner un aspect plus réaliste aux objets du jeu et donne du relief au jeu. Au lieu d’avoir seulement une couleur simple, on peut ajouter des images pour représenter du bois, de la pierre, du métal ou encore de l’herbe.
La texture principale correspond à l’image visible sur l’objet, appelée souvent “Color” ou “Albedo”, qui donne les couleurs et les détails.
Il existe aussi des images spéciales comme la Normal Map : elle ne change pas la forme réelle de l’objet, mais elle crée une illusion de relief avec la lumière, par exemple des bosses, des fissures ou des briques.
D’autres textures peuvent contrôler la brillance, les reflets ou les zones transparentes, ce qui permet de créer des matériaux beaucoup plus réalistes dans un jeu Roblox.

Comment affecter une texture existante

Crée un part :

Associe au part une texture existante :

Puis choisis une couleur :

Essaye les autres textures.

Comment créer une nouvelle texture

Tu peux utiliser ce site pour créer une nouvelle texture ou ce site pour trouver des textures libre de droit :

Choisir une texture sur un site :

Modifie la taille de l’image dans Paint pour une taille de 512×512 pixels :

Puis générer une image « normalMap » pour le relief avec ce site :

Clic avec le bouton gauche de ta souris pour charger ton image :

Modifie les différents paramètres pour obtenir l’image que tu souhaites :

Puis saisis le nom de ton fichier puis clic sur Download :

Maintenant que tes deux images sont prêtes, dans ROBLOX demande l’ouverture du gestionnaire des matériaux :

Crée un nouveau matériau en cliquant sur le + en haut à gauche :

Donne un nom à ton nouveau matériau :

Importe ton image de base :

Ajoute ta nouvelle texture au bloc :

Rajoute ton image normalMap :

Pour retrouver tes nouvelles textures :

Et dans les propriétés du part :

Catégories
Jeu vidéo ROBLOX ROBLOX-NIVEAU02

Barrières invisibles infranchissables

Crée dans ton jeu des barrières invisibles que le joueur ne peut pas franchir. Dès que le joueur touche une barrière invisible, celle-ci se matérialise et déclenche une alarme sonore. Tu peux répliquer autant de barrières invisibles et infranchissables que tu auras besoin pour ton jeu. Ces barrières permettent à ton joueur d’être guider et l’oblige à passer par certaines étapes de ton monde.

Crée dans ton workspace l’arborescence suivante dans un Folder avec un fichier son en option, un script, un part représentant un mur :

Puis saisie ce code dans ton script :

local Players = game:GetService("Players")

-- Configuration
local TRANSPARENCY_VISIBLE = 0.7
local TRANSPARENCY_HIDDEN  = 1
local FADE_DELAY           = 2

-- Récupération des objets du folder
local wallsFolder = script.Parent

-- Fonction appelée quand un joueur touche un mur
local function onWallTouched(otherPart, wall)
	-- Vérification joueur uniquement
	local character = otherPart.Parent
	if not Players:GetPlayerFromCharacter(character) then return end
	print("Collision avec le joueur")
end

-- Lecture de tous les murs du dossier
for _, wall in wallsFolder:GetChildren() do
	if not wall:IsA("Part") then continue end

	wall.Anchored     = true
	wall.Transparency = TRANSPARENCY_HIDDEN
	wall.Material     = Enum.Material.Neon
	wall.CanCollide   = true  -- mur bloquant

	wall.Touched:Connect(function(otherPart)
		onWallTouched(otherPart, wall)
	end)
end

Lance ton jeu, le mur est invisible, si ton joueur touche le mur il reste bloqué !!! Un message dans la sortie indique que le joueur est rentré en collision avec le mur :

Afin d’indiquer au joueur qu’il ne peut pas franchir le mur invisible, on va le faire apparaître et déclencher une alarme sonore.

Modifie le script :

local Players = game:GetService("Players")

-- Configuration
local TRANSPARENCY_VISIBLE = 0.7
local TRANSPARENCY_HIDDEN  = 1
local FADE_DELAY           = 2

-- Récupération des objets du folder
local wallsFolder = script.Parent

-- Chargement du fichier sonore (si présent)
local sound = wallsFolder:FindFirstChildOfClass("Sound")
if not sound then
	warn("[CoinManager] Aucun Sound trouvé dans ", coinsFolder.Name)
end

-- Fonction appelée quand un joueur touche un mur
local function onWallTouched(otherPart, wall)
	-- Vérification joueur uniquement
	local character = otherPart.Parent
	if not Players:GetPlayerFromCharacter(character) then return end
	-- Évite les appels multiples simultanés
	if wall.Transparency == TRANSPARENCY_VISIBLE then return end
	
	-- Affichage du mur en transparence
	wall.Transparency = TRANSPARENCY_VISIBLE
	-- Son d'alerte
	if sound then
		pcall(function() sound:Play() end)
	end
	task.wait(FADE_DELAY)
	wall.Transparency = TRANSPARENCY_HIDDEN
end

-- Lecture de tous les murs du dossier
for _, wall in wallsFolder:GetChildren() do
	if not wall:IsA("Part") then continue end

	wall.Anchored     = true
	wall.Transparency = TRANSPARENCY_HIDDEN
	wall.Material     = Enum.Material.Neon
	wall.CanCollide   = true  -- mur bloquant

	wall.Touched:Connect(function(otherPart)
		onWallTouched(otherPart, wall)
	end)
end

Duplique les murs invisibles infranchissables et déplace les dans ton espace de jeu :