Tutorial de Godot – Parte 22: Arrastrando al jugador con el mouse

En la publicación Tutorial de Godot – Parte 5: Movimiento del jugador , vimos cómo mover al jugador usando el teclado y el joypad. En los comentarios de ese tutorial, un lector pidió sugerencias sobre cómo mover al jugador arrastrándolo con el mouse . En este pequeño tutorial extra, veremos cómo arrastrar nodos KinematicBody2D .

¡Advertencia! Este tutorial requiere el nodo CollisionShape2D agregado en la Parte 6: Tutorial de física y colisiones , ¡así que no lea este tutorial antes de completarlo!

Preparando el nodo del jugador para arrastrar

Abramos el proyecto SimpleRPG.

Lo primero, selecciona el nodo Player . En el Inspector , en las propiedades heredadas de CollisionObject2D , habilita la opción Pickable .

Un objeto seleccionable puede detectar la entrada/salida del puntero del mouse y, si el puntero del mouse está dentro, informar eventos de entrada a través del método _input_event() . Presionaremos y soltaremos el botón izquierdo del mouse respectivamente para comenzar y finalizar el arrastre del jugador.

La secuencia de comandos

Abra el script del jugador . Primero, necesitaremos una variable para almacenar si el arrastre está activo o no. Escribe este código junto a la declaración de la variable de velocidad :

# Player dragging flag
var drag_enabled = false

Ahora, necesitamos agregar dos nuevas funciones al script.

El primero es _input_event() , que, como mencionamos anteriormente, se usa para interceptar eventos del mouse que involucran específicamente al jugador.

func _input_event(viewport, event, shape_idx):
	if event is InputEventMouseButton:
		if event.button_index == BUTTON_LEFT:
			drag_enabled = event.pressed

El funcionamiento de esta función es sencillo: cuando se detecta un evento InputEventMouseButton (es decir, la pulsación o liberación de un botón del ratón), comprobamos que el botón pulsado es el izquierdo. Si es así, la variable drag_enabled se establece en el valor de event.pressed : verdadero si se presiona el botón y falso en caso contrario.

La segunda función que debemos agregar es _input() . Esta función (heredada de Node ) se llama cuando se detecta cualquier entrada. Debemos implementar esta función porque puede ocurrir que se suelte el botón del ratón cuando el puntero está fuera del reproductor. En ese caso, _input_event() no recibe el evento y el procedimiento de arrastre no se completará correctamente.

func _input(event):
	if event is InputEventMouseButton:
		if event.button_index == BUTTON_LEFT and not event.pressed:
			drag_enabled = false

El código es muy similar a la función anterior, pero solo manejamos la liberación del botón del mouse. De lo contrario, el arrastre del jugador comenzaría haciendo clic en cualquier parte de la pantalla.

Finalmente, en la función _physics_process() , inserte este código inmediatamente antes de llamar a move_and_collide() :

# If dragging is enabled, use mouse position to calculate movement
if drag_enabled:
	var new_position = get_global_mouse_position()
	movement = new_position - position;

Si drag_enabled es verdadero, la función calcula el movimiento del jugador como la diferencia entre la posición del mouse en coordenadas globales (obtenidas llamando a la función get_global_mouse_position() ) y la posición actual del jugador. La función move_and_collide() realizará este movimiento, colocando al jugador en la posición del cursor.

Limitación de la velocidad de movimiento

El código que escribimos funciona, pero nos permite mover el reproductor mucho más rápido que cuando usamos el teclado o el joypad. Entonces, queremos limitar la velocidad al valor establecido en la variable de velocidad.

Para hacer esto, debemos verificar si el movimiento calculado es mayor que el posible a la velocidad máxima. En ese caso, necesitamos recalcular el movimiento para que sea en la misma dirección, pero limitado en longitud.

Introduce este código antes de la función move_and_collide() , dentro del bloque if:

if movement.length() > (speed * delta):
	movement = speed * delta * movement.normalized()

Ahora, el jugador no puede moverse más rápido que su velocidad máxima:

A continuación se muestra el código de secuencia de comandos actualizado:

extends KinematicBody2D

# Player movement speed
export var speed = 75

# Player dragging flag
var drag_enabled = false

func _physics_process(delta):
	# Get player input
	var direction: Vector2
	direction.x = Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left")
	direction.y = Input.get_action_strength("ui_down") - Input.get_action_strength("ui_up")
	
	# If input is digital, normalize it for diagonal movement
	if abs(direction.x) == 1 and abs(direction.y) == 1:
		direction = direction.normalized()
	
	# Calculate movement
	var movement = speed * direction * delta
	
	# If dragging is enabled, use mouse position to calculate movement
	if drag_enabled:
		var new_position = get_global_mouse_position()
		movement = new_position - position;
		if movement.length() > (speed * delta):
			movement = speed * delta * movement.normalized()
	
	# Apply movement
	move_and_collide(movement)

func _input_event(viewport, event, shape_idx):
	if event is InputEventMouseButton:
		if event.button_index == BUTTON_LEFT:
			drag_enabled = event.pressed

func _input(event):
	if event is InputEventMouseButton:
		if event.button_index == BUTTON_LEFT and not event.pressed:
			drag_enabled = false

Conclusiones

En este tutorial, hemos aprendido a usar eventos del mouse para mover un nodo KinematicBody2D arrastrándolo por la pantalla. Con algunas modificaciones menores, también es posible crear un sistema de movimiento de apuntar y hacer clic (lo dejo como ejercicio, pero si necesita ayuda, deje un comentario a continuación).