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)

1 Like

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

Hey, i’m having the exact same issue currently. I’m working on the same kind of Roblox camera than you, but it seem like impossible to achieve it because of inconsistency when mouse is moving. Did you find a fix ?

1 Like

i couldn’t find any unfortunately, and i don’t think there is a way to solve it without changing the engine to handle mouse inputs differently on Windows, since the 3d viewport also has the same issue. (sorry for the late reply btw)

2 Likes

Hello i have fixed this problem let me know if you are still interested

@TemTem Please post your solution. If not this person, then any other person that has a similar problem in the future, can benefit from it.

2 Likes

hi. I’ve noticed the same mouse warping issue on Windows when releasing capture while the cursor is moving. A small delay via await get_tree().process_frame before warping sometimes helps, but it’s not always reliable. Might be worth trying call_deferred or reporting it as a platform-specific bug on GitHub.

1 Like

So yea my current working code look like this. Seems to work consistently.

   			if event.button_index == MOUSE_BUTTON_RIGHT and event.pressed:
				savedMousePosition = get_viewport().get_mouse_position()
				set_mouse_captured()
			elif event.button_index == MOUSE_BUTTON_RIGHT:
				Input.mouse_mode = Input.MOUSE_MODE_HIDDEN
				while get_viewport().get_mouse_position().distance_to(savedMousePosition) > 15.0:
					get_viewport().warp_mouse(savedMousePosition)
					await get_tree().process_frame

for reference i’ve tried call_deferred (both with and without a delay) and it hasn’t helped for me- although i am new so take that with a pinch of salt !