Lock Mouse Position In Radius Around RigidBody2d

Godot Version

4.3

Question

Hello! I am relatively new to Godot and I am trying to make a “rage platformer” similar to Getting Over It With Bennett Foddy where you are a gun that is traversing obstacles. I am using a RigidBody2d for the “character” and you move your mouse in a circle to fling yourself around. I am noticing some issues with the movement where if you move your mouse through the sprite it will launch you unpredictably. So I thought I would just lock the mouse movement to a radius around the player.

I have looked at various threads and even some ChatGPT and am getting closer but it still isn’t quite right. My current code locks the mouse to only be able to move in a circle but it isn’t centered around the player. It is shifted up and to the left about 500 pixels.

I originally was using global positions but that was causing the mouse to just be locked to the upper left corner of the screen so I was attempting to use viewport position after ChatGPT suggested it.

Any suggestions here would be much appreciated. Thanks in advance!

func _process(_delta: float) -> void:
	reload_progress_bar.value = reload_timer.time_left
	
	var mouse_position = get_viewport().get_mouse_position()
	var body_position = get_viewport().get_camera_2d().get_transform().basis_xform(global_position)
	var offset = mouse_position - body_position

	if abs(offset.length() - MAX_RADIUS) > 0.1:  # Avoid constant recalculation
		offset = offset.normalized() * MAX_RADIUS
		var clamped_mouse_pos = get_viewport().get_camera_2d().get_transform().basis_xform_inv(body_position + offset)
		
		get_viewport().warp_mouse(clamped_mouse_pos)

Yes, you are definitely mixing wrong coordinate systems.
Try this:

func _process(_delta: float) -> void:
	var max_distance = 200
	var node_pos_in_viewport: Vector2 = get_global_transform_with_canvas().origin
	var mouse_pos_relative_to_node: Vector2 = get_viewport().get_mouse_position() - node_pos_in_viewport
	if mouse_pos_relative_to_node.length() > max_distance:
		var offset: Vector2 = mouse_pos_relative_to_node.normalized() * max_distance
		get_viewport().warp_mouse(node_pos_in_viewport + offset)
2 Likes

You dont want this.

Basis_xform ignores the origin. It would be better to just

var body_position = get_viewport().get_camera_2d().global_position - global_position

Thank you so much! This is exactly what I needed!