Raycast doesn't stop at parts in the way

Hello! I am trying to make a raycasting script that will exclude every descendant of workspace, as long as it is outside of my Map folder, its ancestor doesn’t have a Humanoid, CanCollide is off and transparency is equal to or greater than 0.5.

However, even though there is a character in the way of the mouse position, the raycast result doesn’t stop on the character, but rather goes through it.

local function getMousePosition()
	local mouse = plr:GetMouse()

	local params = RaycastParams.new()
	params.FilterType = Enum.RaycastFilterType.Exclude
	
	local exclude = {}
	
	for _, child in plr.Character:GetChildren() do
		if child:IsA("BasePart") then
			table.insert(exclude, child)
		end
	end

	for _, descendant in workspace:GetDescendants() do
		if descendant:IsA("BasePart") then
			if not table.find(exclude, descendant) then
				local isPartOfMap = descendant:IsDescendantOf(workspace.Map)
				local modelAncestor = descendant:FindFirstAncestorWhichIsA("Model")
				local hasHumanoidAncestor = modelAncestor and modelAncestor:FindFirstChildOfClass("Humanoid")

				if not isPartOfMap and not hasHumanoidAncestor then
					table.insert(exclude, descendant)
				end

				if not descendant.CanCollide and descendant.Transparency >= 0.5 then
					table.insert(exclude, descendant)
				end
			end
		end
	end

	params.FilterDescendantsInstances = exclude
	local result = workspace:Raycast(tool.Handle.Position, (mouse.Hit.Position - plr.Character.HumanoidRootPart.Position).Unit * math.huge, params)
	
	print(result)
	if result then
		return result.Position
	else
		return mouse.Hit.Position
	end
end

I appreciate any answer!

here you are adding the character parts to the exclude table so they are being ignored by the raycast. Would it work to instead set the filter type to include and set the FilterDescendantsInstances to {workspace.Map, character1, character2, …}?

Edit: unless you are only excluding the local character and the character not being detect is another character

That is the local player’s character which is supposed to be ignored

Is it possible your ray is being aimed wrong? The direction maybe should be based on

mouse.Hit.Position - tool.Handle.Position

since it’s originating from tool.Handle.Position.


Another potential problem, if you’re looking for the 3D space the mouse is at but with the exclude list, maybe you should:

  • Start a ray at the camera and send it out to the mouse target to get the 3D position
  • Fire a second ray from the tool to this position

I think this should do what you want!

local k_maxRaycastDistance = 15000 -- This is the max raycast distance that can be calculated!
local k_transparencyCutoff = 0.5   -- This is how transparent an object has to be to be seen by the mouse 

local function getMousePosition()
	local localPlayer = game.Players.LocalPlayer
	local mouse = localPlayer:GetMouse()

	local excludeArray = {} -- This is our final list of excluded parts
	
	local excludeLookup = {} -- This is a look up table so we can check if we've already excluded parts
	local characterPartLookup = {} -- This is a lookup table so we can check if a part is in a humanoid
	
	-- Look up tables are nice because they have a constant look up time! table.find() will take longer if there's more stuff in the table,
	--    but checking if the key is in the table takes the same amout of time no matter how big the table is!
	
	local function canBeExcluded(instance : Instance)
		return instance:IsA("BasePart") and not excludeLookup[instance] and not characterPartLookup[instance]
	end
	
	local function excludePart(part : BasePart)
		excludeLookup[part] = true
		table.insert(excludeArray, part)
	end
	
	-- First go through and find all the characters! We don't want to add any of their parts
	--    We can do this by find all the humanoids in our workspace and removeing their parents children from the possible parts
	for _, descendant in game.Workspace:GetDescendants() do
		if descendant:IsA("Humanoid") and descendant.Parent ~= localPlayer.Character then
			for _, humanoidInstance in descendant.Parent:GetDescendants() do
				characterPartLookup[humanoidInstance] = true
			end
		end
	end
	
	-- Now lets go through and exclude parts
	for _, descendant in game.Workspace:GetDescendants() do
		if canBeExcluded(descendant) then
			local isPartOfMap = descendant:IsDescendantOf(game.Workspace.Map)
			local isNoninteractable = not descendant.CanCollide and descendant.Transparency >= k_transparencyCutoff
			
			if not isPartOfMap or isNoninteractable then
				excludePart(descendant)
			end
		end
	end
	
	
	local raycastParameters = RaycastParams.new()
	raycastParameters.FilterType = Enum.RaycastFilterType.Exclude
	raycastParameters.FilterDescendantsInstances = excludeArray
	
	-- You could also change this to something like game.Workspace.CurrentCamera.CFrame.Position
	--    if you wanted to get anything that was visible to the camera rather than to the tool
	local origin = tool.Handle.Position 
	local target = mouse.Hit.Position
	
	local directionVector = (target - origin).Unit * k_maxRaycastDistance
	
	local result = workspace:Raycast(origin, directionVector, raycastParameters)
	
	if result then
		return result.Position
	else
		return mouse.Hit.Position
	end
end

I suspect there a couple of issues:

  1. your character probably had some hats or some parts that weren’t a direct child of your character model!

so you could also try switching for _, child in plr.Character:GetChildren() do
to for _, child in plr.Character:GetDescendants() do

  1. local hasHumanoidAncestor = modelAncestor and modelAncestor:FindFirstChildOfClass("Humanoid") won’t work if the part your checking is nested inside your character model! (Like a part that’s a child of a hat instance rather than the character itself). This ones a little more tricky to solve, but the solution I provided got around it by doing a pre pass to find instances that belonged to characters!

The solution I provided will also be a little more efficient because it doesn’t use table.find (Even though it does go through the workspace twice!)

1 Like

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