How to cast rays through blocks that have cancollide set to false

You can write your topic however you want, but you need to answer these questions:
I am trying to make my raycast weapons pass through blocks that are cannotcollide.

2.I am not sure how to script this, and I am using the older raycast method.

  1. I do not know what to do, and I am not the best at raycast scripting.
	local ray = Ray.new(hole.CFrame.p, (mouse.hit.p - hole.CFrame.p).unit * range.Value)
		local touch, position = workspace:FindPartOnRay(ray, player.Character, false, true)
		
		--//Hit detection
		if touch then
			hitRemote:FireServer(touch)
		end
		shootRemote:FireServer()
		
		--//Trace
		if allowTracing.Value then
			--//Create
			local trace = Instance.new("Part")
			trace.Anchored = trace
			trace.CanCollide = false
			trace.Transparency = .5
			trace.BrickColor = BrickColor.new("Medium blue")
			trace.Material = Enum.Material.Neon
			
			--//Calculate
			local distance = (hole.CFrame.p - position).magnitude
			trace.Size = Vector3.new(.25, .25, distance)
			trace.CFrame = CFrame.new(hole.CFrame.p, position) * CFrame.new(0, 0, -distance/2)
			trace.Parent = workspace
			remotes.Oof:FireServer(hole.CFrame.p, mouse.hit.p
			)
			
			--//Clean-up
			game:GetService("Debris"):AddItem(trace, 0.02)
			
			wait(.02)

This is on a local script.
I also cast a ray on server.
If possible, I’d like to convert to the new raycast method as I think it is smoother, but I do not understand how to.

2 Likes

Try using the new method, WorldRoot:RayCast allows you to filter parts using collision groups inside of the RaycastParams. Not sure if it’s possible with Ray.new.

As I said, I looked at it but did not understand how to convert my old raycast to this.

2 Likes
local raycastParams = RaycastParams.new()

local origin = hole.CFrame.p
local direction = (mouse.hit.p - hole.CFrame).unit * range.Value

raycastParams.FilterDescendantsInstances = {player.Character}
raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
raycastParams.IgnoreWater = true

local raycastResult = workspace:Raycast(origin, direction, raycastParams)
local position

if raycastResult then
    local touch = raycastResult.Instance

    position = raycastResult.Position

    hitRemote:FireServer(touch)
else
    position = origin + direction
end

something like this

Something like this would work but you I feel like you need to loop everything in workspace that are non-collidable, how I do this is I put this inside a function, and check the part that has been hit if it’s set to cancollide false, if the part is not collidable I will fire again the function, something like that

(I’m not good at english :confused:)

Try

local InstancePart = raycastResult.Instance -- getting the part that has been hit.

if InstancePart.CanCollide == false then -- checking if it is false.
  -- do stuff
end

Yes something like that, then fire the function that is used to raycast like:

local function rayCast(origin, dir)
 --put your stuff here
  if hitPart.CanColide == false then -- make sure the hitpart doesn't have a humanoid in its parent
     rayCast(hitPosition, CFrame.new(hitPosition, hitPosition - hitNormal).LookVector * range) -- Some bits of my old gun system
  end
end
1 Like

Yes, just like that. Also I didn’t notice I was replying to the wrong person LOL

Would that go through cannot collide parts?
Sorry for the stupidity, Not the best at scripting.

To do this with Ray.new()
Shoot 2 rays,

  local Ignore ={tool.Parent}

This makes the ray ignore the tool also use;

 local fPart, fPosition, fNormal = workspace:FindPartOnRayWithIgnoreList(Ray, Ignore)
 -- "the f in front means FIRST" --
if fPart.CanCollide == false then
Ignore = {tool.Parent; fPart}
else
Ignore = {tool.Parent}
end
local Part, Position, Normal = workspace:FindPartOnRayWithIgnoreList(Ray, Ignore)

This is a deprecated method, however It works fine. :sunny:

1 Like

No, I only converted your old raycast to the new API.

