0 votes

The set-up is very basic, I want to use ray casting to pick a kinematic body. Think about having two eggs, one is called Fred and one Joe. A kid clicks on one of them, did he clicked on Joe or Fred? All this I need done via ray casting.

So I want to print the instance name of a clicked node. I don't know how to use the resource id returned by the raycast spacestate.intersectray(rayfrom, rayto), there seem to be no way to connect those IDs to "body1" or "body2". Any ideas?

extends Spatial

var RAY_LENGTH = 1000

const Body = preload("res://example5/KinematicBody.tscn")

func _ready():
    var body1 = Body.instance()
    body1.set_name("body1")
    add_child(body1)
    body1.translate(Vector3(-10, 0, 0))
    var body2 = Body.instance()
    body2.set_name("body2")
    add_child(body2)
    body2.translate(Vector3(10, 0, 0))
    return


func _input(event):
    if event is InputEventMouseButton and event.button_index == BUTTON_LEFT and event.pressed:
        var hits = get_object_under_mouse()
        print("Hit:", hits)
        if hits:
            print(hits.collider.name)
    return


# cast a ray from camera at mouse position, and get the object colliding with the ray
func get_object_under_mouse():
    var mouse_pos = get_viewport().get_mouse_position()
    var ray_from = $Camera.project_ray_origin(mouse_pos)
    var ray_to = ray_from + $Camera.project_ray_normal(mouse_pos) * RAY_LENGTH
    var space_state = get_world().direct_space_state
    var selection = space_state.intersect_ray(ray_from, ray_to)
    return selection

Result:

Hit:{collider:[KinematicBody:1180], colliderid:1180, normal:(0, 0.032928, 0.999458), position:(-9.748708, 0.295415, 0.99081), rid:[RID], shape:0}
KinematicBody
Hit:{collider:[KinematicBody:1184], collider
id:1184, normal:(0.001229, 0.031697, 0.999497), position:(9.453918, 0.492391, 0.988022), rid:[RID], shape:0}
KinematicBod

What I want to output is "body1" when I click on it.

Edit

Thanks for helping me, I figured it out. It was a scene hierarchy problem. The code above is fine. In the KinematicBody scene I used an empty Spatial node as the scene root. That means that the raycast collision event is correctly captured by the physics engine to the second node in the hierarchy, the actual KinematicBody node. That is because this node is interacting physically with the ray cast, not Spatial. If one moves the KinematicBody to the top as the root of the instanced scene, then the sript will return correctly body1 or body2.

To keep the Spatial node as your scene root, since the reference to the cinematic objects is set, one could simply go up the node hierarchy.

    if hits:
        print(hits.collider.name)
        var c = hits.collider
        print (c.get_parent().name)
in Engine by (34 points)
edited by

my set up is different than yours but I can print a selection as kinematicbody:1404 , my selection variable name is item if I print "item.name" it prints "PlayerJeep". that is the equivalent of the first entry in the library your printing.name "KinematicBody:1184.name"

I dont have enough experience to know it would work but I would try something like "print(collider[0].name)" and see if that gets what you are looking for.

Thats what print(hits.collider.name) was doing, but it prints the Scene's node name (KinematicBody), while I need the instance name ("body1" or "body2"). So far I have no way of knowing which instance of Body I clicked.

1 Answer

0 votes
Best answer

You can access the KinematicBody by hits.collider.

The result of the intersect_ray method is a dictionary which contains the following information:

position: Vector2 # point in world space for collision
normal: Vector2 # normal in world space for collision
collider: Object # Object collided or null (if unassociated)
collider_id: ObjectID # Object it collided against
rid: RID # RID it collided against
shape: int # shape index of collider
metadata: Variant() # metadata of collider

You can find more info about the topic in the Godot docs.

by (148 points)
selected by

That's what I was doing, but how do I obtain the instanced node name ("body1" or "body2") from the object ID. After trying for an hour or two I think it might even ne impossible, because the object IDs come from the physical state space, that runs in a separate thread from the game space. But I am not sure.

Frankly without the ability to obtain the scene instance of a certain collider the dictionary is quite unhelpful, unless one just wants to check that objects clicked are of a certain type.

I put together an example based on your code snippet and it worked.
enter image description here
Could you share your scene hierarchy? Maybe something is off with it.

Dude. You are awesome! I figured it up now, thanks for the tip.

I edited the question with the answer :)

If you ever have another issue like that, know that you can use the remote scene tree while debugging your game. It's a different tab in the scene tree dock that appears when you launch the game in debug. You would have seen that the spatial node was indeed correctly named "body1".

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 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 webmaster@godotengine.org with your username.

Categories