Door AI Mechanic

Hi there, I have tried to make a Door AI for my new game. I have no idea how can i do this. I want to make a Door that with time will slowly progress to another phase, and will reset it’s phases once resetting the door with ProximityPrompt. I also want it to Tween the door with each phase, but i have no idea how to make it. I made a small part of the code, I would appreciate every bit of help.

The sample of the code:

Note: it isn’t the best code, i made it for testing purposes. You can correct my mistakes if you want.

local function RollRandom()
	repeat
		task.wait(math.random(minOpenTime, maxOpenTime))
		local success = math.random(1, 15)
		if success < 4 then
			doorCurrentPos += 1
			Close.Enabled = true
			print("Moved")
		end
	until doorCurrentPos == doorMaxPos
end

local function TriggerFunction()
	Close.Enabled = false
	doorCurrentPos = 1
	TweenDoor(tweens.Barrier, 0.5)
end

RollRandom()
Close.Triggered:Connect(TriggerFunction)

Hello! Can you please elaborate on the expected result? I understand the role of the proximity prompt, but what exactly are phases? Perhaps a drawing of the door’s function would help.

Edit. @NoisyDawid123456 alright, I’ll think about it and reply in short, thanks.

1 Like

“The phases” are just positions of the door, which i want to tween the door to. Like the door is slightly opened, more opened, half opened and fully opened.

1 Like

@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)

2 Likes

Thank you for help! I made it somehow

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.