Not sure how/where to handle input and ray casting

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

I’m new to Godot and I am trying to figure out what to handle where.
Please consider the following script:

extends StaticBody

onready	var camera = get_node("/root/Spatial/Camera")
onready var raycast = get_node("/root/Spatial/RayCast")

var selected_object = null
var left_mouse_clicked = true

func _ready():
	pass

func _process(_delta):	
	pass	

func change_rigidbody_color(body, color):
	var mesh = body.get_node("MeshInstance")
	var material = mesh.get_surface_material(0)
	material.albedo_color = color
	
func _physics_process(_delta):
	if left_mouse_clicked:	
		left_mouse_clicked = false		
		if (raycast.is_colliding()):
			var other = raycast.get_collider() 						
			if other is RigidBody:			
				other.apply_impulse(Vector3.ZERO, Vector3(0,5,0))
				change_rigidbody_color(other, Color(0.2, 1, 0.2))											
				if selected_object != null and selected_object != other:
					change_rigidbody_color(selected_object, Color(0.5, 0.5, 0.5))											
				selected_object = other
	
func _input(event):
	if event is InputEventMouseButton and event.button_index == BUTTON_LEFT and event.pressed:		
		var from = camera.project_ray_origin(event.position)
		var to = from + camera.project_ray_normal(event.position) * 1000;
		raycast.translation = from;
		raycast.cast_to = to;		
		left_mouse_clicked = true

The idea is that I check whether or not the user has clicked a rigidbody with the left mouse button and then perform the following tasks:

  • Change the color of the rigidbody
  • Assign the rigidbody to the selected_object variable
  • Make the rigidbody jump a little

And the script does all of that but is this really the way to handle it?

I process the event in _input(event).
If the mouse button is pressed I update the raycast
and set the left_mouse_clicked flag.

In _physics_process(_delta): I check that flag
and if it is set I check raycast.is_colliding()).

Basic idea:

  • Update the raycast in _input(event)
  • Query the raycast in func _physics_process(_delta)

I had another version before:

  • Set the left_mouse_clicked flag in _input(event)_
  • Update the raycast in func _physics_process(_delta)
  • Query the raycast in func _physics_process(_delta)

The problem with this was that the query would often return the
cached value because the raycast did not get time to
update it’s position and vector yet.

To solve that issue I had to call force_raycast_update()
before raycast.is_colliding() at which point I could even
set raycast.enabled to false

Next up I wanted to handle other inputs like:

if Input.is_action_pressed("ui_up") 

which some samples seem to handle in _physics_process(_delta) which,
in the script on this page, would mean I’d be handling input in two different functions.
(Also, coming from Unity, I feel like _phycis_process(_delta) might not be the correct place to handle input)

So (when) should input be handled in _process(_delta), _physics_process(_delta) or _input(event)

Should the raycast be updated in _input(event) or in _physics_process(_delta)

The tutorial in the docs ends like this:

const ray_length = 1000

func _input(event):
    if event is InputEventMouseButton and event.pressed and event.button_index == 1:
          var camera = $Camera
          var from = camera.project_ray_origin(event.position)
          var to = from + camera.project_ray_normal(event.position) * ray_length

Remember that during _input(), the space may be locked, so in practice this query should be run in _physics_process().

but it feels to me like there’s some information missing, information that is probably very obvious to the trained mind but not so much to newcomers.

Generally speaking, you want to handle input based on what you do with it.
if it needs to do some physics stuff(like walking) when it goes to the _physics_process(or process if it just moving without collision detection)… if you want to do something exactly when something happens(like a first person camera controller or touch input stuff) then you want to go to the _input call.

rustyStriker | 2020-04-14 16:56