Controlling 3D player movement with mouse position

Godot Version

4.2.2

Question

I’m trying to prototype a simple infinite runner-style minigame, using the mouse position to control the player’s position on the x-axis. I’ve made some progress with it but am having trouble with a few things:

First, moving the player rigidbody with the mouse position the way I’m currently doing it seems to conflict with the collision system. If I move the mouse too fast, the rigidbody clips through the boundaries I’ve set at either end of the plane. I’m thinking this has to do with how I’m moving the object with my mouse in the code.

My code (I think) simply moves the object to the position on-screen that my mouse is in, without “translating” the object. This means if I start the game with my mouse off to the side of my screen, my player rigidbody will spawn off the track and fall.

Instead, what I’d like to happen is for my mouse position to be “normalized” to the center when the game starts or when the mouse isn’t moving, and then translate the player to the left / right based on the mouse movement from that normalized position, while still respecting the collision.

One other thing I can’t quite figure out is how to lock the mouse to the game window, and have it look at mouse position relative to the game window, not at mouse position relative to my entire screen.

Here’s my current code, attached to a Node3D that the rigidbody is a child of:

extends Node3D

@onready var camera := get_parent() as Camera3D
@export_range(1, 1000) var depth := 10.0
@export var should_only_set_position := true

func _process(delta):
	var mouse_pos = get_viewport().get_mouse_position()
	var cursor_pos_g = camera.project_position(mouse_pos, depth)
	global_position.x = cursor_pos_g.x

Sorry if I used any incorrect terminology, still learning.
Greatly appreciate any help. Thank you!

1 Like

Clamp the position:

global_position.x = clampf(global_position.x, left_wall.position.x, right_wall.position.x)

I would script the RigidBody, you may want to use _integrate_forces to apply force/linear velocity instead of setting positions directly. It’s much better to use the physics system for physics objects instead of position. The math is tougher though since you are working against gravity, friction, and inertia.

extends RigidBody3D

@onready var camera := get_parent() as Camera3D
@export_range(1, 1000) var depth := 10.0
@export var should_only_set_position := true

func _integrate_forces(state: PhysicsDirectBodyState3D) -> void:
	var mouse_pos = get_viewport().get_mouse_position()
	var cursor_pos_g = camera.project_position(mouse_pos, depth)

	var diff := cursor_pos_g - global_position
	# mess with diff, limiting length is usually a good idea
	state.apply_central_force(diff)