In the post Godot Tutorial – Part 5: Player movement, we saw how to move the player using keyboard and joypad. In the comments of that tutorial, a reader asked for suggestions on how to move the player by dragging it around with the mouse. In this small bonus tutorial, we will see how to drag KinematicBody2D nodes.
Warning! This tutorial require the CollisionShape2D node added in Part 6: Physics and collisions tutorial, so don’t read this tutorial before you complete that!
Preparing player node for dragging
Let’s open the SimpleRPG project.
First thing, select the Player node. In the Inspector, in the properties inherited from CollisionObject2D, enables the Pickable option.

A pickable object can detect the mouse pointer entering/leaving, and if the mouse pointer is inside it, report input events through the _input_event() method. We will use the press and release of the left mouse button respectively to begin and end player dragging.
The script
Open Player’s script. First, we will need a variable to store whether dragging is active or not. Write this code next to the declaration of the speed variable:
# Player dragging flag
var drag_enabled = false
Now, we need to add two new functions to the script.
The first is _input_event(), which, as we mentioned earlier, is used to intercept mouse events that specifically involve the player.
func _input_event(viewport, event, shape_idx):
if event is InputEventMouseButton:
if event.button_index == BUTTON_LEFT:
drag_enabled = event.pressed
The working of this function is simple: when an InputEventMouseButton event is detected (i.e. the press or release of a mouse button), we check that the button pressed is the left one. If so, the drag_enabled variable is set to the value of event.pressed: true if the button is pressed and false otherwise.
The second function we must add is _input(). This function (inherited from Node) is called when any input is detected. We must implement this function because it can happen that the mouse button is released when the pointer is outside the player. In that case, _input_event() does not receive the event, and the dragging procedure will not be completed correctly.
func _input(event):
if event is InputEventMouseButton:
if event.button_index == BUTTON_LEFT and not event.pressed:
drag_enabled = false
The code is very similar to the previous function, but we only handle the release of the mouse button. Otherwise, player dragging would start by clicking anywhere on the screen.
Finally, in the _physics_process() function, insert this code immediately before calling 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;
If drag_enabled is true, the function calculates player’s movement as the difference between the position of the mouse in global coordinates (obtained by calling the function get_global_mouse_position()) and the current position of Player. The move_and_collide() function will perform this movement, placing the player at the cursor position.

Limiting movement speed
The code we wrote works, but it allows us to move the player much faster than when we use the keyboard or the joypad. So, we want to limit the speed to the value set in the speed variable.
To do this, we need to check if the calculated movement is greater than what is possible at maximum speed. In that case, we need to recalculate the movement so that it’s in the same direction, but limited in length.
Enter this code before the move_and_collide() function, inside the if block:
if movement.length() > (speed * delta):
movement = speed * delta * movement.normalized()
Now, the player can’t move faster than its maximum speed:

