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?

asked Jul 13, 2019 in Engine by johnygames (1,839 points)

2 Answers

+1 vote
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.

answered Jul 14, 2019 by Dlean Jeans (3,917 points)
selected Jul 14, 2019 by johnygames

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

answered Jul 13, 2019 by BraindeadBZH (1,020 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.