Catégories
Jeu vidéo ROBLOX

Système d’ouverture de portes

Construis un système de portes que tu pourras répliquer partout dans ton jeu. Le joueur pourra ouvrir des portes et découvrir d’autres pièces ou d’autres mondes. Tu pourras choisir entre une fermeture manuelle de la porte ou automatique après un laps de temps. Plusieurs boutons synchronisés permettent de piloter une même porte. Le bouton peut-être installé à distance de la porte.

Construis cette arborescence dans ton workspace :

Sous un folder, insére un son pour l’ouverture de ta porte, un script, un part représentant ta porte, sous la porte un part pour représenter le bouton d’ouverture, puis un proxyprompt sous le bouton. Renomme chaque élément pour plus de clarté :

Les noms donnés n’ont pas d’importance par contre la structure de l’arborescence du folder doit être absolument respectée.

Saisie le code suivant dans le script :

-- Récupération du joueur
local Players = game:GetService("Players")

-- Récupération du dossier des portes
local doorsFolder = script.Parent

-- Initialisation de chaque porte
-- Le dossier doit comporte un part pour la porte
-- puis un part pour chaque bouton
-- puis proxymity prompt pour chaque bouton
for _, door in doorsFolder:GetChildren() do
	if not door:IsA("Part") then continue end
	door.Anchored     = true
	door.Transparency = 0
	door.CanCollide   = true

	for _, button in door:GetChildren() do
		if not button:IsA("Part") then continue end
		button.Anchored     = true
		button.Transparency = 0
		button.CanCollide   = true		
		local proxi = button:FindFirstChildOfClass("ProximityPrompt")
		if not proxi then continue end
		proxi.ActionText = LABEL_OPEN
		proxi.KeyboardKeyCode=Enum.KeyCode.E
		local delay = button:GetAttribute("TimeoutClose") or TIMEOUT_CLOSE

		proxi.Triggered:Connect(function(player)
			-- Ouverture ou fermeture de la porte
			
			print("ouverture porte")
		end)
	end
end

Lance ton jeu, quand tu actives le proximitry prompt, le message suivant s’affiche dans la console de sortie mais la porte ne s’ouvre pas encore :

Modifie ton code pour ouvrir la porte :

-- Récupération du joueur
local Players = game:GetService("Players")

-- Configuration
local TIMEOUT_CLOSE = 0
local LABEL_CLOSE   = "Fermer"
local LABEL_OPEN    = "Ouvrir"

-- Récupération du dossier des portes
local doorsFolder = script.Parent
local sound       = doorsFolder:FindFirstChildOfClass("Sound")

-- Lecture du son d'ouverture de la porte
local function playSound()
	if not sound then return end
	pcall(function() sound:Play() end)
end

-- Ouverture ou fermeture d'une porte
local function setDoor(door, isOpen)
	door.Transparency = isOpen and 1 or 0
	door.CanCollide   = not isOpen
end

-- Mise à jour du texte des proximity prompt des boutons
local function setActionText(door)
	-- Pas de fermeture automatique
	for _, button in door:GetChildren() do
		if button:IsA("Part") then
			local proxi = button:FindFirstChildOfClass("ProximityPrompt")
			if proxi then
				proxi.ActionText = door.CanCollide and LABEL_OPEN or LABEL_CLOSE
			end
		end
	end

end

-- Activation ou désactivation des proximity prompts des boutons
local function setEnabledProxi(door, isOpen)
	-- Pas de fermeture automatique
	for _, button in door:GetChildren() do
		if button:IsA("Part") then
			local proxi = button:FindFirstChildOfClass("ProximityPrompt")
			proxi.Enabled = isOpen			
		end
	end	
end

-- Initialisation de chaque porte
-- Le dossier doit comporte un part pour la porte
-- puis un part pour chaque bouton
-- puis proxymity prompt pour chaque bouton
for _, door in doorsFolder:GetChildren() do
	if not door:IsA("Part") then continue end
	door.Anchored     = true
	door.Transparency = 0
	door.CanCollide   = true

	for _, button in door:GetChildren() do
		if not button:IsA("Part") then continue end
		button.Anchored     = true
		button.Transparency = 0
		button.CanCollide   = true		
		local proxi = button:FindFirstChildOfClass("ProximityPrompt")
		if not proxi then continue end
		proxi.ActionText = LABEL_OPEN
		proxi.KeyboardKeyCode=Enum.KeyCode.E
		local delay = button:GetAttribute("TimeoutClose") or TIMEOUT_CLOSE

		proxi.Triggered:Connect(function(player)
			-- Ouverture ou fermeture de la porte
			playSound()
			setDoor(door, door.CanCollide)

			if delay > 0 then
				-- Décompte pour fermeture automatique
				setEnabledProxi(door, false)
				task.delay(delay, function()
					setDoor(door, false)
					setEnabledProxi(door, true)
					playSound()
				end)
			else
				-- Pas de fermeture automatique
				setActionText(door)
			end
		end)
	end
