@NoisyDawid123456 I had an unexpected meeting so I’m sending this with a delay. I hope this wasn’t too much of an inconvenience.
Because of the various angles and transition times, the idea of using tweens seemed rather inefficient. I’m introducing a bit different approach utilizing hinge constraint.
The idea is a bit difficult to explain in short, so I made a quick example I’m appending below.
There’s a simple door consisting of three parts (DoorFrame, DoorHinge and DoorBase). DoorFrame represents the root any other moving part of the door would be welded to. This root is then welded to the DoorHinge, and everything but the base is unanchored.
Between the DoorBase and DoorHinge, a HingeConstraint
is installed, with limited upper and lower angle, servo actuator type etc.
The script then moves the door to various angles in a loop. Once the proximity prompt is triggered, the locked_for_closing
condition halts the loop and prioritizes the closing of the door (resetting), before resuming the endless cycle.
One of the problems is detecting when the target angle
was reached, for there’s no event such as tween.Completed
available. I found a solid workaround is active checking with a reasonable wait time like .1 seconds. Because of the potential deviation and floating point errors, we can’t check exact goals, but rather an approximation.
Without further ado, here are the script and the file. I tried to keep the code self explainatory and added some comments for support.
Script
-- Angles and velocities to randomly choose from.
ANGLES = {30, 60, 90, 110}
VELOCITIES = {.5, 1, 1.5, 2}
local door = workspace.Door
local doorBase = door.Base
local doorHinge = door.DoorHinge
local hinge = doorHinge.HingeConstraint
local proxPrompt = door.DoorFrame.ProximityPrompt
-- In case the door is rotated.
local defaultDoorHingeAngleY = doorHinge.Orientation.Y
local RandomGen = Random.new()
local targetAngle = 0
local locked_for_closing = false
hinge.TargetAngle = 0
proxPrompt.Enabled = false
local function WaitForAlignment()
local cachedTarget = targetAngle
if doorHinge.Orientation.Y - defaultDoorHingeAngleY > targetAngle then
repeat task.wait(.1)
-- If target has changed, abort.
if cachedTarget ~= targetAngle then return; end
until doorHinge.Orientation.Y - defaultDoorHingeAngleY < targetAngle +2
else
repeat task.wait(.1)
if cachedTarget ~= targetAngle then return; end
until doorHinge.Orientation.Y - defaultDoorHingeAngleY > targetAngle -1
end
task.wait(.1)
end
local function RollRandom()
local cachedAngle = targetAngle
repeat
targetAngle = ANGLES[RandomGen:NextInteger(1, #ANGLES)]
until targetAngle ~= cachedAngle -- prevent duplicates
hinge.AngularVelocity = VELOCITIES[RandomGen:NextInteger(1, #VELOCITIES)]
hinge.TargetAngle = targetAngle
end
local function OnProxPromptTrigger(player: Player?)
locked_for_closing = true -- halt the main loop
proxPrompt.Enabled = false
targetAngle = 0
hinge.TargetAngle = targetAngle
WaitForAlignment()
task.wait(1)
-- Perform the first opening.
RollRandom(); WaitForAlignment()
proxPrompt.Enabled = true
locked_for_closing = false
end
proxPrompt.Triggered:Connect(OnProxPromptTrigger)
OnProxPromptTrigger()
task.spawn(function()
while true do
if not locked_for_closing then
RollRandom(); WaitForAlignment()
end
task.wait(1)
end
end)
RBXM file (drag and drop): NaughtyDoor.rbxm (7.3 KB)