0
\$\begingroup\$

I'm making a fps controller, and I'm trying to clamp my cameras x rotation. Here's my code so far:

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

public class Player : MonoBehaviour
{
    // Start is called before the first frame update

    [SerializeField] Camera cam;
    [SerializeField] float camSpeed;
    [SerializeField] float walkSpeed;
    [SerializeField] float jumpSpeed;

    float yaw;
    float camPitch;
    Vector3 direction;
    Vector3 worldDirection;

    Rigidbody myrigbody;
    void Start()
    {
        myrigbody = GetComponent<Rigidbody>();
    }

    // Update is called once per frame
    void Update()
    {
        camPitch = -Input.GetAxis("Mouse Y") * camSpeed;
        cam.transform.Rotate(new Vector3(camPitch, 0, 0));
        yaw = (yaw + Input.GetAxis("Mouse X") * camSpeed) % 360f;

        direction = new Vector3(Input.GetAxis("Horizontal") * walkSpeed, myrigbody.velocity.y, Input.GetAxis("Vertical") * walkSpeed);
        worldDirection = transform.TransformVector(direction);

        if(Input.GetKeyDown(KeyCode.Space))
        {
            myrigbody.AddForce(new Vector3(0, jumpSpeed, 0), ForceMode.Impulse);
        }
    }
    private void FixedUpdate()
    {
        myrigbody.MoveRotation(Quaternion.Euler(0, yaw, 0));
        myrigbody.velocity = worldDirection;
    }
}

I know that I want to clamp my cameras X rotation within a range of -89 to 89, but no matter what I try I can't figure out how to clamp the rotation while using cam.transform.Rotate(). I don't think I can clamp camPitch, because it is reset every frame, and I can't figure out a way to directly clamp the cameras rotation. The cameras rotation is not resetting, so if I could somehow clamp it it would work. Is this possible, or do I need to try a different method? How do i get this to clamp correctly?

\$\endgroup\$
4
  • \$\begingroup\$ Does this answer your question? How to Clamp rotation of a turret \$\endgroup\$ – Kevin Apr 30 at 2:14
  • 1
    \$\begingroup\$ He seems to be rotating his turret differently. My problem is that I can't clamp the value I'm using to rotate, because it's reset every frame, and I don't know if directly clamping the rotation is possible (vs clamping the value used to rotate) \$\endgroup\$ – Millard Apr 30 at 2:21
  • \$\begingroup\$ What do you mean when you say he's rotating it differently? The asker of that question was using transform.Rotate(), which is what you're using. The axes are different but the approach used in the solution is equally applicable to your question. \$\endgroup\$ – Kevin Apr 30 at 4:39
  • \$\begingroup\$ See also gamedev.stackexchange.com/questions/185309/… , gamedev.stackexchange.com/questions/174259/… , \$\endgroup\$ – Kevin Apr 30 at 4:46
0
\$\begingroup\$

I fixed it! With the help from Kevin's links. So this is the code I ended up with:

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

public class Player : MonoBehaviour
{
    // Start is called before the first frame update

    [SerializeField] Camera cam;
    [SerializeField] float camSpeed;
    [SerializeField] float walkSpeed;
    [SerializeField] float jumpSpeed; 

    float mouseAngle;
    float yaw;
    float camPitch;
    Vector3 direction;
    Vector3 worldDirection;

    Rigidbody myrigbody;
    void Start()
    {
        myrigbody = GetComponent<Rigidbody>();
    }


    // Update is called once per frame
    void Update()
    {
        camPitch += Input.GetAxis("Mouse Y") * camSpeed;
        camPitch = Mathf.Clamp(camPitch, -89, 89);
        cam.transform.eulerAngles = new Vector3(-camPitch, yaw, 0);
        yaw = (yaw + Input.GetAxis("Mouse X") * camSpeed) % 360f;

        direction = new Vector3(Input.GetAxis("Horizontal") * walkSpeed, myrigbody.velocity.y, Input.GetAxis("Vertical") * walkSpeed);
        worldDirection = transform.TransformVector(direction);

        if(Input.GetKeyDown(KeyCode.Space))
        {
            myrigbody.AddForce(new Vector3(0, jumpSpeed, 0), ForceMode.Impulse);
        }
    }
    private void FixedUpdate()
    {
        myrigbody.MoveRotation(Quaternion.Euler(0, yaw, 0));
        myrigbody.velocity = worldDirection;
    }

}

My problem was pretty simple. In my original code, I used camPitch = Input.GetAxis("Mouse Y") * camSpeed;. The problem was that that resets camPitch every frame, so it's value would never actually reach 89 degrees up so clamping it correctly would be impossible. Instead, I changed the camPitch = to camPitch +=. Now camPitch has the mouse value added instead being of set to the mouses current motion, so it's value will equal what the cameras pitch should be, and can be clamped as i do on the next line. The other change I made, is using cam.transform.eulerAngles = new Vector3(-camPitch, yaw, 0); instead of cam.transform.Rotate(new Vector3(camPitch, 0, 0));. I used eulerAngles because this uses a set value of what the rotation's value should be on this frame instead of rotating based on the current motion on this frame. I hope this makes sense. I also added yaw for the y axis because since the cameras rotation is being directly set instead of rotated, it no longer follows it's parent's (the players) rotation. I hope that was clear, and that this will help someone in the future. Thanks to Kevin for helping me out!

\$\endgroup\$

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.