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
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
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.
No, I only converted your old raycast to the new API.
You have 3 options to do that:
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.
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.
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.
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).
Something like this should work, thought I didn’t test it thoroughly:
local function RaycastWithACondition(condition, origin, direction, raycastParams) -- condition is a function which returns true or false
local raycastResult = workspace:Raycast(origin, direction, raycastParams)
if raycastResult == nil or condition(raycastResult.Instance) then -- this is to ensure we dont call condition(nil)
return raycastResult -- returns nil or RaycastResult
end
-- if the condition didnt pass
local intersection = raycastResult.Position
direction = direction - (intersection - origin) -- previous direction reduced by the distance traveled from the previous origin to the intersection
origin = intersection -- the intersection is the new origin of the next ray
return RaycastWithACondition(condition, origin, direction, raycastParams) -- recursion, back to the top of the function with new origin and direction
end
I implemented the above one with recursion, you can also use a while loop:
local function RaycastWithACondition(condition, origin, direction, raycastParams) -- condition is a function which returns true or false
while true do
local raycastResult = workspace:Raycast(origin, direction, raycastParams)
if raycastResult == nil or condition(raycastResult.Instance) then -- this is to ensure we dont call condition(nil)
return raycastResult -- returns nil or RaycastResult
end
-- if the condition didnt pass
local intersection = raycastResult.Position
direction = direction - (intersection - origin) -- previous direction reduced by the distance traveled from the previous origin to the intersection
origin = intersection -- the intersection is the new origin of the next ray
end
end
You should probably put this in some module script and return it (or put it in a table and return the table), so any script can access it.
Here is an example of the condition function:
local function condition(instance)
return (instance.Transparency < 1 and instance.CanCollide) -- true if a part's Transparency is below 1 and CanCollide is true, otherwise false
end
Some implementation notes:
I tested it and it seems like if you cast a ray that originates from the intersection of the previous ray and a part, it won’t hit the same part again. Basically, a ray that starts from inside a part and goes through it, doesn’t intersect with it. This might not be true for some kinds of unions/meshes with complicated geometries, but the function should still work. This way it’s simpler and we don’t have to mess with tables/Blacklists. From what I know, RaycastParams.FilterDescendantsInstances copies any table you set it to, so it would essentially be creating a new table every time, which wouldn’t be good.
I also tested for the edge case of the ray hitting a part which doesn’t pass the condition at exactly origin + direction. I couldn’t get it to happen. In that case, it would attempt a useless raycast with a direction vector of Vector3.new(0, 0, 0). It would still correctly return a nil, but we could technically prevent the extra workspace.Raycast call by checking if direction == Vector3.new() or if direction.Magnitude == 0. I found this check unnecessary, since it seems like rays don’t detect an intersection at the end of the ray. I tested this by casting a ray with an origin of Vector3.new(0, 0, 0) and a direction of Vector3.new(0, 1, 0). It intersected a part above it at Vector3.new(0, 0.5, 0). Then I tested the same scenario with a direction of Vector3.new(0, 0.5, 0) and there was no intersection.
Hey people, forgot to put a solution on this. Roblox now has a new property called ‘CanQuery’ which manages this exact thing. Therefore, this thread is now deprecated. Sorry everyone!