To get the mouse speed, Can I use get_global_mouse_position inside _physics_process?

Godot Version

4.7.1.stable

Question

video explaining my question
tl:dr: is it ok for me to use `get_global_mouse_position()` inside func _physics_process?

I’m using it to manually calculate the mouse speed and pass that to the rigidbody , and it seems to work just fine , I’m just curious if there is something I’m missing about event.relative that i could/should(?) use instead

#---Description---
## 

#---Class---
extends Node2D
#---Signals---

#---Variables---
@export var object_follow_speed: float = 500 
@export var max_thow_speed: float = 1500
var _last_mouse_position: Vector2 
var _mouse_velocity: Vector2
#---References---
@onready var area_2d: Area2D = $Area2D
var _grabbed_object: PickupableObject2D

#---Functions---
func _ready() -> void:
	area_2d.body_entered.connect(_on_area_2d_body_entered)

# Object Movement
func _physics_process(delta: float) -> void:
	var mouse_position = get_global_mouse_position()
	area_2d.global_position = mouse_position
	
	if _grabbed_object:
		var mouse_speed = _last_mouse_position.distance_to(mouse_position) / delta
		var obj_linear_velocity = _mouse_velocity
		#var obj_linear_velocity = _grabbed_object.position.direction_to(mouse_position) * mouse_speed
		_grabbed_object.grab_linear_velocity = obj_linear_velocity
	
	_last_mouse_position = mouse_position

# Grab & Release
func _grab_object(object: PickupableObject2D) -> void:
	pass # unrelated to the question so i repaced it w pass
func _release_held_object() -> void:
	pass #

# Input & Rigidbody detection
## Check if the pickup action was just pressed to pickup (instantly checks if an object is on the area2d)
## release the object when the action is released
func _unhandled_input(event: InputEvent) -> void:
	if event is InputEventMouseMotion:
		_mouse_velocity = event.relative
		_mouse_velocity = event.screen_velocity
		Input.get_last_mouse_screen_velocity()
	
	
	
	if event.is_action_pressed("Pickup"):
		var obj = area_2d.get_overlapping_bodies()[0] if area_2d.get_overlapping_bodies() else null ##
		if obj != null and obj is PickupableObject2D:
			_grab_object(obj)
		else: 
			pass
	if event.is_action_released("Pickup"):
		if _grabbed_object != null: 
			_release_held_object()

func _on_area_2d_body_entered(body: Node2D) -> void:
	pass #
 

#---Description---
##PickupableObject2D.gd

#---Class---
extends RigidBody2D
class_name PickupableObject2D

#---Signals---

#---Variables---
var is_being_grabbed: bool
var grab_linear_velocity : Vector2

var _initial_position: Vector2
var _initial_gravity_scale : float

#---references---

#---functions---
func _ready() -> void:
	_initial_position = position
	_initial_gravity_scale = gravity_scale


func _integrate_forces(state: PhysicsDirectBodyState2D) -> void:
	## Grab movement
	if is_being_grabbed:
		gravity_scale = 0.0
		linear_velocity = grab_linear_velocity
		#rotation = 0
	else:
		gravity_scale = _initial_gravity_scale
	
	## Reset the object's position if it falls down
	if position.y > 300:
		position = _initial_position
		linear_velocity = Vector2.UP * 200
		#angular_velocity = 0

thanks in advance.

Good question. If you want to see how it works under the hood:

Yes, get_global_mouse_position() is perfectly fine to use inside _physics_process(). It’s not tied to input events, because, it simply returns the current mouse position tracked by the viewport. You can safely call it from any process callback.

The reason event.relative isn’t ideal here is that _physics_process() runs at a fixed timestep (60 Hz by default), while mouse motion events occur independently. During a single physics frame you might receive no motion events, or several. Since event.relative is only the delta for a single input event, using it as the mouse velocity for an entire physics tick can lead to missed movement or stale values.

I also noticed that in your _unhandled_input() you’re doing:

_mouse_velocity = event.relative
_mouse_velocity = event.screen_velocity

The second assignment immediately overwrites the first, so event.relative is never actually used. If multiple mouse events occur before the next physics frame, you’re also only keeping the last one.

Your current approach of calculating the velocity in _physics_process() is actually the more robust solution:

var velocity = (current_mouse_pos - last_mouse_pos) / delta

This measures the net mouse movement over the entire physics frame, regardless of how many input events occurred in between. It also naturally returns Vector2.ZERO when the mouse isn’t moving, instead of reusing the last event’s value.

For comparison:

  • Input.get_last_mouse_velocity() returns a smoothed velocity based on recent input events. It’s convenient, but because it’s smoothed and event-driven, it can feel slightly delayed for physics.

  • event.screen_velocity is the velocity for a single input event, so it has the same timing limitations as event.relative.

For something like driving a RigidBody2D every physics frame, calculating the velocity from the mouse position difference inside _physics_process() is the approach I’d recommend. I’d also remove the now-unused event.screen_velocity and Input.get_last_mouse_velocity() code to keep things clean.