Godot Version
Godot 4.4
Question
Hi everybody. I’m a beginner and I’m trying to figure out how to implement mouse control in the same way that Path of Exile, Diablo, and Last Epoch use:
- hold down left click away from the character and the character walks towards the cursor
Here is what I’ve got so far:
extends CharacterBody2D
@export var speed = 0
var target = position
func _input(event: InputEvent) -> void:
if event.is_action_pressed("left_click"):
target = get_global_mouse_position()
speed = 200
else:
speed = 0
func _physics_process(delta: float) -> void:
velocity = position.direction_to(target) * speed
look_at(target)
if position.distance_to(target) > 10:
move_and_slide()
Right now it sort of works as long as I keep the cursor still. As soon as I move the cursor, the character stops moving. Any help would be appreciated.
Hi!
I believe the event that’s received when moving the mouse is not considered a pressed action. I might be wrong, but you should try that way:
- On left click just pressed: set a
moving
boolean to true in your script.
- On left click released: set the same
moving
boolean to false.
- In
_physics_process
, if moving
is true, get the mouse global position there, and move.
You don’t have to handle input on every mouse motion, as you only need to know if it’s been pressed or released to switch state.
Something like this (this is code I wrote on the fly so it may not work directly, you may need to adjust some errors in it, it’s just to show the idea):
extends CharacterBody2D
@export var speed = 200
var target = position
var moving: bool = false
func _input(event: InputEvent) -> void:
if event.is_action_just_pressed("left_click"):
moving = true
elif event.is_action_released("left_click"):
moving = false
func _physics_process(delta: float) -> void:
if moving:
velocity = position.direction_to(target) * speed
look_at(target)
if position.distance_to(target) > 10:
move_and_slide()
Also, as I did in my code, it’s cleaner to leave the exported speed value to the movement speed and not use it to nullify a movement. Moving with a speed of 0 is different from not moving at all, and it could lead to some issues later on, so keep it to the same value, and just don’t use it when player is not moving.
1 Like
Thanks so much. Your code didn’t work at first but I added “target = get_global_mouse_position()” to the input function and now it works perfectly.
extends CharacterBody2D
@export var speed = 200
var target = position
var moving: bool = false
func _input(event: InputEvent) -> void:
target = get_global_mouse_position()
if event.is_action_pressed("left_click"):
moving = true
elif event.is_action_released("left_click"):
moving = false
func _physics_process(delta: float) -> void:
look_at(target)
if moving:
velocity = position.direction_to(target) * speed
if position.distance_to(target) > 10:
move_and_slide()
1 Like
Great! Indeed I forgot it.
From what I understand, the character looks at the mouse every frame, even if not moving. If you want it to only look at the mouse when moving, then you should get the mouse position only when moving, as you don’t need it otherwise (and keep in mind that _input
is called on any input, so that may result in a lot of get_global_mouse_position()
calls for nothing (not that it would break your game performances, but it’s always worth optimizing a bit when it takes a few seconds).
Something like this, just in case you want to do the change, but it’s your call 
extends CharacterBody2D
@export var speed = 200
var target = position
var moving: bool = false
func _input(event: InputEvent) -> void:
if event.is_action_pressed("left_click"):
moving = true
elif event.is_action_released("left_click"):
moving = false
func _physics_process(delta: float) -> void:
look_at(target)
if moving:
target = get_global_mouse_position()
velocity = position.direction_to(target) * speed
if position.distance_to(target) > 10:
move_and_slide()
1 Like