I need help with detecting when a player is looking at a part that is spawned in

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.

1 Like

If I were you, I’d consider using one of the two special camera methods: WorldToScreenPoint() or WorldToViewportPoint().

  • Args:
    world position: Vector3

  • 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)
2 Likes

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.

1 Like

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