How to keep mouse still or from warping to the middle?

Godot Version

4.6

Question

Hello!
I am making a third-person camera, and I was trying to implement a way so holding right click would let you rotate your camera by moving your mouse without moving the cursor, similar to Roblox’s camera.

The script currently saves the mouse position before capturing it whenever you hold right-click, and when let go, makes it visible and warps it back to where it previously was. This works if it’s let go while the mouse isn’t being moved, but when the mouse is still moving, the cursor gets warped to the middle of the screen.

It also seems the Godot 3D viewport suffers the same issue, as it also warps your mouse to the middle when you let go while moving your mouse.

Anyways, is there a better way to implement this or a way to fix it? Or maybe a different way to keep the mouse still?

@export_range(0.0, 1.0) var mouse_sensitivity = 0.01
@export var tilt_limit = deg_to_rad(80)
var rotating = false
var old_mouse_position: Vector2i

func _process(_delta: float) -> void:
	if Input.is_action_just_pressed("rotate camera"):
		rotating = true
		old_mouse_position = get_viewport().get_mouse_position()
		Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
	if Input.is_action_just_released("rotate camera"):
		rotating = false
		Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
		DisplayServer.warp_mouse(old_mouse_position)

func _unhandled_input(event : InputEvent) -> void:
	if event is InputEventMouseMotion and rotating:
		rotation.y -= event.relative.x * mouse_sensitivity
		rotation.x -= event.relative.y * mouse_sensitivity
		rotation.x = clampf(rotation.x, -tilt_limit, tilt_limit)

You don’t need the _process(), you can do it all in the _unhandled_input(), should be more efficient this way.

I haven’t changed any of the main logic and this code works for me no matter if I move the mouse or let it be still. Does it not work for you? What happens for you?

extends Node3D


@export_range(0.0, 1.0) var mouse_sensitivity = 0.01
@export var tilt_limit = deg_to_rad(80)
var rotating = false
var old_mouse_position: Vector2i


func _unhandled_input(event : InputEvent) -> void:
	if event.is_action_pressed("rotate camera"):
		rotating = true
		old_mouse_position = get_viewport().get_mouse_position()
		Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
	elif event.is_action_released("rotate camera"):
		rotating = false
		Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
		DisplayServer.warp_mouse(old_mouse_position)
	elif event is InputEventMouseMotion and rotating:
		rotation.y -= event.relative.x * mouse_sensitivity
		rotation.x -= event.relative.y * mouse_sensitivity
		rotation.x = clampf(rotation.x, -tilt_limit, tilt_limit)
1 Like

Thanks for the quick reply, and yeah, for some reason my mouse teleports back still. The only idea I have is maybe my computer’s acting up?

This is how it works for me, I don’t see any reason why it should work different for you. Maybe you can try creating a new project to see if it’ll work there to isolate the case?

I just tested it on a new project, but it still teleports my mouse

Are you developing on Windows? It could be a Windows thing then, because I’m testing on Linux.
Maybe try awaiting a frame before warping the mouse? I don’t have any better idea.

1 Like

Yeah, probably a windows thing. The await helps fix it mostly