end

Lance ton jeu et regarde l’ouverture de ta porte.

Modifie dans ton script la valeur de cette constante :

local TIMEOUT_CLOSE = 3

Lance ton jeu et regarde le comportement de ta porte.

Duplique les boutons d’ouverture :

Lance ton jeu, et essaye tous les boutons d’ouverture.

Construis un décor autour de ta porte :

Crée une arborescence sous la forme d’un folder sous ta porte pour ranger la structure qui entoure celle-ci :

Tu peux dupliquer ta porte et ainsi avoir tout un système de portes dans ton jeu :

Puis différencier les portes :

Modifie ton code pour prendre en compte un ClickDetector sur un bouton :

Modifie ton script pour tester si le bouton a un promixityPrompt ou un clickDetector :

-- Récupération du joueur
local Players = game:GetService("Players")

-- Configuration
local TIMEOUT_CLOSE = 0
local LABEL_CLOSE   = "Fermer"
local LABEL_OPEN    = "Ouvrir"

-- Récupération du dossier des portes
local doorsFolder = script.Parent
local sound       = doorsFolder:FindFirstChildOfClass("Sound")

-- Lecture du son d'ouverture de la porte
local function playSound()
	if not sound then return end
	pcall(function() sound:Play() end)
end

-- Ouverture ou fermeture d'une porte
local function setDoor(door, isOpen)
	door.Transparency = isOpen and 1 or 0
	door.CanCollide   = not isOpen
end

-- Mise à jour du texte des proximity prompt des boutons
local function setActionText(door)
	-- Pas de fermeture automatique
	for _, button in door:GetChildren() do
		if button:IsA("Part") then
			local proxi = button:FindFirstChildOfClass("ProximityPrompt")
			if proxi then
				proxi.ActionText = door.CanCollide and LABEL_OPEN or LABEL_CLOSE
			end
		end
	end

end

-- Activation ou désactivation des proximity prompts des boutons
local function setEnabledProxi(door, isOpen)
	-- Pas de fermeture automatique
	for _, button in door:GetChildren() do
		if button:IsA("Part") then
			local proxi = button:FindFirstChildOfClass("ProximityPrompt")
			if proxi then 
				proxi.Enabled = isOpen
			end
		end
	end	
end

-- Logique de déclenchement commune
local function connectTrigger(door, button, onTriggered)
	local delay = button:GetAttribute("TimeoutClose") or TIMEOUT_CLOSE

	onTriggered(function()
		-- Ouverture ou fermeture de la porte
		playSound()
		setDoor(door, door.CanCollide)

		if delay > 0 then
			-- Décompte pour fermeture automatique
			setEnabledProxi(door, false)
			task.delay(delay, function()
				setDoor(door, false)
				setEnabledProxi(door, true)
				playSound()
			end)
		else
			-- Pas de fermeture automatique
			setActionText(door)
		end
	end)

end



-- Initialisation de chaque porte
-- Le dossier doit comporte un part pour la porte
-- puis un part pour chaque bouton
-- puis proxymity prompt pour chaque bouton
for _, door in doorsFolder:GetChildren() do
	if not door:IsA("Part") then continue end
	door.Anchored     = true
	door.Transparency = 0
	door.CanCollide   = true

	for _, button in door:GetChildren() do
		if not button:IsA("Part") then continue end
		button.Anchored     = true
		button.Transparency = 0
		button.CanCollide   = true	
		--test si le bouton a un proximity prompt ou un click detector
		local proxi = button:FindFirstChildOfClass("ProximityPrompt")
		local clicker = button:FindFirstChildOfClass("ClickDetector")

		if proxi then
			proxi.ActionText = LABEL_OPEN
			proxi.KeyboardKeyCode=Enum.KeyCode.E
			connectTrigger(door, button, function(callback)
				proxi.Triggered:Connect(function(player)
					callback()
				end)
			end)

		elseif clicker then
			connectTrigger(door, button, function(callback)
				clicker.MouseClick:Connect(function(player)
					callback()
				end)
			end)

		else
			warn("[DoorManager] Aucun ProximityPrompt ni ClickDetector sur :", button:GetFullName())
		end
		
	end
end