Hello! As of recently, I’ve been attempting to make a mechanic in my game that would cause a player looking at a part named “B187” (spawned in from a script) to freeze.
I want to make it so that when the part enters the screen of a player, the player’s WalkSpeed is set to 0. The closest I’ve gotten has somewhat worked, but it uses the direct center of the screen (albeit with a bit of fluctuations from the character’s idle animations).
I want it to detect if the part is on any part of the screen, how could I do that?
local camera = game.Workspace.CurrentCamera
game:GetService("RunService").RenderStepped:Connect(function()
local direction = (game.Players.LocalPlayer.character.Head.Position - camera.CFrame.Position).Unit * 1000
local descendantsToIgnore = game.Players.LocalPlayer.Character
local ray = Ray.new(camera.CFrame.Position, direction)
local hit, position = workspace:FindPartOnRay(ray, descendantsToIgnore)
if hit and hit:IsA("BasePart") then
print(position)
if hit.Name == "B187" then
print("Looking at B-187")
game.Players.LocalPlayer.Character.Humanoid.WalkSpeed = 0
elseif game.Players.LocalPlayer.Character.Hiding.Value == false and hit.Name ~= "B187" then
game.Players.LocalPlayer.Character.Humanoid.WalkSpeed = 14
end
end
end)
Raycast the players mouse and detect if it is hovering over the part. If you don’t want the raycast script running 24/7 just make it run if you are in a certain radius of the part.
Return:
coordinates (x and y on screen + z-depth): Vector3, isOnScreen: boolean
The only difference between the two is that the former takes GuiInset into account while its counterpart doesn’t. The second returned argument is truthy whenever a point is on screen, even if it is covered by obstacles or terrain.
The next step is casting a ray from camera’s position towards the part.
The provided code does exactly that, and includes @LiterallyLaser’s suggestion to only raycast in certain proximity. I left the Hidden value out for the sake of simplicity. You can re-add it later.
Code
local RunService = game:GetService("RunService")
local camera = workspace.CurrentCamera
local localPlayer = game:GetService("Players").LocalPlayer
local character = localPlayer.Character or localPlayer.CharacterAdded:Wait()
local rootPart = character:WaitForChild("HumanoidRootPart")
local humanoid = character:WaitForChild("Humanoid")
local part = workspace.B187
local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
raycastParams.FilterDescendantsInstances = {character}
RunService.Heartbeat:Connect(function(dt)
if (rootPart.CFrame.Position - part.CFrame.Position).Magnitude > 35 then
humanoid.WalkSpeed = 14
return
end
local vector, isOnScreen = camera:WorldToViewportPoint(part.Position)
local raycastResult = workspace:Raycast(
camera.CFrame.Position,
(part.CFrame.Position - camera.CFrame.Position).Unit * 1000,
raycastParams
)
if isOnScreen and raycastResult and raycastResult.Instance == part then
humanoid.WalkSpeed = 0
else
humanoid.WalkSpeed = 14
end
end)
Thank you! One problem though, the part isn’t always in the workspace. It’s cloned from ReplicatedStorage when the server calls for it. However, I could make a workaround for this.