Raycast detects last collider, even if that collider is not part of the collision mask

Godot Version

v4.7.stable.official [5b4e0cb0f]

Question

this is my code, it fires a raycast from the camera and in the direction the player is looking. the problem is that this raycast only detects hitting an enemy if the enemy has nothing behind them. if there is a wall behind them, the raycast either hits the wall, or if the wall is exlcuded via collision_mask then the raycast hits nothing.

func fire_functional_bullet(dir: Vector3, damage: int) -> Dictionary:
	var space_state := get_world_3d().direct_space_state
	var query := PhysicsRayQueryParameters3D.create(
		global_position,
		global_position + (dir * RAY_LENGTH),
		collision_mask
	)
	query.collide_with_areas = true
	query.hit_from_inside = true
	var result = space_state.intersect_ray(query)
	if not result: return result
	if result.collider is not Health: return result
	result.collider.hit(self, damage)
	return result

i know it is firing in the correct direction and that the enemy successfully recieves damage when result.collider is an enemy. i am using csg nodes and Health extends Area3D (which is why query.collide_with_areas = true)

What are your collision layers/mask values? What do you set as this query’s collision mask?

the collision masks i have are World, Player, and Enemies. i want and did have the raycast using World + Enemies, but it would detect the wall if there was one behind the enemy. im not sure godot cares what my collision masks are though, because when i set the raycast to just Enemies then it detects nothing if there is a wall behind the enemy.

Share Inspector settings be the best you can do to get best advice .

such as

Player



Enemy


World

And what value do you set for collision_mask in your sample? Can you show the code defining this value?

the collision mask is set to an @export var under BulletManager

extends Node3D
class_name BulletManager


const RAY_LENGTH: float = 4000

# This is set to just Enemies layer in inspector
@export_custom(PROPERTY_HINT_LAYERS_3D_PHYSICS, "") var collision_mask: int = 1


func fire_functional_bullet(dir: Vector3, damage: int) -> Dictionary:
	var space_state := get_world_3d().direct_space_state
	var query := PhysicsRayQueryParameters3D.create(
		global_position,
		global_position + (dir * RAY_LENGTH),
		collision_mask
	)
	query.collide_with_areas = true
	query.hit_from_inside = true
	var result = space_state.intersect_ray(query)
	if not result: return result
	if result.collider is not Health: return result
	result.collider.hit(self, damage)
	return result


# not much for now, but later ill add visual bullet
func fire_bullet(dir: Vector3, damage: int) -> void:
	fire_functional_bullet(dir, damage)

this is what it is set to in the inspector

Print collision_mask in fire_functional_bullet().

print(collision_mask) is 4

How do you determine what gets hit?

here

and i use result.collider

Use it in what way? Do you print it? If not, you should.
Print result in fire_functional_bullet() if it’s not empty, as soon as you get it.

i use it here

ive printed result, thats how i know its hitting the wall behind the enemy if there is one. even with the wall excluded via collision mask it prints nothing

That doesn’t make sense. Which node is running the BulletManager script? Post your scene structure.

Who and how calls fire_bullet()? How do you calculate dir? Check that the ray is pointed correctly.

Player calls fire_bullet() in _physics_process():

if Input.is_action_just_pressed("fire"):
	$BulletManager.fire_bullet(-camera.basis.z, 100)

and camera is @onready var camera: PlayerCamera = $PlayerCamera

Can you make a minimal reproduction example?

Btw, you should probably use camera’s global basis.

oh it was because im not using global basis