Help with Raycasting

Hey developers!

I am creating a placement system in which you can only place on certain parts.

Here’s my testing code:

local LocalPlayer = game:GetService("Players").LocalPlayer

local Mouse = LocalPlayer:GetMouse()

local RaycastParam = RaycastParams.new()
RaycastParam.IgnoreWater = true
RaycastParam.FilterType = Enum.RaycastFilterType.Whitelist
RaycastParam .FilterDescendantsInstances = {workspace.PlacementParts}

local Tool = script.Parent

local Equipped = false

Tool.Equipped:Connect(function()
	Equipped = true
end)

Tool.Unequipped:Connect(function()
	Equipped = false
end)

game:GetService("RunService").RenderStepped:Connect(function()
	if Equipped then
		local Hit = Mouse.Hit

		local Raycast = Ray.new(
			Hit.p,
			Vector3.new(0,-1,0)*500
		)

		local RaycastResult = workspace:Raycast(Hit.p, Vector3.new(0,-1,0)*500, RaycastParam)

		if RaycastResult and RaycastResult.Position then
			local Part = Instance.new("Part")
			Part.Parent = workspace
			Part.Position = RaycastResult.Position
			Part.Anchored = true

			task.delay(.1, function()
				Part:Destroy()
			end)
		end
	end
end)

workspace.PlacementParts is the folder in which the parts you can place on are stored.

When testing however, you can only place on parts above the parts in the folder:
Hovering over the part itself isn’t working:

But parts above it does work:
image

Does anyone know what’s causing this?
Thanks!

1 Like

I see 3 parts. Something Green, something Red, and something clear and white. Can you add a print(RaycastResult.Instance) to make sure your not running into the filter? Also, this line has an unwanted space:

RaycastParam .FilterDescendantsInstances = {workspace.PlacementParts}

Probably would have spit out an error if it was a problem.

When hovering over a part that is part of the map, I get this output:

Hovering over placement part gives an error:

nil means the raycast was unsuccessful, which means the green part is being filtered. It works on the red part, as per your original pictures.

Show us where that green part is housed. It may need to be moved into a different folder.

Shouldn’t it pick up the clear part itself though?

Change line 31 to

local RaycastResult = workspace:Raycast(Hit.p + Vector3.new(0,0.001,0), Vector3.new(0,-500,0), RaycastParam)

I think the raycast is erroring because the ray is being casted in the part, not on top it. Adding 0.001 makes it slightly above the part making the ray fully go through it.

I would need to see the workspace folder setup, but I think you filtered a folder that these parts are in. The ray is missing both the green and the white.

Also check your “cantouch” and “canquery” properties.

Better use mouse.hit.Z/Y/X IS so much easier

image
image
White is above the green, and that’s the placement part.

@deafaultyboii1324 I already tried that and it didn’t work :frowning:

Yeah, that’s exactly what you filtered! :slight_smile:

Try moving the green part to the Map folder and try again!

I thought I was filtering it goes to the white part only? Cause that’s what I was wanting… can only place on white part

I’m confused, I think. Is placement part the white part? Where is the green part?

Placement part is white, green part is a random part part of the map.

LOL, I was running in circles! OK, green is not filtered but white is… and neither are filtered for the Mouse.Hit, but the white part has collide turned off. (throws out the rulebook)

OK, a few more suggestions.

  1. can you test print(Mouse.Target) to make sure the white part is actually the start of the raycast? It should be.
  2. is the white part overlapping the green part? If so, raise the white part up and make it thinner. @deafaultyboii1324 might be right about the problem, but wrong about the correction necessary.
  3. Maybe create a part at Hit.p? When all else fails, throw a part out there. No need to write anything new, try this:
local function addball (pos, size)
local ball = Instance.new("Part")
ball.BrickColor = BrickColor.new("Really red")
ball.Shape = "Ball"
ball.Size = Vector3.new(size,size,size)
ball.Anchored = true
ball.Position = pos
ball.Parent = game.Workspace
end
  1. Tested it, and white part is the start of the raycast.

  2. Nope, not overlapping

  3. Here’s what that looks like:
    image

I just grabbed my code. This is from my working raycast formula. I am SO sorry I did not catch this faster.

raycastParams.FilterType = Enum.RaycastFilterType.Blacklist

and here’s your code:

RaycastParam.FilterType = Enum.RaycastFilterType.Whitelist

The only thing your raycast should find is the white part. The reason it works on the red part is simple: Mouse hits the red, you raycast through it and hit the white.

I thought whitelist meant that only the supplied parts can be found by a raycast? I made the edit and now any part, including those outside of the placement area, can be selected. I am thinking an easier solution might be to have raycasting on for everywhere and check if the part is within a placement region using region3.

It does. The only part you can find in the whitelist is the white part. However, you already found the white part with the mouse hit, and you are raycasting from there. You can’t find the white part again, as you are already inside it.

2 scenarios:
Mouse.hit on the white part. Raycast down from the white part finds nothing (only thing under white is green, not whitelisted).

Mouse.hit on the red part. Raycast down from the red part finds the white part.

It looks like you want the white part to be the “region” You can do that by blacklisting the white part, but you also need to add the check that the Mouse.Target is the white part.

1 Like

Ended up ditching my method!
My final code:

local LocalPlayer = game:GetService("Players").LocalPlayer

local Mouse = LocalPlayer:GetMouse()

local RaycastParam = RaycastParams.new()
RaycastParam.IgnoreWater = true
RaycastParam.FilterType = Enum.RaycastFilterType.Whitelist
RaycastParam.FilterDescendantsInstances = {workspace.Map}

local Tool = script.Parent

local Equipped = false

Tool.Equipped:Connect(function()
	Equipped = true
end)

Tool.Unequipped:Connect(function()
	Equipped = false
end)

function isInsideBrick(position, brick)
	local v3 = brick.CFrame:PointToObjectSpace(position)
	return (math.abs(v3.X) <= brick.Size.X / 2)
		and (math.abs(v3.Y) <= brick.Size.Y / 2)
		and (math.abs(v3.Z) <= brick.Size.Z / 2)
end

function CheckPosition(Position)
	for _, Part in pairs(workspace.PlacementParts:GetChildren()) do
		if isInsideBrick(Position, Part) then
			return true
		end
	end
	return false
end

game:GetService("RunService").RenderStepped:Connect(function()
	if Equipped then
		local Hit = Mouse.Hit

		local Raycast = Ray.new(
			Hit.p+Vector3.new(0,10,0),
			Vector3.new(0,-1,0)*500
		)

		local RaycastResult = workspace:Raycast(Hit.p, Vector3.new(0,-1,0)*500, RaycastParam)
		
		if RaycastResult and RaycastResult.Position and CheckPosition(RaycastResult.Position) then
			local P = Instance.new("Part", workspace)
			P.Position = RaycastResult.Position
			P.Anchored = true
			delay(.1, function()P:Destroy()end)
		end
	end
end)

Result:

Thanks to everyone that helped!

1 Like