Need Help with Godot 4 3D mouse movement

Godot Version

4

Question

Hellooo I’m new to game design and I’m trying to make a 3d top down game, with moba-type movement. I’m using raycasting and it works, but it’s very inaccurate sometimes. Also I want my character to move to the click position, but my character moves to click position only when I hold the mouse button.

This is the code:

extends CharacterBody3D

@export var SPD = 10
@export var fall_acceleration = 75

var target_velocity = Vector3.ZERO

func mouse_cast():
var space_state = get_world_3d().direct_space_state
var camera = get_tree().root.get_camera_3d()
var mouse_position = get_viewport().get_mouse_position()
var origin = camera.project_ray_origin(mouse_position)
var end = origin + camera.project_ray_normal(mouse_position) * 1500
var query = PhysicsRayQueryParameters3D.create(origin, end)
query.collide_with_areas = true
query.exclude = [self]

var result = space_state.intersect_ray(query)

if result.has("position"):
	return result["position"]
return Vector3()

func move(delta):
var direction = Vector3.ZERO

if Input.is_action_pressed("click_move"):
	direction = mouse_cast()

if direction != Vector3.ZERO:
	direction = direction.normalized()
	direction.y = 0
	$Pivot.basis = Basis.looking_at(-direction)

target_velocity.x = direction.x * SPD
target_velocity.z = direction.z * SPD

if not is_on_floor():
	target_velocity.y = target_velocity.y - (fall_acceleration * delta)

if position.distance_to(mouse_cast()) > 1:
	velocity = target_velocity
	move_and_slide()

func fall_n_die():
if self.position.y < -8:
get_tree().quit()

func _physics_process(delta):
move(delta)
fall_n_die()

Thank you very much!

Note: the Camera node is a child node of the player node and uses orthogonal projection

It stops when you’re not pressing the mouse button because direction gets reset to zero every frame. Try something like this, have a target_position variable that don’t get reset and the character can keep going towards it (I haven’t tested it…)

var target_pos = Vector3.ZERO

func move(delta):
    var direction = Vector3.ZERO
	if Input.is_action_pressed("click_move"):
		target_pos = mouse_cast()
	
		if target_pos != Vector3.ZERO:
			direction = target_pos.normalized()
			direction.y = 0
			$Pivot.basis = Basis.looking_at(-direction)
	
	target_velocity.x = direction.x * SPD
	target_velocity.z = direction.z * SPD
	
	if not is_on_floor():
		target_velocity.y = target_velocity.y - (fall_acceleration * delta)
	
	if position.distance_to(target_pos) > 1:
		velocity = target_velocity
		move_and_slide()
    else:
        velocity = Vector3.ZERO

1 Like

It works well, but I think there is a problem with detecting the mouse position (mouse_cast function), because if I click near my character it’s fine, but if click far away it’s completely off.
Code:

func mouse_cast():
var space_state = get_world_3d().direct_space_state
var camera = get_tree().root.get_camera_3d()
var mouse_position = get_viewport().get_mouse_position()
var origin = camera.project_ray_origin(mouse_position)
var end = origin + camera.project_ray_normal(mouse_position) * 4000
var query = PhysicsRayQueryParameters3D.create(origin, end)
query.collide_with_areas = true
query.exclude = [self]

var result = space_state.intersect_ray(query)

if result.has("position"):
	return result["position"]
return Vector3()

I don’t know, I’m using the same code and it works for me, though my camera isn’t orthogonal so maybe it has something to do with that.

I’ll look into it. Thanks a mill!