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()
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
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()