Tweening/Script not working

At this point I’m desperate to get this script working so, any recommendations will help greatly.

This script is meant to make a spotlight model move, more like an actual spotlight. Smooth and realistic. Yet, with my current skills (close to no skill), this is difficult just trying to change an original script I got help with.

(I apologize for this horribly messy script, I need a lot of help)

if not game:IsLoaded() then game.Loaded:Wait() end

local userInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")
local SpotlightHead = game.Workspace.Spotlight.Arm.Head
local UpdateCon

local moveStart = SpotlightHead:GetPivot()
local moveEnd = moveStart * CFrame.Angles(1, 0, 0)

local tweenInfo = TweenInfo.new(
	0.5,
	Enum.EasingStyle.Quad,
	Enum.EasingDirection.Out,
	-1,
	true,
	0
)

local tweenStart = TweenService:Create(SpotlightHead, tweenInfo, {CFrame = moveEnd})
local tweenStop = TweenService:Create(SpotlightHead, tweenInfo, {CFrame = moveStart})

userInputService.InputBegan:Connect(function(input, gameProcessedEvent)
	if input.UserInputType ~= Enum.UserInputType.Keyboard then return end
	if input.KeyCode ~= Enum.KeyCode.KeypadEight then return end

	if UpdateCon then
		UpdateCon:Disconnect()
		UpdateCon = nil
	end

	UpdateCon = RunService.Heartbeat:Connect(function(dt)
		tweenStart:Play()
		SpotlightHead:SetPrimaryPartCFrame(moveStart)
	end)
end)

userInputService.InputEnded:Connect(function(input, gameProcessedEvent)
	if input.UserInputType ~= Enum.UserInputType.Keyboard then return end
	if input.KeyCode ~= Enum.KeyCode.KeypadEight then return end
	if not UpdateCon then return end
	
	tweenStop:Play()

	UpdateCon:Disconnect()
	UpdateCon = nil
end)

Currently, there is an error at the time of testing this script:

(just to dumb it down for easier reference, the original script moved the spotlight model abruptly, which didn’t sit right with me, so I wanted to make it so when it started moving (via a keybind) i wanted it to speed up to a number, lets say 1, and when i released, slow it down back to 0, making it feel more smooth)

Here is how it originally looked for reference:

If anyone can provide any possible solution (or give tips to clean up this garbage code), I will genuinely appreciate you, and leave likes on comments that helped. :slight_smile:

I assume that object ‘Head’ is the variable SpotlightHead.
Elsewhere in the script, you called SpotlightHead:SetPrimaryPartCFrame(moveStart), which is only callable on models, not baseparts. In the tween, instead of using SpotlightHead, consider trying SpotlightHead.PrimaryPart instead.

Note that it may cause issues with it being seperate to other parts of the light. If this happens, make everything but the primary part unanchored, and just weld everything together!

Hmm… I’ll try to come up with a script that might solve this problem.

This might take a little longer, but I’ll come up with something scalable.

I think this should fix the problem:

if not game:IsLoaded() then game.Loaded:Wait() end

local userInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")
local SpotlightHead = game.Workspace:WaitForChild("Spotlight").Arm.Head

local keyCodes = {
	up = {key = Enum.KeyCode.KeypadEight, m = {1, 0, 0}},
	down = {key = Enum.KeyCode.KeypadTwo, m = {-1, 0, 0}},
	left = {key = Enum.KeyCode.KeypadFour, m = {0, 1, 0}},
	right = {key = Enum.KeyCode.KeypadFive, m = {0, -1, 0}}
}

local tweenInfo = TweenInfo.new(
	0.5,
	Enum.EasingStyle.Quad,
	Enum.EasingDirection.Out,
	0,
	false,
	0
)

local CFrameValue = Instance.new("CFrameValue"); CFrameValue.Value = SpotlightHead:GetPivot()

userInputService.InputBegan:Connect(function(input, gameProcessedEvent)
	if input.UserInputType ~= Enum.UserInputType.Keyboard then return end
	
	local dir, currKey
	for i, v in pairs(keyCodes) do
		if input.KeyCode == v.key then
			currKey = v.key
			dir = v.m
		end
	end
	
	if not currKey then return end
	
	local keyUp = false
	local keyUpListener
	keyUpListener = userInputService.InputEnded:Connect(function(input2, gpe2)
		if input2.KeyCode == currKey then
			keyUp = true
			keyUpListener:Disconnect()
		end
	end)
	
	local tweenStart
	repeat
		CFrameValue.Value = SpotlightHead:GetPivot()
		tweenStart = TweenService:Create(CFrameValue, tweenInfo, {Value = CFrameValue.Value * CFrame.Angles(table.unpack(dir))})
		tweenStart:Play()
		local changed = CFrameValue.Changed:Connect(function()
			SpotlightHead:PivotTo(CFrameValue.Value)
		end)
		tweenStart.Completed:Once(function()
			changed:Disconnect()
		end)
		RunService.Heartbeat:Wait()
	until keyUp
end)

