0
\$\begingroup\$

I'm currently attempting to make a first person character using a rigid body. I am aware that the character controller exists, but I believe my game will be very physics based so it's better if my character is a rigid body. I currently can walk, and rotate the camera up and down with the mouse. I am now trying to rotate my character left and right with the mouse, but this requires me to rotate my rigid body, not just the camera. Here's my code so far.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour
{
    [SerializeField] float walkSpeed = 3;
    [SerializeField] float cameraSpeed = 3;

    Vector3 direction;
    float cameraX;

    Rigidbody myRigidBody;
    [SerializeField] Camera myCamera;
    // Start is called before the first frame update
    void Start()
    {
        myRigidBody = GetComponent<Rigidbody>();
    }

    // Update is called once per frame
    void Update()
    {
        direction = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
        cameraX = -Input.GetAxis("Mouse Y") * cameraSpeed;

        myCamera.transform.Rotate(new Vector3(cameraX, 0, 0));
    }
    void FixedUpdate()
    {
        myRigidBody.AddRelativeForce(direction * walkSpeed, ForceMode.Acceleration);
    }

I believe that the rigid body function I should use to rotate left and right is MoveRotation (I'm still new to rigid bodies), but I'm open to ideas. MoveRotation uses Quaternions, and I have no idea how to translate my mouse axis into a quaternion.

Here's my question, How do i implement the Y rotation for my rigid body first person controller? Should I use torque, or somehow directly alter my rotation without using forces? Also, How do i translate the Mouse Axis into something I can use to rotate something? thnx.

Edit:

I tried adding this line of code:

myRigidBody.MoveRotation(Quaternion.Euler(0, mouseX * cameraSpeed, 0));

for some reason it has no effect on my character at all, but I feel Like it's on the right track. Why isn't this working?

Edit 2:

I added this line in Update:

rotateDirection = new Vector3(0, Input.GetAxis("Mouse X"), 0);

And this line in FixedUpdate:

myRigidBody.MoveRotation(Quaternion.Euler(rotateDirection));

Now when I move my mouse (I commented out my camera up and down movement to test) my character moves left and right for a tiny bit, but jitters back to it's original position, so It feels like I'm fighting it. The rotation in the inspector jitters in the correct direction, negative if i move the mouse left, positive if right, but only for a very small amount, 1.45 being the most, and then reverts back to zero. Also, it doesn't rotate smoothly, but jitters. Anybody know whats going on?

Edit 3: changed it from addforce to addrelativeforce because that make it move forward based on local coordinates not global.

\$\endgroup\$
6
  • \$\begingroup\$ If you don't know how to convert mouse movement into a quaternion, you really need to brush up on your basics. Start with docs.unity3d.com/ScriptReference/Quaternion.Euler.html and docs.unity3d.com/Manual/QuaternionAndEulerRotationsInUnity.html \$\endgroup\$
    – Kevin
    Apr 14 at 2:40
  • \$\begingroup\$ hey, thnx for the links, they were helpful! So, update, I added this line of code after my AddForce() "myRigidBody.AddTorque(new Vector3(0, Input.GetAxis("Mouse X") * cameraSpeed, 0));" and that sort of works, meaning that it rotates correctly. However, what with the acceleration and decelleration, caused by applying forces, the character doesn't stop rotating when the mouse stops, etc. So I don't think torque is the way to go, now I just need to figure out a way to rotate the character without breaking the physics. \$\endgroup\$
    – Millard
    Apr 14 at 3:23
  • \$\begingroup\$ 2nd update, I tried using transform.rotate and it moved jerkily and was often stopped completely (I think because it was conflicting with the physics) \$\endgroup\$
    – Millard
    Apr 14 at 3:26
  • \$\begingroup\$ Do not mix Transform and Rigidbody movement. Choose one or the other. \$\endgroup\$
    – DMGregory
    Apr 14 at 11:28
  • \$\begingroup\$ ok, thnx. which rigid body function would you recommend? \$\endgroup\$
    – Millard
    Apr 14 at 15:29
1
\$\begingroup\$

Your code assumes that MoveRotation(rot) takes an increment to add to the current rotation. That's not what it does. It takes an absolute orientation to move to, completely discarding the previous orientation.

So by passing just the travel of the mouse in this frame, your rotation will snap back to zero yaw anytime the mouse stops moving.

It looks like you want something more like this, where you accumulate your desired yaw frame over frame:

[SerializeField] float rotationSpeed;

float _yaw;
Rigidbody _body;

void Update() {
    _yaw = (_yaw + Input.GetAxis("MouseX") * cameraSpeed) % 360f;

    _body.MoveRotation(Quaternion.Euler(0, _yaw, 0));
}
\$\endgroup\$
3
  • \$\begingroup\$ This works perfectly, thanks! the only part I don't understand is the % 360f, why is that necessary? \$\endgroup\$
    – Millard
    Apr 14 at 16:39
  • \$\begingroup\$ It isn't, strictly. What this does is wrap your angle between -360 and +360, so that if a player decides to spin in one direction for a Loooooooong time you won't lose floating point precision. See my earlier answers on floating point for more about that. \$\endgroup\$
    – DMGregory
    Apr 14 at 16:43
  • \$\begingroup\$ oh, that makes sense, thnx. \$\endgroup\$
    – Millard
    Apr 14 at 16:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.