Below is the updated script code:
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
Conclusions
In this tutorial, we have learned how to use mouse events to move a KinematicBody2D node by dragging it across the screen. With a few minor modifications, it is also possible to create a point and click movement system (I leave this as an exercise, but if you need help, leave a comment below).
23 Comments
Matt · January 3, 2020 at 5:15 pm
This code didn’t work for me. I basically had to modify the _input method to add the following else condition:
elif event.button_index == BUTTON_LEFT and event.pressed:
drag_enabled = true
I don’t think the _input_event is even needed, as in my debugging it never fired.
Davide Pesce · January 6, 2020 at 8:18 pm
Have you enabled the Pickable property of the Player node? The _input_event() function is called only if Pickable is enabled.
Your solution does not implement dragging. With your code, the player moves by clicking anywhere in the window.
Charlie · January 12, 2020 at 9:47 pm
I have the same problem, and yeah I’ve triple checked to make sure Pickable is enabled. Do we have to manually connect the signal for this?
Davide Pesce · January 13, 2020 at 7:26 am
You don’t need to connect the signal, the _input_event function is called anyway. Try to check if at least one collision layer is selected for Player (you can find it in the Inspector, in the PhysicsBody2D section).By default, the first layer should be selected, but if for some reason it’s not, the input events do not work.
Charlie · January 14, 2020 at 2:04 am
Yep, that’s selected. Tried messing with different layers, doesn’t seem to make any difference. I can’t even get any console print output from the _input_event function.
Davide Pesce · January 14, 2020 at 1:09 pm
I should take a look at your project to be able to help you… if you can upload it somewhere (on Dropbox or Google Drive for example) and send me the link I will.
Sharon · January 19, 2020 at 1:30 pm
The issue is that part 5.1 builds on part 6 and not part 5.
Part 6 add CollisionShape2D, which is needed for this code to work.
Davide Pesce · January 19, 2020 at 7:41 pm
This issue was fixed a few days ago thanks to Permagate’s comment. I’ve changed the order of the tutorials and there is now a warning at the beginning of this one.
Permagate · January 15, 2020 at 2:44 pm
I also encountered an issue where _input_event was not executed for some reasons. After mucking around, I found out the issues:
1. _input_event will work if both pickable flag in the KinematicBody2D is checked AND it has a CollisionShape2D child. This page is linked from Part 5. At that point, CollisionShape2D has not been added in the tutorial yet (it is added in the next chapter).
2. The other issue was when I added ColorRect node under Root node. This also prevents _input_event from firing. By default, its MouseFilter mode is set to stop, which means it will catch any mouse events and stop it from being handled by any other nodes. I fixed it by setting the mouse filter (In Inspector, Control -> Mouse -> Filter) to Ignore.
Davide Pesce · January 15, 2020 at 3:43 pm
Yeah, you’re right! As soon as possible I update the tutorial to report this thing, thanks for the feedback!
It was written in the tutorial where the ColorRect is added:
Permagate · January 16, 2020 at 12:36 am
Hehe, now you know I haven’t completed the tutorial yet. Hopefully I can finish it soon. You have one of the better tutorial for godot beginner like me in my opinion, so thank you!
Charlie · January 16, 2020 at 2:00 am
Aha, yes that was the trick! (adding a CollisionSHape2D child) Thanks for pointing that out.
angel · April 12, 2020 at 6:36 pm
hey, I am new in godot, y want to know how can i move my character (an area2D) with swipes, I’m making a game for android and I want to move the character by swipes, like angry birds, went I drag the character in any direction it will get shot to the oposite side, I don’t know how to do it
Davide Pesce · April 12, 2020 at 10:30 pm
Hi angel, I could not give you a comprehensive answer in a comment, but you gave me an idea for a tutorial! In the next few days I will write something about it.
Davide Pesce · May 2, 2020 at 3:41 pm
Given the limited free time available, it took me longer than expected… but if you are still interested, here you can find the tutorial on Angry Birds-style movement: How to make a slingshot using a RigidBody2D
Juanma · June 7, 2020 at 11:41 am
If anyone is struggling with the “click and point”. you can find a possible solution in the godot docs https://docs.godotengine.org/en/stable/tutorials/2d/2d_movement.html#click-and-move
Tim · July 29, 2020 at 1:09 pm
I don’t get it. Just tried to get started and tried to make the example from the godot doc (https://docs.godotengine.org/de/stable/getting_started/step_by_step/exporting.html).
Now I want simply to control my player with my finger on my android smartphone. It just has to follow it (like in the game Archero for example). Isn’t it the same principle as with the mouse?
I’m new to godot and I want to try some ideas for a smartphone app but for that I have to understand this kind of movement 😀
Davide Pesce · July 29, 2020 at 3:42 pm
Godot “translates” touch inputs into equivalent mouse inputs, so what works for mouse also works for touch. The code on the page you linked does what you want, I didn’t understand exactly how I can help you…
Tim · July 30, 2020 at 7:02 am
The code on the page let’s the player just walk to the point where I touched. I don’t want letting the player walk to a point which I touched. I want the player follow my finger while I touch the touchscreen.
Davide Pesce · July 30, 2020 at 8:43 am
OK! I got it! To follow your finger, add this variable to the script:
and change the _input and _process function like this:
Tim · July 30, 2020 at 9:35 am
Works 🙂 Thank you very much for your help 😉
Kavya · March 8, 2021 at 7:12 am
something went wrong..
in this line
var velocity = target – position
the identifier “target isn’t dclared in the current scope is shown
my script is as follow
extends KinematicBody2D
# Player movement speed
export var speed = 75
var button_pressed = false
# Player dragging flag
var drag_enabled = false
func _process(delta):
if button_pressed:
target = get_global_mouse_position()
else:
target = position
var velocity = target – position
if velocity.length() > 10:
$AnimatedSprite.play()
velocity = velocity.normalized() * speed
else:
$AnimatedSprite.stop()
velocity = Vector2()
position += velocity * delta
position.x = clamp(position.x, 0, screen_size.x)
position.y = clamp(position.y, 0, screen_size.y)
if velocity.x != 0:
$AnimatedSprite.animation = “walk”
$AnimatedSprite.flip_v = false
$AnimatedSprite.flip_h = velocity.x 0
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:
button_pressed = (event.button_index == BUTTON_LEFT and event.pressed)
i am new to godot and I really need such tutorials
Thanks!
kavya · March 9, 2021 at 8:41 am
my player can be dragged but it does not animates
i had followed the 2d sprite animation to get the following codes
extends KinematicBody2D
# Player movement speed
export var speed = 75
# Player dragging flag
var drag_enabled = false
var last_direction = Vector2(0, 1)
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)
# Animate player based on direction
animates_player(direction)
func animates_player(direction: Vector2):
if direction != Vector2.ZERO:
# update last_direction
last_direction = direction
# Choose walk animation based on movement direction
var animation = get_animation_direction(last_direction) + “_walk”
# Play the walk animation
$Sprite.play(animation)
else:
# Choose idle animation based on last movement direction and play it
var animation = get_animation_direction(last_direction) + “_idle”
$Sprite.play(animation)
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
func get_animation_direction(direction: Vector2):
var norm_direction = direction.normalized()
if norm_direction.y >= 0.707:
return “down”
elif norm_direction.y <= -0.707:
return "up"
elif norm_direction.x = 0.707:
return “right”
return “down”