(I am trying to guess the hierarchy of the Spotlight object.)

You can adjust the speed by changing the one’s inside m.
It also simulates physical motors vibrating with two opposing inputs. (Epic example of a bug becoming a feature)

This does work, however, there is another issue.
As I’ll show you here, it does move based on the set tween, but it doesn’t follow the change of the arm during the tween.

If it makes sense visually, you can tell that the head stops during the tween, then after the tween is finished, then follows the arm. How can I make it so it always follows the arm angle?

I see. I think the problem is these lines:

I think the problem is the tween overwriting the parent’s movement while tweening, so you should try changing those lines to:
CFrameValue.Value = SpotlightHead:GetPivot() * SpotlightArm:GetPivot().Rotation

And see if it works.

Didn’t seem to work. With your added “SpotlightArm” instance, I added this:

local SpotlightArm = game.Workspace:WaitForChild("Spotlight").Arm

Under the initial location of the head, just to tell it which is the arm, but it didn’t change much.
Not sure if this was the intended solution, but let me know.

I also tried implementing this in the scripts that control both the arm and the head, but that didn’t work either.

I think that’s unfortunately the quirks of tween service. You’ll need Motor6Ds to properly do this.

If I recall correctly, this would require connecting the two parts with a motor, and then editing it via a script with the same tween?

Correct! It does require two parts to be connected to the motor. You can also modify that existing script to tween the motors. Also, you can set which object to be tweened by adding an extra instance = (head), then add a variable on the key selector (the for i, v) to initialize that instance and modify the instance that is being tweened to be that variable.

I just quickly edited the script to get the Motor6D that I implemented into the Arm part of the spotlight, and made part 0 the Arm’s primary part, and part 1 the head’s primary part (not sure if this is the correct ones to use)

if not game:IsLoaded() then game.Loaded:Wait() end

local userInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")
local SpotlightArm = game.Workspace:WaitForChild("Spotlight").Arm.Motor6D

local keyCodes = {
	up = {key = Enum.KeyCode.KeypadFour, m = {0, 0.5, 0}},
}

local tweenInfo = TweenInfo.new(
	0.2,
	Enum.EasingStyle.Quad,
	Enum.EasingDirection.Out,
	0,
	false,
	0
)

local CFrameValue = Instance.new("CFrameValue"); CFrameValue.Value = SpotlightArm:GetPivot()

userInputService.InputBegan:Connect(function(input, gameProcessedEvent)
	if input.UserInputType ~= Enum.UserInputType.Keyboard then return end

	local dir, currKey
	for i, v in pairs(keyCodes) do
		if input.KeyCode == v.key then
			currKey = v.key
			dir = v.m
		end
	end

	if not currKey then return end

	local keyUp = false
	local keyUpListener
	keyUpListener = userInputService.InputEnded:Connect(function(input2, gpe2)
		if input2.KeyCode == currKey then
			keyUp = true
			keyUpListener:Disconnect()
		end
	end)

	local tweenStart
	repeat
		CFrameValue.Value = SpotlightArm:GetPivot()
		tweenStart = TweenService:Create(CFrameValue, tweenInfo, {Value = CFrameValue.Value * CFrame.Angles(table.unpack(dir))})
		tweenStart:Play()
		local changed = CFrameValue.Changed:Connect(function()
			SpotlightArm:PivotTo(CFrameValue.Value)
		end)
		tweenStart.Completed:Once(function()
			changed:Disconnect()
		end)
		RunService.Heartbeat:Wait()
	until keyUp
end)

This script shows an error though.

Here is the hierarchy of the model.
Screen Shot 2023-11-27 at 11.25.40 PM

Let me know if there is any way to fix this.

You should try changing :GetPivot() to .C1 or .C0 to find which works.

C0 is the motor’s CFrame of Part0, and C1 is the same, but with Part1


What do I change “PivotTo” to?

You can delete the CFrameValues, then change the property table of tweenStart to C1 or C0 (depending on your part0,part1). You can also delete the changed function and the .completed function.

If the other parts seem to not move, try welding them.

If it does not move at all, try unanchoring everything except the base after welding.


Is that getting rid of these two?

Correct. Those functions won’t be needed anymore.

The welding part is where I can’t really do much, for some reason every which way I have welded parts, either to each other to keep everything in-tact, or to the part that correlates with .C0 or .C1, would just rotate the entire model up and down, and not left and right.

Did you weld everything instead of each group? The motor also keeps it in place, so there’s no need to weld the arm to the head.

Yeah, I even made it so I only welded everything to their primary parts, unanchored the Arm and Head, not the base, then welded the Arm’s primary part to the base, which kept it all together.
Yet, it still rotates the entire model.

(also i dont usually ask this cause it feels like it’s against some rules, but if you have time at any point i could give you the place so it’s easier to figure out the hierarchy and positions of everything just for ease of access, and to see if the script is properly doing something (which it probably is at this point), and it’s okay if not possible)

(this is also just so this post doesn’t get flooded too far)