Open Splizard opened 2 years ago
If I understand correctly this is similar to what happens with the buttons discussed in PR #19. I think this is something that should be fixed in the Godot engine itself. But for now I like your idea of using a raycast. I don't have much experience developing 3D games in godot but I put together something basic that should work, if you want to try it add the following code to the _emit
method in InputManager.gd:
if "position" in val:
var camera = get_viewport().get_camera()
var from = camera.project_ray_origin(val.position)
var to = from + camera.project_ray_normal(val.position) * (camera.far)
var root = get_tree().get_root()
if root is Node:
var inter = root.get_world().direct_space_state.intersect_ray(from,to)
if !inter.empty():
inter["collider"]._input_event(camera, val, inter["position"], inter["normal"], inter["shape"])
Also here is an example project I used for testing: example.zip
Some comments about the code:
camera.far
because I assume that is a reasonable length.Node
to check if the scene is 3D before trying to get the direct_space_state
but I don't know if there is a better way to do it (there probably is)._input
or _unhandled_input
method of another node where it must only be executed if the processed event is non-native. This has the advantage of not being specific to GDTIM custom events.I am running into this issue in my 2D project. I planned on using the SingleTouch/SingleTap events on an Area2D input_event() instead of using the button nodes (mouse emulation) since my project is mobile only. I'm assuming the raycast solution is only relevant in a 3D project?
Maybe I'm approaching this incorrectly but my goal was just to make my own buttons that use the GTIM events.
Mouse emulation and button nodes should work even if your project is mobile only, but maybe you have another reason.
The raycast solution, as far as I know, is not useful in 2D, but in 2D it's not that hard to do it manually. I mean you need the coordinates of the 4 vertices that define the Area2D (assuming it's a rectangle) and then with that you can check if the position of the event is inside the Area2D. I'm not sure if it makes a difference, but you should also be able to do this kind of manual detection with the button nodes, in fact all you need is 4 dots describing a rectangle.
If I understand correctly this is similar to what happens with the buttons discussed in PR #19. I think this is something that should be fixed in the Godot engine itself. But for now I like your idea of using a raycast. I don't have much experience developing 3D games in godot but I put together something basic that should work, if you want to try it add the following code to the
_emit
method in InputManager.gd:if "position" in val: var camera = get_viewport().get_camera() var from = camera.project_ray_origin(val.position) var to = from + camera.project_ray_normal(val.position) * (camera.far) var root = get_tree().get_root() if root is Node: var inter = root.get_world().direct_space_state.intersect_ray(from,to) if !inter.empty(): inter["collider"]._input_event(camera, val, inter["position"], inter["normal"], inter["shape"])
Also here is an example project I used for testing: example.zip
Some comments about the code:
- The ray must have a length. I used
camera.far
because I assume that is a reasonable length.- I check if the root of the tree is a
Node
to check if the scene is 3D before trying to get thedirect_space_state
but I don't know if there is a better way to do it (there probably is).- The code can also be placed in the
_input
or_unhandled_input
method of another node where it must only be executed if the processed event is non-native. This has the advantage of not being specific to GDTIM custom events.
Could you port this solution to Godot 4? I tried the code below:
if DEBUG: print(val.as_string())
emit_signal("any_gesture", sig, val)
emit_signal(sig, val)
Input.parse_input_event(val)
if "position" in val:
var camera = get_viewport().get_camera_3d()
var from = camera.project_ray_origin(val.position)
var to = from + camera.project_ray_normal(val.position) * (camera.far)
var root = get_tree().get_root()
if root is Node:
var ray_query = PhysicsRayQueryParameters3D.new()
ray_query.from = from
ray_query.to = to
var inter = root.get_world_3d().direct_space_state.intersect_ray(ray_query)
if !inter.is_empty():
inter["collider"]._input_event(camera, val, inter["position"], inter["normal"], inter["shape"])
But I get the following error: Invalid call. Nonexistent function '_input_event' in base 'StaticBody3D'.
I've found this project incredibly helpful for building the mobile/touch camera input for my 3D project. I wanted to use the SingleTouch/SingleTap events for selecting objects in the scene howevever the events don't appear to propogate through to the
CollisionObject
input_event
signal.https://docs.godotengine.org/en/stable/classes/class_collisionobject.html
I've had a look through the Readme here and also at the Godot documentation, there doesn't appear to be a simple way to enable this.
Here's two ideas on how this could be achieved:
_input_event
on the collider._input_event
handler (leveraging the existing raycasts), for example: