0 votes

Hi, I'm new to Godot so bare with me. I've worked with Unity a lot and decided to give Godot a try. I have a 3D top down game in which the player is moved with WASD and steered with the mouse. With a non-rigid body this was simple to do using the LookAt method to always face the player towards the mouse cursor but since I do not want to simulate the physics myself I am trying to get this working with a RigidBody instead using forces.

I based my code off this example here: https://docs.godotengine.org/en/3.1/tutorials/physics/rigid_body.html

My code works but it's not great. Player movement works well but rotation is not great. At points the player will spin for no reason or will move position by moving the mouse when it should only rotate. My code is below:

Vector3 target;  

public override void _Input(InputEvent @event)
{
    if (@event is InputEventMouseMotion eventMouseMotion)
    {
        Vector3 from = camera.ProjectRayOrigin(eventMouseMotion.Position);
        Vector3 to = from + camera.ProjectRayNormal(eventMouseMotion.Position) * rayLength;

        PhysicsDirectSpaceState directState = PhysicsServer.SpaceGetDirectState(camera.GetWorld().GetSpace());
        Godot.Collections.Dictionary result = directState.IntersectRay(from, to);

        if (result["collider"] is CSGMesh)
        {
            Vector3 resultVector = (Vector3)result["position"];
            Vector3 xyVector = new Vector3(resultVector.x, Translation.y, resultVector.z);

            target = xyVector;
        }
    }
}

public override void _IntegrateForces(PhysicsDirectBodyState state)
{
    Vector3 upDir = new Vector3(0, 1, 0);
    Vector3 curDir = Transform.basis.Xform(new Vector3(0, 0, 1));
    Vector3 targetDir = (target - Transform.origin).Normalized();
    float rotationAngle = Mathf.Acos(curDir.x) - Mathf.Acos(targetDir.x);

    if (targetDir.z < 0)
    {
        rotationAngle = -rotationAngle;
    }

    state.SetAngularVelocity(upDir * (rotationAngle / state.GetStep()));

    if (Input.IsActionPressed("player_move_forward"))
    {
        AddForce(GetGlobalTransform().basis.z * movementSpeed, -GetGlobalTransform().basis.z);
    }
    else if (Input.IsActionPressed("player_move_backward"))
    {
        AddForce(-GetGlobalTransform().basis.z * movementSpeed, GetGlobalTransform().basis.z);
    }

    if (Input.IsActionPressed("player_move_left"))
    {
        AddForce(GetGlobalTransform().basis.x * movementSpeed, -GetGlobalTransform().basis.x); 
    }
    else if (Input.IsActionPressed("player_move_right"))
    {
        AddForce(-GetGlobalTransform().basis.x * movementSpeed, GetGlobalTransform().basis.x);
    }
}

What it does is a RayCast from the camera down at the mouse location. There is an invisible mesh plane that it will collide with which returns back a Vector3 position. Next I take the x and z component and create a new Vector3 with the y set to the players current y. This is our world target to point our player towards. Now I may be doing this completely wrong so any suggestions a greatly appreciated. I then use the code from the example to rotate the player to face the target Vector3.

Any suggestions to get this working properly or a better method would be appreciated. Also code examples in GDScript or C# will work.

Edit: I will also note that using the example code does not work fully. It will only rotate 180 and not the full 360 and so I had to add in the code below but I feel this isn't the correct way to make this work.

if (targetDir.z < 0)
 {
     rotationAngle = -rotationAngle;
 }
in Engine by (21 points)

Please log in or register to answer this question.

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 Frequently asked questions and 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 [email protected] with your username.