this is a flashlight script for a horror game, the sound and pointlight are children of the local script, the client-sided script is located in Startercharacterscripts
script:
local uis = game:GetService("UserInputService")
local sfx = script.Sound
local light = script.Light
local plr = game:GetService("Players").PlayerAdded:Wait()
local char = plr.Character
local torso = char:WaitForChild("Torso")
uis.InputBegan:Connect(function(inp, gpe)
if gpe then return end
if inp.KeyCode == Enum.KeyCode.F then
sfx:Play()
light.Parent =torso
light.Enabled = not light.Enabled
end
end)
local plr = game:GetService("Players").PlayerAdded:Wait()
This line will wait for a new player to join and assign that as plr. I think the player you are looking for in this case is Players.LocalPlayer.
However, you don’t seem to use plr for anything other than getting the character so you don’t need it. Since scripts in StarterCharacterScripts get cloned and the clone is parented to the character, you can get the character in the following way
local char = script.Parent
Here’s the whole edited code (only changes are removing one line and changing another line).
local uis = game:GetService("UserInputService")
local sfx = script.Sound
local light = script.Light
local char = script.Parent
local torso = char:WaitForChild("Torso")
uis.InputBegan:Connect(function(inp, gpe)
if gpe then return end
if inp.KeyCode == Enum.KeyCode.F then
sfx:Play()
light.Parent =torso
light.Enabled = not light.Enabled
end
end)
If you only want light on the front side of torso, you can use a SurfaceLight or a SpotLight. They both have a face property. Set it to Enum.NormalId.Front. They also have an angle property to define how wide the light cone will be.
Then you shouldn’t parent the light to the torso. Lights can be parented to attachments too.
Is it okay for your use case if the light originates from the camera position? If it’s okay then you can create an attachment, parent it to workspace.Terrain and parent the light to the attachment. Then, every frame, update Attachment.CFrame to be equal to the camera CFrame.
Otherwise, parent the Attachment to whichever part the light should originate from. Then you could get the world position of the mouse and calculate the attachments CFrame every frame in the following way:
If the light is a PointLight, you should first change it to a SpotLight.
local uis = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local sfx = script.Sound
local light = script.Light
local char = script.Parent
local torso = char:WaitForChild("Torso")
local runServiceConnection
local attachment = Instance.new("Attachment")
light.Face = Enum.NormalId.Front
light.Parent = attachment
attachment.Parent = workspace.Terrain
local function updateAttachmentCFrame()
attachment.CFrame = workspace.CurrentCamera.CFrame
end
if light.Enabled then
runServiceConnection = RunService.PreRender:Connect(updateAttachmentCFrame)
end
uis.InputBegan:Connect(function(inp, gpe)
if gpe then return end
if inp.KeyCode == Enum.KeyCode.F then
sfx:Play()
light.Enabled = not light.Enabled
if light.Enabled then
runServiceConnection = RunService.PreRender:Connect(updateAttachmentCFrame)
else
runServiceConnection:Disconnect()
end
end
end)
Perhaps moving a PointLight is actually a better option than using a SpotLight. Change the light back to a PointLight and try this code. It worked in my testing
local uis = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
-- You can change these but Roblox has some limitations (such as Light.Range being limited to 60).
local MAX_LIGHT_DIST: number = 100
local MIN_DIAMETER: number = 20
local CONE_ANGLE_IN_DEGREES: number = 45
local sfx = script.Sound
local light = script.Light
local char = script.Parent
local torso = char:WaitForChild("Torso")
local runServiceConnection
local attachment = Instance.new("Attachment")
light.Parent = attachment
attachment.Parent = workspace.Terrain
local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
raycastParams.FilterDescendantsInstances = {char}
local function updateAttachmentCFrame()
local cameraCf = workspace.CurrentCamera.CFrame
local lightOrigin = cameraCf.Position
local raycastVector: Vector3 = MAX_LIGHT_DIST * cameraCf.LookVector
local raycastResult = workspace:Raycast(lightOrigin, raycastVector, raycastParams)
local lightPos: Vector3, distFromLightOrigin: Vector3
if raycastResult ~= nil then
lightPos, distFromLightOrigin = raycastResult.Position, raycastResult.Distance
else
lightPos, distFromLightOrigin = lightOrigin + raycastVector, raycastVector.Magnitude
end
attachment.Position = lightPos
light.Range = math.max(distFromLightOrigin * math.tan(.5 * math.rad(CONE_ANGLE_IN_DEGREES)), .5 * MIN_DIAMETER)
end
if light.Enabled then
runServiceConnection = RunService.PreRender:Connect(updateAttachmentCFrame)
end
uis.InputBegan:Connect(function(inp, gpe)
if gpe then return end
if inp.KeyCode == Enum.KeyCode.F then
sfx:Play()
light.Enabled = not light.Enabled
if light.Enabled then
runServiceConnection = RunService.PreRender:Connect(updateAttachmentCFrame)
else
runServiceConnection:Disconnect()
end
end
end)
@notsad2, I added the first if statement just in case the light is initially enabled before the user presses the key for the first time.