+1 vote

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"

in Engine by (30 points)

2 Answers

+2 votes
Best answer

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)
by (5,274 points)
selected by

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

https://godotengine.org/qa/78248/make-cast-exclude-things-only-collide-with-particulate-body?show=78283#a78283

0 votes

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

#your code here .is_in_group(#name of the group)
by (55 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.