Valve Wheel not working as expected

I am trying to get a valve to spin with a Proximity Prompt, but the wheel gets stuck a few seconds after spinning.
Here is a video of the problem:


I have tried everything, including defining a variable with the current orientation and adding that to the orientation of the wheel.
I am confused and I do not know what is causing this bug.
Here is my code:

local Spinning
local current_oreintation
script.Parent.Wheel.ProximityPrompt.PromptButtonHoldEnded:Connect(function()
	Spinning = false
end)
script.Parent.Wheel.ProximityPrompt.PromptButtonHoldBegan:Connect(function()
	Spinning = true
	while true do
		task.wait()
		if Spinning == false then break end
		current_oreintation = script.Parent.Wheel.Orientation
		script.Parent.Wheel.Orientation += Vector3.new(0.5,0,0)
		script.Parent.Cylinder.Orientation += Vector3.new(0.5,0,0)
	end
end)

Can anyone help?

1 Like

Hello. I think you need to use other proximity prompt state to connect function, because holdbegan acts like a button, only when u started holding, and after a second it stops, even while u still hold down the button.
Sadly cannot help in other way.

I looked at the docs here:

The 2 actions I used are the only actions for detecting if the player is holding it down, or not holding it anymore.

Well, after some thinking, I got idea of how you can fix valve.
First, make any kind of loop or function on proximityprompt.buttonholdbegan that will set spinning to true.
Second make another any kind of loop or function but with proximityprompt.buttonholdended and make so it sets spinning to false.
And third make function that will do animation while spinning is true.

I believe the issue may be a weird thing with how you’re using Orientation. I heavily advise not using Orientation for something like this, and instead using CFrame.Angles as I have, with this as a solution:

local RunService = game:GetService("RunService")
-- Constants
-- When the player holds down the prompt
local TURN_SPEED: number = .5
-- When the player stops holding down the prompt
local TURN_BACKWARDS_SPEED: number = 4
-- Variables
local Turn_Value: number = 0
local Valve = script.Parent
-- Prompt is your ProximityPrompt
local Prompt = Valve:WaitForChild("ProximityPrompt")
local Original_Pivot: CFrame = Valve:GetPivot() -- This should be stored

local Connections: { RBXScriptConnection } = {}
-- For updating the valve angle
local function UpdateValve()
	-- As a micro-optimization, only multipliy the original CFrame by the spin value if it's greater than 0
	Valve:PivotTo(if Turn_Value > 0 then Original_Pivot * CFrame.Angles(0, 0, Turn_Value) else Original_Pivot)
end
-- Shorthand function for disconnecting all connections
local function DisconnectAll()
	for Index: number, Connection: RBXScriptConnection in Connections do
		-- Since :Disconnect() returns nil, this knocks out two things in one,
		--   making the table index nil and disconnecting the connection
		Connections[Index] = Connection:Disconnect()
	end
end
-- Then, set up connections
Prompt.PromptButtonHoldEnded:Connect(function()
	DisconnectAll()
	-- Makes the valve spin back to its original orientation
	table.insert(Connections, RunService.Heartbeat:Connect(function(Elapsed: number)
		-- What math.max does is get the maximum value of two or more values
		-- In this case, it's the Spin_Value subtracted by the turn speed and 0, which stops Spin_Value from going below 0
		Turn_Value = math.max(Turn_Value - (Elapsed * TURN_BACKWARDS_SPEED), 0)
		UpdateValve()
		
		if Turn_Value <= 0 then
			DisconnectAll()
		end
	end))
end)
Prompt.PromptButtonHoldBegan:Connect(function()
	DisconnectAll()
	table.insert(Connections, RunService.Heartbeat:Connect(function(Elapsed: number)
		-- What this does is add the turn speed to Turn_Value
		--   The modulo (%) operator makes it repeat if it's greater than or equal to pi
		Turn_Value = (Turn_Value + (Elapsed * TURN_SPEED)) % math.pi
		UpdateValve()
	end))
end)

Result:

All of the code I provided should hopefully help you understand what does what. And, as a slight warning, the snippet CFrame.Angles(0, 0, Turn_Value) may provide the wrong axis rotation. If so, just move it to a different 0, i.e CFrame.Angles(0, Turn_Value, 0). Here’s something funny that happened while I was trying to figure that out:

I hope this helps.

If you also wanted something that more directly correlates to the Prompt’s HoldDuration, and something with fixed math (oops…), try this:

local RunService = game:GetService("RunService")
-- Constants
-- When the player stops holding down the prompt
local TURN_BACKWARDS_SPEED: number = .5
-- Variables
local Turn_Value: number = 0
local Finished: boolean = false

local Valve = script.Parent
-- Prompt is your ProximityPrompt
local Prompt = Valve:WaitForChild("ProximityPrompt")
local Original_Pivot: CFrame = Valve:GetPivot() -- This should be stored

local Connections: { RBXScriptConnection } = {}
-- For updating the valve angle
local function UpdateValve()
	-- As a micro-optimization, only multipliy the original CFrame by the spin value if it's greater than 0
	Valve:PivotTo(if Turn_Value > 0 then Original_Pivot * CFrame.Angles(0, 0, math.rad(Turn_Value * 360)) else Original_Pivot)
end
-- Shorthand function for disconnecting all connections
local function DisconnectAll()
	for Index: number, Connection: RBXScriptConnection in Connections do
		-- Since :Disconnect() returns nil, this knocks out two things in one,
		--   making the table index nil and disconnecting the connection
		Connections[Index] = Connection:Disconnect()
	end
end
local function FinishValve()
	DisconnectAll()
	
	Finished = true
	Turn_Value = 0
	
	UpdateValve()
end
-- Then, set up connections
Prompt.PromptButtonHoldEnded:Connect(function()
	if not Finished then
		DisconnectAll()
		
		Prompt.Enabled = false
		-- Makes the valve spin back to its original orientation
		table.insert(Connections, RunService.Heartbeat:Connect(function(Elapsed: number)
			-- What math.max does is get the maximum value of two or more values
			-- In this case, it's the Spin_Value subtracted by the turn speed and 0, which stops Spin_Value from going below 0
			Turn_Value = math.max(Turn_Value - (Elapsed * TURN_BACKWARDS_SPEED), 0)
			UpdateValve()

			if Turn_Value <= 0 then
				DisconnectAll()
				Prompt.Enabled = true
			end
		end))
	end
end)

Prompt.Triggered:Connect(FinishValve)
Prompt.PromptButtonHoldBegan:Connect(function()
	DisconnectAll()
	table.insert(Connections, RunService.Heartbeat:Connect(function(Elapsed: number)
		-- What this does is add the turn speed to Turn_Value
		--   The modulo (%) operator makes it repeat if it's greater than or equal to pi
		Turn_Value = (Turn_Value + (Elapsed * (1 / Prompt.HoldDuration))) % 1
		UpdateValve()
		
		if Turn_Value >= 1 then
			return FinishValve()
		end
	end))
end)
1 Like

I made concept of script

local spinning = false
-- any other local values

proximityprompt.buttonholdbegan:connect(function()
wait()
spinning = true
wait(hold duration time)  -- fixes infinite animation if it happens
spinning = false
end)
proximityprompt.buttonholdended:connect(function()
wait()
spinning = false
     -- insert any other code if needed
end)
-- create your spin animation function here

Thank you, from your solution I learned why I should not use orientation in the way I was using it.

1 Like

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