You have 3 options to do that:

  1. Create an array with all CanCollide false parts in your game and set raycastParams.FilterDescendantsInstances to it. You can use workspace:GetDescendants() or CollectionService:GetTagged() (if you tag all CanCollide false parts before that, it can be done in studio edit mode with the command bar) to find all the CanCollide false parts in your game.
  2. Instead of using the CanCollide property, make a new Collision Group which doesn’t collide with Default and set all of the CanCollide false parts’ Collision Group to it.
  3. If your raycast hits a CanCollide false part, raycast again from where the last ray ended (new origin vector). You would also have to decrease the direction vector based on how far from the last origin the ray traveled, so the rays don’t go too far. Repeat this until you get a result which isn’t a CanCollide false part.

The 3rd method is probably the best if your game has a lot of CanCollide false parts, but also the hardest to implement.

@Epic_2219 Hello, unfortunately I am not enough experienced to have a answer, but I would council getting all the RayCast functions, and then use them at there designed place.

Where?

I’ll attempt this, thank you.
I will also implement a the new raycast thing.

And another question, will this create a new ray part? As I need that.

What do you mean by a “ray part”?

As in a block that is streched across the ray length.

And by the way, this is not working.
Is this implemented correctly?


local function fire()
	--//Checks
	if canShoot:InvokeServer() then
		--//Initialize
		
	
		
		--[[local SPREAD = 1000 -- set some value for it
		local spreadPosition = Vector3.new(
			hole.CFrame.p.X + math.random(-SPREAD, SPREAD)/1000,
			hole.CFrame.p.Y + math.random(-SPREAD, SPREAD)/1000,
			hole.CFrame.p.Z + math.random(-SPREAD, SPREAD)/1000
		)]]
		local raycastParams = RaycastParams.new()

		local origin = hole.CFrame.p
		local direction = (mouse.hit.p - hole.CFrame).unit * range.Value

		raycastParams.FilterDescendantsInstances = {player.Character}
		raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
		raycastParams.IgnoreWater = true

		local raycastResult = workspace:Raycast(origin, direction, raycastParams)
		local position

		if raycastResult then
			local touch = raycastResult.Instance

			position = raycastResult.Position

			hitRemote:FireServer(touch)
		else
			position = origin + direction
		end
	end
end

OLD:

local function fire()
	--//Checks
	if canShoot:InvokeServer() then
		--//Initialize
		
	
		
		--[[local SPREAD = 1000 -- set some value for it
		local spreadPosition = Vector3.new(
			hole.CFrame.p.X + math.random(-SPREAD, SPREAD)/1000,
			hole.CFrame.p.Y + math.random(-SPREAD, SPREAD)/1000,
			hole.CFrame.p.Z + math.random(-SPREAD, SPREAD)/1000
		)]]
		local ray = Ray.new(hole.CFrame.p, (mouse.hit.p - hole.CFrame.p).unit * range.Value)
		local touch, position = workspace:FindPartOnRay(ray, player.Character, false, true)
		
		--//Hit detection
		if touch then
			hitRemote:FireServer(touch)
		end
		shootRemote:FireServer()
		
		--//Trace
		if allowTracing.Value then
			--//Create
			local trace = Instance.new("Part")
			trace.Anchored = trace
			trace.CanCollide = false
			trace.Transparency = .5
			trace.BrickColor = BrickColor.new("Medium blue")
			trace.Material = Enum.Material.Neon
			
			--//Calculate
			local distance = (hole.CFrame.p - position).magnitude
			trace.Size = Vector3.new(.05, .05, distance)
			trace.CFrame = CFrame.new(hole.CFrame.p, position) * CFrame.new(0, 0, -distance/2)
			trace.Parent = workspace
			remotes.Oof:FireServer(hole.CFrame.p, mouse.hit.p
			)
			
			--//Clean-up
			game:GetService("Debris"):AddItem(trace, 0.02)
			
			wait(.02)
			
		
		end
	end
end

Oh, my bad. I missed a “.p” for the direction variable. Should have been:

local direction = (mouse.hit.p - hole.CFrame.p).unit * range.Value

I only changed the top of your old code to show you how you can use the new Raycasting API with your code. The rest of the code should still work, I didn’t bother copy pasting it (the shootRemote:FireServer() part and anything below).

Alright, so the ray cast works. Now to cast them through non-solid blocks or massless blocks, we would have to do what?