0 votes

I've been trying to make a top-down game where the character faces towards the position of the mouse. I searched online and I figured out I have to use raycasting. More specifically, I implemented the following code:

func _input(event):
    if event is InputEventMouseMotion:
        var from = camera.project_ray_origin(event.position)
        var to = from + camera.project_ray_normal(event.position) * ray_length
        $player.look_at(to*Vector3(1,0,1), from)

where player is the character in question and raylength is the distance travelled by the ray. It is worth noting that 'player' is a separate scene made up of a KinematicBody and a mesh.
Though everything works as expected when the player is in the middle, everything starts malfunctioning when I move the player using move
and_slide(). This is when the object stops rotating fully in a circle.

What am I doing wrong?

in Engine by (1,859 points)

2 Answers

+2 votes
Best answer

Just tried this and it works way better than the raycast method:

func _physics_process(delta):
    var offset = -PI * 0.5
    var screen_pos = get_viewport().get_camera().unproject_position(player.global_transform.origin)
    var mouse_pos = get_viewport().get_mouse_position()
    var angle = screen_pos.angle_to_point(mouse_pos)
    player.rotation.y = -angle + offset

Raycasting requires physics bodies, if no bodies are present then it would not work anymore.

by (4,155 points)
selected by

Wow, that works!

It looks very complicated, though. I do not know how I was supposed to come up with that solution :)
Anyway, it works better than expected, because it works even when the camera is not facing top-down in a 90 degree angle to the floor. Kudos!

Dunno how I came up with that, but it's exactly how you handle it in a 2D top-down shooter with the only extra step is to unproject the player position from 3D to 2D, not that complicated.

Before that, I also worked on a 3D top-down shooter with raycasting for mouse handling so I know it doesn't work very well.

0 votes

First, if you want to update something in realtime it is better to use the _process function and if you have to move a physical object, like a KinematicBody, _physics_process.

Second, if I remember correctly, to orient a node in the direction of the mouse is to start with get_local_mouse_position (Doc). And the rotation is calculated with something like Vector2(-mouse_vec.y, mouse_vec.x).angle().

by (1,045 points)

Thank you for your comment!

getlocalmouseposition throws an error:
"Method get
localmouseposition is not declared in the current class"

This is in 3D, get_local_mouse_position() is only available for 2D nodes. Call get_viewport().get_mouse_position() for global position and subtract the node position to get the local mouse position.

Yes, you're correct I didn't realized the question was ask for 3D.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.