Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Missing CollisionObject input_event integration. #16

Open
Splizard opened this issue Apr 18, 2022 · 4 comments
Open

Missing CollisionObject input_event integration. #16

Splizard opened this issue Apr 18, 2022 · 4 comments

Comments

@Splizard
Copy link
Contributor

Splizard commented Apr 18, 2022

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:

  1. emit a raycast from the primary camera whenever these events are triggered and then call _input_event on the collider.
  2. provide a helper function for converting the Godot touch events inside of a _input_event handler (leveraging the existing raycasts), for example:
func _on_input(camera, event, position, normal, shape_idx):
    var gestures = InputGestureEvents(event)
    for gesture in gestures:
        // handle events
@Federico-Ciuffardi
Copy link
Owner

Federico-Ciuffardi commented May 1, 2022

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 the direct_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.

@JeffBusch
Copy link

JeffBusch commented Aug 19, 2022

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.

@Federico-Ciuffardi
Copy link
Owner

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.

@dpnnl
Copy link

dpnnl commented Apr 17, 2024

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 the direct_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'.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants