Flashlight ring jitters, need help

Hello,

As the title states, I’m trying to figure out how to make the flashlight ring stop jittering.

Script:

local UIS = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local HttpService = game:GetService("HttpService")
local LocalPlayer = game.Players.LocalPlayer
local Cam = workspace.CurrentCamera
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")

local Flashlight = ReplicatedStorage:WaitForChild("Flashlight")
local Brightness = 20
local Toggle = false
local canTick = false
local hasFlashlight = false

local tweenInfOn = TweenInfo.new(0.3, Enum.EasingStyle.Sine)
local tweenInfOff = TweenInfo.new(0.15, Enum.EasingStyle.Sine)

local clonedFlashlight

local spotLightAngle = 100
local spotLightRange = 27.6

local function toggle()
	if not hasFlashlight then
		clonedFlashlight = Flashlight:Clone()

		local character = LocalPlayer.Character
		if character and character:FindFirstChild("Head") then
			local head = character.Head

			local frontAttachment = head:FindFirstChild("FrontAttachment")
			if not frontAttachment then
				frontAttachment = Instance.new("Attachment")
				frontAttachment.Name = "FrontAttachment"
				frontAttachment.Position = Vector3.new(0, 0, 0)
				frontAttachment.Parent = head
			end

			clonedFlashlight.CFrame = frontAttachment.WorldCFrame
			clonedFlashlight.Anchored = false
			clonedFlashlight.Parent = head

			local weld = Instance.new("WeldConstraint")
			weld.Part0 = clonedFlashlight
			weld.Part1 = head
			weld.Parent = clonedFlashlight

			hasFlashlight = true
		else
			warn("Head not found on character")
			clonedFlashlight:Destroy()
			clonedFlashlight = nil
			hasFlashlight = false
			return
		end
	end

	if Toggle == false then
		Toggle = true
		script.On:Play()
		canTick = true
	else
		Toggle = false
		script.Off:Play()
		canTick = false

		if clonedFlashlight then
			clonedFlashlight:Destroy()
			clonedFlashlight = nil
			hasFlashlight = false
		end
	end
end

local function toggleOnDeath()
	if Toggle == true then
		Toggle = false
		script.Off:Play()
		canTick = false

		if clonedFlashlight then
			clonedFlashlight:Destroy()
			clonedFlashlight = nil
			hasFlashlight = false
		end
	end
end

local function onFlashlight(input, gameProcessed)
	if gameProcessed then return end

	if shared.keybindActionsLoaded then
		local keybindActions = LocalPlayer:FindFirstChild("Keybind_Actions")

		if keybindActions then
			local flashlightKeybind = keybindActions:FindFirstChild("Flashlight") and HttpService:JSONDecode(keybindActions["Flashlight"].Value) or nil

			if flashlightKeybind then
				if table.find(flashlightKeybind, input.UserInputType.Name) then
					toggle()
				elseif input.KeyCode then
					if table.find(flashlightKeybind, input.KeyCode.Name) then
						toggle()
					end
				end
			end
		end
	end
end

UIS.InputBegan:Connect(onFlashlight)

if UIS.TouchEnabled then
	local mobileButton = LocalPlayer.PlayerGui:WaitForChild("MobileButton")
	mobileButton.FlashlightButton.MouseButton1Down:Connect(function()
		toggle()
	end)
end

RunService.RenderStepped:Connect(function(deltaTime)
	if clonedFlashlight and Toggle then
		Brightness = math.clamp(Brightness + (0.5 * deltaTime), 0, 1)
		local spotLight = clonedFlashlight:FindFirstChild("SpotLight")

		if spotLight then
			spotLight.Shadows = true
			spotLight.Angle = spotLightAngle
			spotLight.Range = spotLightRange
			TweenService:Create(spotLight, tweenInfOn, {Brightness = Brightness}):Play()
		end
	elseif clonedFlashlight then
		local spotLight = clonedFlashlight:FindFirstChild("SpotLight")
		if spotLight then
			spotLight.Shadows = false
			TweenService:Create(spotLight, tweenInfOff, {Brightness = 0}):Play()
		end
	end
end)

LocalPlayer.CharacterAdded:Connect(function(character)
	local humanoid = character:WaitForChild("Humanoid")
	humanoid.Died:Connect(function()
		hasFlashlight = false
		toggleOnDeath()
	end)
end)

Video:

1 Like

It’s probably because you are attaching the flashlight to the player’s head. You should always use the camera for this, which you could do by simply parenting the light to a part and pivoting it to the camera every single frame.

I tried parenting the flashlight to cam and it still gets the same results.

I’m not necessarily talking about parenting it to the camera, but rather pivoting it to the camera every frame, so no attachments or any sort of weld used. You just need a loop that updates the light or its parent part’s CFrame to the camera’s CFrame every frame.

I understand but it just returns the same results , you can give it a go if you’d like or not. I’ve been stuck on this for a minute, I can’t seem to figure it out.

I tested the following code, and it seems to work perfectly fine:

local RunService = game:GetService("RunService")

local function makeLight()
	local holder = Instance.new("Part")
	holder.Parent = workspace
	holder.CanCollide = false
	holder.CanTouch = false
	holder.CanQuery = false
	holder.Anchored = true
	holder.Transparency = 1
	holder.Size = Vector3.one
	
	local light = Instance.new("SpotLight")
	light.Parent = holder
	light.Brightness = 20
	light.Angle = 15
	
	return holder
end

repeat task.wait() until workspace.Camera
local camera = workspace.CurrentCamera
local holder = makeLight()

