how do i exclude every thing else but one particulate node for ray cast?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By MCjelly

So I’m creating a slash & hit VFX that whenever that the player hit the enemy, a ray well cast to the enemy from player, and the hit VFX would be appearing at the ray-collided position

however, the player can hit multiple targets at once, but the VFX for other enemies would appear only on the first enemy the ray is colliding with. they ray may collide with other unnecessary objects such as the tilemap.

here’s my code:

func _on_Attack_coli_body_entered(body: Node) -> void:
var slash_effect = preload("res://crs/effects/attackanim/swordslide.tscn").instance()
var spacestate = get_world_2d().direct_space_state
var result = spacestate.intersect_ray(global_position,body.global_position,["anything but body"])

print(result)

get_parent().add_child(slash_effect)
slash_effect.position = result.position
slash_effect.rotation = (position - body.position).angle()+1.5

how do I make ray collide only with the “body”

:bust_in_silhouette: Reply From: Simon

You can add a group on the particulate node and use this:

#your code here .is_in_group(#name of the group)
:bust_in_silhouette: Reply From: avencherus

You would have to build an Array of all the things you’d like to exclude, so you’ll have to be keeping track of these things globally.

Typically this kind of filtering is best done with the layer masks. Then having most unrelated object into their own physics layers.

In this example you have the body that you’re interested, and you can check the results for that. This would be the more usual approach.

func _on_Attack_coli_body_entered(body: Node) -> void:

	var a = global_position
	var b = body.global_position

	# Have most other things on their own layers.
	var layer = body.collision_layer
	
	var state = get_world_2d().direct_space_state
	var result = state.intersect_ray(a, b, [], layer)

	if(not result.empty() and result.collider == body):
		slash_effect()

If you really need to track and exclude all other objects, it requires all objects to register themselves somewhere globally, such as an Autoload Singleton.

I don’t recommend this approach.

But here is what such code would look like:

 func _on_Attack_coli_body_entered(body: Node) -> void:

	var a = global_position
	var b = body.global_position

	var layer = body.collision_layer

	# Every physics object would need to register itself somewhere.
	# IE - (Game) singleton (Implementation details vary game to game.)

	# Then globally retrieve that list of active objects.
	# Remove the one body here that is being queried.

	var exclusions = Game.get_all_active_objects()
	exclusions.erase(body)
	
	var state = get_world_2d().direct_space_state
	var result = state.intersect_ray(a, b, exclusions, layer)

	if(not result.empty()):

		assert(result.collider == body) # Not every object was accounted for.
		slash_effect()

EDIT

Also occurs to me that maybe you want the ray to keep going until it has exhausted all possible collisions, because maybe these are monsters and one is standing inbetween the one you want to check a line of sight against.

That code would be to keep looping ray casts, accumulating exclusions of the last object that wasn’t the desired one, and breaking when you hit the desired one or nothing is hit.

func _on_Attack_coli_body_entered(body: Node) -> void:

	var a = global_position
	var b = body.global_position

	var layer = body.collision_layer
	var exclusions = []

	while(true):
	
		var state = get_world_2d().direct_space_state
		var result = state.intersect_ray(a, b, exclusions, layer)

		if(result.empty()):
			break # Done

		elif(result.collider == body):
			slash_effect()
			break
			
		else: # Continue casting.  Accumulate undesired contacts.
			exclusions.append(result.collider)

thanks for the answers, but someone has already figured it out for me on Reddit :slight_smile:
I accidentally asked this question twice, because Godot q&a is slow as heck… and I couldn’t wait.

How do i make ray-cast exclude all things but only collide with one particulate body? - Archive - Godot Forum

MCjelly | 2020-07-29 15:22