You can write your topic however you want, but you need to answer these questions:
-
What do you want to achieve?
I want to achieve a watertight door that opens and closes. The idea is:
Player triggers a prompt on the Handle. The Handle starts to spin, and so does a pole with 2 cogwheel models. While they spin, the door model slides open/close. I attached a video below how it works. In most of the cases, it works fine.
-
What is the issue? Include screenshots / videos if possible!
The issue is that if a lot of players attempt to interact with the prompt all at once, there is a chance that the door will break. It will get stuck half-way open, and the pole and handle will just spin in an endless loop (in some cases they don’t). Video provided below. To be clear, it’s pretty hard to replicate that glitch in studio - I had to use an autoclicker with 100 or sometimes 10 ms interval. And even more to that, I had to catch a right moment to stop clicking, in order to cause this bug.
-
What solutions have you tried so far? Did you look for solutions on the Creator Hub?
I have tried searching on dev forum, and I tried adding more strict flags to prevent 2 tweens from overlapping. Didn’t help.
Important information (I guess):
In the game itself, the prompt takes 2 seconds to trigger, and gets disabled for the time of tweening. However, the issue still occurs.
This is my current script
local watertightDoorFolder = script.Parent
local door = watertightDoorFolder:WaitForChild("Door")
local pole = watertightDoorFolder:WaitForChild("Pole")
local handle = watertightDoorFolder:WaitForChild("WTDHandle")
local prompt = watertightDoorFolder:FindFirstChildWhichIsA("ProximityPrompt", true)
local TweenService = game:GetService("TweenService")
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local WTDCloseEvent = ReplicatedStorage:WaitForChild("WTDCloseEvent")
local isOpen = false
local spinning = false
local busy = false --prevent double activation
local tweenInfo = TweenInfo.new(2, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut)
local function tweenDoor(targetOffset)
local doorPrimaryCFrame = door:GetPrimaryPartCFrame()
local startCFrame = doorPrimaryCFrame
local targetCFrame = startCFrame * targetOffset
local numberValue = Instance.new("NumberValue")
numberValue.Value = 0
local tween = TweenService:Create(numberValue, tweenInfo, { Value = 1 })
local doorParts = {}
local relativeOffsets = {}
for _, part in ipairs(door:GetDescendants()) do
if part:IsA("BasePart") then
table.insert(doorParts, part)
-- Save the offset from PrimaryPart
relativeOffsets[part] = door.PrimaryPart.CFrame:toObjectSpace(part.CFrame)
end
end
numberValue.Changed:Connect(function(alpha)
local newCFrame = startCFrame:Lerp(targetCFrame, alpha)
for _, part in ipairs(doorParts) do
local relOffset = relativeOffsets[part]
part.CFrame = newCFrame * relOffset
end
end)
tween:Play()
return tween
end
local function spinPole(direction)
spinning = true
local speed = math.rad(90)
if direction == "close" then
speed = -speed
end
local cogwheelModels = {}
for _, model in ipairs(pole:GetChildren()) do
if model:IsA("Model") and model.PrimaryPart then
table.insert(cogwheelModels, model)
elseif model:IsA("Model") then
warn("Cogwheel model "..model.Name.." is missing a PrimaryPart!")
end
end
local spinningPartsModel = handle:FindFirstChild("SpinningParts")
local handleSpinningModel = spinningPartsModel and spinningPartsModel:IsA("Model") and spinningPartsModel.PrimaryPart and spinningPartsModel or nil
if not handleSpinningModel and spinningPartsModel then
warn("Handle's SpinningParts model is missing a PrimaryPart!")
end
local connection
connection = RunService.Heartbeat:Connect(function(deltaTime)
if not spinning then
connection:Disconnect()
return
end
pole.CFrame = pole.CFrame * CFrame.Angles(speed * deltaTime, 0, 0)
for _, model in ipairs(cogwheelModels) do
model:PivotTo(model:GetPivot() * CFrame.Angles(speed * deltaTime * 3, 0, 0))
end
if handleSpinningModel then
handleSpinningModel:PivotTo(handleSpinningModel:GetPivot() * CFrame.Angles(speed * deltaTime * 2, 0, 0))
end
end)
end
task.delay(20, function()
spinPole("open")
local doorTween = tweenDoor(CFrame.new(0, 0, -3.162))
doorTween.Completed:Wait()
spinning = false
isOpen = true
prompt.ActionText = "Close"
end)
WTDCloseEvent.Event:Connect(function()
spinPole("close")
local doorTween = tweenDoor(CFrame.new(0, 0, 3.162))
doorTween.Completed:Wait()
spinning = false
isOpen = false
prompt.ActionText = "Open"
end)
prompt.Triggered:Connect(function(player)
if busy then
return
end
busy = true
prompt.Enabled = false
if not isOpen then
spinPole("open")
local doorTween = tweenDoor(CFrame.new(0, 0, -3.162))
doorTween.Completed:Wait()
spinning = false
isOpen = true
prompt.ActionText = "Close"
else
spinPole("close")
local doorTween = tweenDoor(CFrame.new(0, 0, 3.162))
doorTween.Completed:Wait()
spinning = false
isOpen = false
prompt.ActionText = "Open"
end
prompt.Enabled = true
busy = false
end)
If you have any questions or if you need some information, feel free to ask!