Better approach to this

I’m making a door system but I don’t wanna use script for each attachment and each door so I went for PromptTriggered the problem is it triggers for each door and I don’t want that, not to mention it is really buggy. Is there a better approach to this? Bindable Events?

local hinge = script.Parent.Parent.Parent.hinges.targethinge
local lock = script.Parent:FindFirstChild("Locked")
local opened = false
local d = false
function GetClass(Child):string?
	return Child.ClassName
end
function Distance(Character:Model?, Distance: number?, InitialPart:BasePart?)
	if GetClass(Character) ~= "Model" then warn("Not a Character model!") return nil end
	if type(Distance) ~= "number" then warn(Distance.. " is not a number!") return nil end
	if typeof(InitialPart) ~= "Instance" then warn(InitialPart.. " is not an instance.. somehow..?") return nil end
	assert(Character.HumanoidRootPart, "HRP doesn't exist yet.")
	assert(InitialPart.Position, tostring(InitialPart).. " doesn't have position.")
	if (Character.HumanoidRootPart.Position - InitialPart.Position).Magnitude <= Distance then return true end
end 
local T = math.huge
local Door = {
	["Lock"] = function(Player:Player?, Part:BasePart?, Prom)
		if lock.Value == false and Distance(Player.Character, 15, Part) and not d then
			d = true
			Prom.ActionText = "LOCKED"
			lock.Value = true
			print("locked")
			d = false
		else
			Prom.ActionText = ""
			lock.Value = false
			print("unlocked")
			d = false
		end
	end,
	["Knock"] = function(Player:Player?, Part:BasePart?) 
		if Distance(Player.Character, 15, Part) then
			print("Knock")
		end
	end,
	["Open"] = function(Player:Player?, Part:BasePart?)
		if Distance(Player.Character, 7, Part) then
			if Part:FindFirstChild("Locked").Value == false then
				if not opened then
					opened = true
					script.Parent.Lock.ProximityPrompt.Enabled = false
					script.Parent.Knock.ProximityPrompt.Enabled = false
					local TweenService = game:GetService("TweenService")
					local TI = TweenInfo.new(0.835, Enum.EasingStyle.Sine, Enum.EasingDirection.Out, 0)
					local Goal = {CFrame = script.Parent.Parent.Parent.hinges.hingewantedposition.CFrame}
					local Animation = TweenService:Create(hinge, TI, Goal)
					Animation:Play()
				else
					script.Parent.Lock.ProximityPrompt.Enabled = true
					script.Parent.Knock.ProximityPrompt.Enabled = true
					opened = false
					local TweenService = game:GetService("TweenService")
					local TI = TweenInfo.new(0.835, Enum.EasingStyle.Sine, Enum.EasingDirection.Out, 0)
					local Goal = {CFrame = script.Parent.Parent.Parent.hinges.refreshhinge.CFrame}
					local Animation = TweenService:Create(hinge, TI, Goal)
					Animation:Play()
				end
			else
				print("dont open")
			end
		end
	end,
}
local Prom = game:GetService("ProximityPromptService")
Prom.PromptTriggered:Connect(function(Prompt, Player)
	print(tostring(Prompt))
	if Prompt.Parent:IsA("Attachment") then
		if Prompt.Parent:GetAttribute("IsDoor") == true then
			print(tostring(Prompt.Parent:FindFirstAncestorWhichIsA("BasePart")))
			Door[Prompt.Type.Value](Player, Prompt.Parent:FindFirstAncestorWhichIsA("BasePart"), Prompt)
			Prompt.Enabled = false
			task.delay(Prompt:GetAttribute("Cooldown"),function()
				Prompt.Enabled = true
			end)
		end
	end
end)

Also Lock function seems to run twice.

Using Bindable Events is a better approach for this type of problem. You can have a single script that listens to events and executes the corresponding function. Here’s an example of how you can implement it:

  1. Create a ModuleScript named “DoorModule” in ServerStorage(Standard is to store modules here).
  2. Add the following code to DoorModule:
  3. Modify your script to listen to events from DoorModule:
local Door = {}

function Door.Lock(player, doorPart)
	if doorPart.Locked.Value == false then
		doorPart.Locked.Value = true
		print("Locked")
	else
		doorPart.Locked.Value = false
		print("Unlocked")
	end
end

function Door.Knock(player, doorPart)
	print("Knock")
end

function Door.Open(player, doorPart)
	if doorPart.Locked.Value == false then
		local hinge = doorPart.Parent.hinges.targethinge
		local opened = doorPart.Parent.Open.Value
		local TweenService = game:GetService("TweenService")
		local TI = TweenInfo.new(0.835, Enum.EasingStyle.Sine, Enum.EasingDirection.Out, 0)
		
		if not opened then
			doorPart.Parent.Open.Value = true
			script.Parent.Lock.ProximityPrompt.Enabled = false
			script.Parent.Knock.ProximityPrompt.Enabled = false
			
			local Goal = {CFrame = hinge.hingewantedposition.CFrame}
			local Animation = TweenService:Create(hinge, TI, Goal)
			Animation:Play()
		else
			script.Parent.Lock.ProximityPrompt.Enabled = true
			script.Parent.Knock.ProximityPrompt.Enabled = true
			doorPart.Parent.Open.Value = false
			
			local Goal = {CFrame = hinge.refreshhinge.CFrame}
			local Animation = TweenService:Create(hinge, TI, Goal)
			Animation:Play()
		end
	else
		print("Door is locked")
	end
end

return Door

This goes in ServerScriptService.

local DoorModule = require(ServerScriptService.DoorModule)

local function onPromptTriggered(prompt, player)
	local doorPart = prompt.Parent:FindFirstAncestorWhichIsA("BasePart")
	local promptType = prompt.Type.Value
	DoorModule[promptType](player, doorPart)
end

local function onPromptCooldownEnded(prompt)
	prompt.Enabled = true
end

local function onPromptEnabledChanged(prompt)
	if prompt.Enabled then
		prompt.Cooldown = 0.5 -- Change this to your desired cooldown time
	end
end

local Prom = game:GetService("ProximityPromptService")
Prom.PromptTriggered:Connect(onPromptTriggered)
Prom.PromptCooldownEnded:Connect(onPromptCooldownEnded)
Prom.PromptEnabledChanged:Connect(onPromptEnabledChanged)

With this approach, you can easily add new door functions to the DoorModule without modifying the script that listens to events.

1 Like