Telling what object (if any) in a folder that the player is looking at

Hi guys,

I need to tell WHAT object in a folder in workspace a player is looking at locally. This is different from telling if an object is being looked at, as I want to be able to check through everything on a local script on the player, as with the amount of objects that could be in this folder (10k+), having a script for each one would be way too laggy. Is there some way to do this with raycasts or something else?

2 Likes
local rayOrigin = --player head location
local rayDirection = --player camera look vector*ray length
local folderPath = --path of the folder to be checked

local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {folderPath}
raycastParams.FilterType = Enum.RaycastFilterType.Include
raycastParams.IgnoreWater = true

local raycastResult = workspace:Raycast(rayOrigin, rayDirection, raycastParams)
print(raycastResult.Instance)

Keep in mind the above code will ignore parts that aren’t inside the folder, meaning that if a non-folder part(like a wall) is in front of the part you’re looking for it will still be detected, as if you’re looking through it. Instead if you want a normal raycast that checks for all parts you should remove the raycastParams argument and perform the following check:

if raycastResult and raycastResult.Instance and raycastResult.Instance:IsDescendantOf(folderPath) then
	print("Found a part within the folder")
elseif raycastResult and raycastResult.Instance then
	print("A non-folder part was detected")
else
	print("No part was detected")
end
1 Like

raycastResult is set to nil.

local rayOrigin = chr:FindFirstChild("Head").Position
local rayDirection = hrp.CFrame.LookVector * 100
local folderPath = workspace.folder
print(rayOrigin, rayDirection)

local raycastResult = workspace:Raycast(rayOrigin, rayDirection)
print(raycastResult)

if raycastResult.Instance and raycastResult.Instance:IsDescendantOf(folderPath) then		print("Found a part within the folder")
elseif raycastResult.Instance then
	print("A non-folder part was detected")
else
	print("No part was detected")
end

rayOrigin and rayDirection are printed out just fine. Priting raycastResult just gives nil, which makes it error when we try to get the instance. Did I do something wrong when removing the raycastParams argument?

1 Like

Here, I can help, just answer something real quick for me,

  1. Do you want it to be detected from the players camera, or just the head like how @NyrionDev did it?
1 Like

Camera preferrably. If possible, I’d like this to be able to run on client and server so I can run a sanity check and make sure they can actually see what I’m trying to get and that they haven’t exploited to bypass it, but if not its not the end of the world.
Im pretty sure locally I can just do workspace.CurrentCamera.Position but I haven’t tested yet. Not sure about server.

1 Like

You misread my reply. The head is the start of the ray, the camera is where the ray is pointing(most specifically the camera look vector) and when multiplying that by ray length(lets say 1000) we move it away 1000 studs, effectively increasing the length of the ray. So that way in order for something to be detected it must be in the folder, have the player directly looking at it, and also be less than 1000 studs away.

2 Likes

My bad, but I was just using you for an indirect reference. Apologies,

1 Like

I will help you work on a script in a hot moment, something just came up. Should we want to take it to DevForum DMS?

That would be fine. There isn’t a rush, and thanks for the help!

1 Like

I fixed my if statement, check above for the correct version. Also that code should run each time the camera look vector is updated/the camera is moved. In my reply it runs once at script start, so its logical it doesn’t detect anything. Something you can do is add the if-statement under a RunService event such as RenderStepped:

game:GetService("RunService").RenderStepped:Connect(function()
	--the if statement from above
end)

Its not giving errors anymore, but the raycastResult is still equal to nil.

local rayOrigin = chr:FindFirstChild("Head").Position
local rayDirection = hrp.CFrame.LookVector * 100
local folderPath = workspace.folder
print(rayOrigin, rayDirection)

local raycastResult = workspace:Raycast(rayOrigin, rayDirection)
print(raycastResult)
	
if raycastResult and raycastResult.Instance and raycastResult.Instance:IsDescendantOf(folderPath) then
	print("Found a part within the folder")
elseif raycastResult and raycastResult.Instance then
	print("A non-folder part was detected")
else
	print("No part was detected")
end

Add it inside a RunService connection as shown above or a while task.wait() do loop.

It has been since the start already, I don’t think thats the issue.

Update the rayOrigin and rayDirection variables in there. Together with fetching the character head position inside(instead from outside). Also try increasing the look vector multiplier.

I did some testing, and it turns out it only picks up the parts if they were in the folder from the beginning of the server. Any parts cloned in (which will be all of them in this folder after testing) don’t get picked up. Any idea why that could be happening?

Maybe you clone them inside a different folder? Are there two folders named folder? Even if you don’t update folderPath the reference should not change when you clone new parts inside the instance. Perhaps another custom-management script deletes and recreates said folder when a new instance is added?

There is only one folder, and I checked; the cloned parts are being added properly. Nothing else besides the script spawning the parts in and this script interacts with the folder in any way. I’m just as confused as you are…

Try doing folderPath:IsAncestorOf(raycastResult.Instance) instead.

(copied from DMS)

Alright, I came up with something.

Folder1 is the folder I set the detection to.


(Resolution is low to ensure that it can be sent)

Heres the script:

-- local script in StarterCharacterScripts
local WORKSPACE = game:GetService("Workspace")
local RUN_SERVICE = game:GetService("RunService")
local PLAYERS = game:GetService("Players")
--------------------------------------
local CAMERA = WORKSPACE.CurrentCamera
local PLAYER = PLAYERS.LocalPlayer
local CHARACTER = PLAYER.Character or PLAYER.CharacterAdded:Wait() -- feel free to change this to however you get the player's character!
--------------------------------------
local TABLE = {}
for i, PART in pairs(CHARACTER:GetDescendants()) do
	if PART:IsA("BasePart") then
		table.insert(TABLE, PART)
	end
end

local PARAMS = RaycastParams.new()
PARAMS.FilterType = Enum.RaycastFilterType.Exclude
PARAMS.FilterDescendantsInstances = TABLE -- so the raycast doesnt get interrupted by the player character
--------------------------------------
local DESIRED_FOLDER = WORKSPACE.Folder1 -- replace this with the folder you want!
--------------------------------------
RUN_SERVICE.Heartbeat:Connect(function()
	local ORIGIN = CAMERA.CFrame.Position -- We can just do this if the game is in first-person.
	local DIRECTION = CAMERA.CFrame.LookVector * 1000 
	
	local RAYCAST = WORKSPACE:Raycast(ORIGIN, DIRECTION, PARAMS)
	if RAYCAST then
		if RAYCAST.Instance:IsDescendantOf(DESIRED_FOLDER) then
			print("Hit!")
		end
	end
end)

And heres the hierachy for reference:

Screenshot 2024-05-16 114617

copied from DM’s to ensure anybody else who has this problem will get it solved.

I see two different folders in there, not one. Maybe that’s related to the author’s problem?