Add CanCollide as a filter parameter for WorldRoot:Raycast

Problem:
Doing checks to see what players can collide against with WorldRoot:Raycast is currently difficult, because raycasts ignore parts CanCollide property.

Often CanCollide == false geometry gets used for triggers, effects, and other visuals, and players automatically do not collide with them, which makes building relatively simple.

To have a raycast check the same geometry that players can touch the options are:

  • manually casting the ray twice or more (example below)
  • building/maintaining complicated whitelists or blacklists
  • making sure everything is tagged with a custom collision group

None of these solutions are ideal, especially collision groups, because if you use that to ignore CanCollide parts, you can’t use the collision group for other physics related tasks in the world.

Example code of the current “best” workaround:

function module:CastAgainstSameStuffAsPlayer(start, dir)
    
    local raycastParams = RaycastParams.new()
    
    local blacklist = {}
    
    raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
    raycastParams.FilterDescendantsInstances = blacklist
    raycastParams.CollisionGroup = "PlayerGroup"
    raycastParams.IgnoreWater = true
    
    while (true) do
        
        local raycastResult = workspace:Raycast(start,dir, raycastParams)

        if (raycastResult == nil) then
            return nil
        end

        if (raycastResult.Instance.CanCollide == false) then
            --Add the CanCollide part to the blacklist, Repeat 
            table.insert(blacklist, raycastResult.Instance)
            raycastParams.FilterDescendantsInstances = blacklist
        else
            return raycastResult
        end
    end
    return nil
end 

Benefit if addressed

A very common use would be pets, where you want the pet to hover off the ground a short distance away from the player.

You’d be able to cast a ray down and have it hit exactly the same geometry that a player can currently stand on, so same collision group, and also CanCollide == false.

The code might end up looking like:

function module:CastAgainstSameStuffAsPlayer(start, dir)
    
    local raycastParams = RaycastParams.new()
    
    raycastParams.CollisionGroup = "PlayerGroup"
    raycastParams.IgnoreWater = true
    raycastParams.UseCanCollide = true
   
    return workspace:Raycast(start,dir, raycastParams)

end
16 Likes

(Hi I think this was meant to go in Engine Features)

1 Like

IIRC, the upcoming CanQuery property for BaseParts intends to be a raycast filter.

3 Likes

Ooh, that does seems useful!

But it doesn’t solve the issue of casting the exact same ray that a humanoid would use…

2 Likes

I currently use a CollissionGroup trick - with the old raycast method, to prevent rays from colliding with specific geometry, and I use Folders in Workspace to determine Instances that shouldn’t register to rays.

1 Like