RunService.RenderStepped:Connect(function(dt)
	holder.CFrame = camera.CFrame
end)

Here is a video of it in action:

One important thing I’ve noticed is that Lighting.Technology matters in terms of light quality, and found that Future works the best in this case.

Now obviously I don’t have the same camera and flashlight configuration as you do, nor any real consistency with your game. However, that should not be a problem in this context as what you’re trying to do is pretty trivial in terms of complexity and should work in any game.

I feel like this is the same.

image

Script:

local UIS = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local HttpService = game:GetService("HttpService")
local LocalPlayer = game.Players.LocalPlayer
local Cam = workspace.CurrentCamera
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")

local Flashlight = ReplicatedStorage:WaitForChild("Flashlight")
local Brightness = 20
local Toggle = false
local canTick = false
local hasFlashlight = false

local tweenInfOn = TweenInfo.new(0.3, Enum.EasingStyle.Sine)
local tweenInfOff = TweenInfo.new(0.15, Enum.EasingStyle.Sine)

local clonedFlashlight

local spotLightAngle = 100
local spotLightRange = 27.6

local function toggle()
	if not hasFlashlight then
		clonedFlashlight = Flashlight:Clone()
		clonedFlashlight.CFrame = Cam.CFrame
		clonedFlashlight.Parent = Cam
		hasFlashlight = true
	end

	if Toggle == false then
		Toggle = true
		script.On:Play()
		canTick = true
	else
		Toggle = false
		script.Off:Play()
		canTick = false

		if clonedFlashlight then
			clonedFlashlight:Destroy()
			clonedFlashlight = nil
			hasFlashlight = false
		end
	end
end

local function toggleOnDeath()
	if Toggle == true then
		Toggle = false
		script.Off:Play()
		canTick = false

		if clonedFlashlight then
			clonedFlashlight:Destroy()
			clonedFlashlight = nil
			hasFlashlight = false
		end
	end
end

local function onFlashlight(input, gameProcessed)
	if gameProcessed then return end

	if shared.keybindActionsLoaded then
		local keybindActions = LocalPlayer:FindFirstChild("Keybind_Actions")

		if keybindActions then
			local flashlightKeybind = keybindActions:FindFirstChild("Flashlight") and HttpService:JSONDecode(keybindActions["Flashlight"].Value) or nil

			if flashlightKeybind then
				if table.find(flashlightKeybind, input.UserInputType.Name) then
					toggle()
				elseif input.KeyCode then
					if table.find(flashlightKeybind, input.KeyCode.Name) then
						toggle()
					end
				end
			end
		end
	end
end

UIS.InputBegan:Connect(onFlashlight)

if UIS.TouchEnabled then
	local mobileButton = LocalPlayer.PlayerGui:WaitForChild("MobileButton")
	mobileButton.FlashlightButton.MouseButton1Down:Connect(function()
		toggle()
	end)
end

RunService.RenderStepped:Connect(function(deltaTime)
	if clonedFlashlight and Toggle then

		clonedFlashlight.CFrame = Cam.CFrame

		Brightness = math.clamp(Brightness + (0.5 * deltaTime), 0, 1)
		local spotLight = clonedFlashlight:FindFirstChild("SpotLight")

		if spotLight then
			spotLight.Shadows = true
			spotLight.Angle = spotLightAngle
			spotLight.Range = spotLightRange
			TweenService:Create(spotLight, tweenInfOn, {Brightness = Brightness}):Play()
		end
	elseif clonedFlashlight then
		local spotLight = clonedFlashlight:FindFirstChild("SpotLight")
		if spotLight then
			spotLight.Shadows = false
			TweenService:Create(spotLight, tweenInfOff, {Brightness = 0}):Play()
		end
	end
end)

LocalPlayer.CharacterAdded:Connect(function(character)
	local humanoid = character:WaitForChild("Humanoid")
	humanoid.Died:Connect(function()
		hasFlashlight = false
		toggleOnDeath()
	end)
end)

You’re right, it does look to be functionally similar. I assume Ring is the “image” that is projected onto the surface of the light, however, I don’t see where/how that is handled in your code. Could that be the issue?

The ring is parented to the flashlight part and the flashlight is in replicated storage. It gets cloned and parented into workspace. The “Ring” is a union.

image

I had a similar issue to this in my game so I just welded the light morph to the humanoidrootpart but kept the light part at the players head

wdym by light morph? the ring?

morph as in an how the objects are welded to the character, I have mine setup so you place the objects based on a specific limb which is what I did

yeah, you still have me lost. do you weld the ring to the rootpart or the flashlight part?

Is the flashlight anchored? It looks like the flashlight is trying to fall down but is repositioned before it can go too far, creating a jitter effect.

no, nothing is anchored. I still dont know what the issue could be

Heres the file:

flashlight.rbxm (14.5 KB)

The script is under the Flashlight part, it goes in starterplayerscripts. If anyone can fix this issue much would be appreciated.

Make sure lighting is on Future and have 6+ graphics in order to see the ring.

Try anchoring the flashlight ring.

Sounds like they may be right!

nope, didn’t work, I’m just hoping someone downloads the file and helps assist because I have no clue.

It does not seem to be that the parts are unanchored, but rather some weird issue with lighting updates. Here is a video:


Edit: I’m not really sure if you can avoid this because it really does seem like an engine limitation/issue. I would just recommend getting rid of the ring or trying a different method.

You prob right, roblox always on something man.

Ill probably just get rid of it.