Clamp a quaternion rotation in unity - c#

I have this code but I have not been able to find a decent solution to clamp the X axis between 2 angle values. How would it be done in this case?
public class CameraController : MonoBehaviour {
public float cameraSmoothness = 5f;
private Quaternion targetGlobalRotation;
private Quaternion targetLocalRotation = Quaternion.Identity;
private void Start(){
targetGlobalRotation = transform.rotation;
}
private void Update(){
targetGlobalRotation *= Quaternion.Euler(
Vector3.up * Input.GetAxis("Mouse X"));
targetLocalRotation *= Quaternion.Euler(
Vector3.right * -Input.GetAxis("Mouse Y"));
transform.rotation = Quaternion.Lerp(
transform.rotation,
targetGlobalRotation * targetLocalRotation,
cameraSmoothness * Time.deltaTime);
}
}

For this you would rather use Euler angles and only convert them to Quaternion after applying the clamp!
Never directly touch individual components of a Quaternion unless you really know exactly what you are doing! A Quaternion has four components x, y, z and w and they all move in the range -1 to 1 so what you tried makes little sense ;)
It could be something like e.g.
// Adjust via Inspector
public float minXRotation = 10;
public float maxXRotation = 90;
// Also adjust via Inspector
public Vector2 sensitivity = Vector2.one;
private float targetYRotation;
private float targetXRotation;
private void Update()
{
targetYRotation += Input.GetAxis("Mouse X")) * sensitivity.x;
targetXRotation -= Input.GetAxis("Mouse Y")) * sensitivity.y;
targetXRotation = Mathf.Clamp(targetXRotation, minXRotation, maxXRotation);
var targetRotation = Quaternion.Euler(Vector3.up * targetYRotation) * Quaternion.Euler(Vector3.right * targetXRotation);
transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, cameraSmoothness * Time.deltaTime);
}

You need to Clamp Mouse Y + transform.rotation.x like this
_mouseX += Input.GetAxis("Mouse X") * _horizontalSensitive;
_camera.transform.localRotation = Quaternion.Euler(0, _mouseX, 0);
_mouseY -= Input.GetAxis("Mouse Y") * _verticalSensitive;
_mouseY = Mathf.Clamp(_mouseY, -90, 90);
_camera.transform.localRotation = Quaternion.Euler(_mouseY, 0, 0);
PS: _camera represent any gameobject on your scene

Related

When look up my character moves forwards in unity

I am using this movement code with a box collider in unity (I am quite a beginner)
public class Movement : MonoBehaviour
{
public float speed = 10.0f;
void Update()
{
float horizontalInput = Input.GetAxis("Horizontal");
float verticalInput = Input.GetAxis("Vertical");
transform.Translate(new Vector3(horizontalInput, 0, verticalInput) * Time.deltaTime * speed);
And this mouselook code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Mouselook : MonoBehaviour
{
public float sensitivity = 100.0f;
public float clampAngle = 80.0f;
private float rotX = 0.0f;
private float rotY = 0.0f;
void Start()
{
Vector3 rot = transform.localRotation.eulerAngles;
rotX = rot.x;
rotY = rot.y;
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
void Update()
{
float mouseX = Input.GetAxis("Mouse X");
float mouseY = -Input.GetAxis("Mouse Y");
rotX += mouseY * sensitivity * Time.deltaTime;
rotY += mouseX * sensitivity * Time.deltaTime;
rotX = Mathf.Clamp(rotX, -clampAngle, clampAngle);
Quaternion localRotation = Quaternion.Euler(rotX, rotY, 0.0f);
transform.localRotation = localRotation;
}
}
I tried making a different movement code and I was expecting it to let me use wasd to move in a unity puzzle game.
The thing is
transform.Translate(new Vector3(horizontalInput, 0, verticalInput) * Time.deltaTime * speed);
uses local space and since your object is rotated and looking up it will start to move upwards as well.
You could eliminate that by using global space and erase any movement on Y by doing e.g.
var move = transform.rotation * new Vector3(horizontalInput, 0, verticalInput) * Time.deltaTime * speed;
move.y = 0f;
transform.position += move;

FPS Player camera cant look left and right

I tried the last few weeks fix the problem with the camera. Like the title says, the players camera wont look left and right. And why? Because when I move the mouse left and right, the players y rotation rotates the right direction. But the Cameras y rotation is equal to the Players y rotation as a negative number. so, can anyone help me?
I tried literally everything. I expect the camera to rotate in all direction.
Here is the movement and look code:
mX += Input.GetAxis("Mouse X") * Sensivity * Time.deltaTime;
mY -= Input.GetAxis("Mouse Y") * Sensivity * Time.deltaTime;
mY = Mathf.Clamp(mY, -89.9f, 89.9f);
transform.eulerAngles = Vector3.up * mX/2;
cam.eulerAngles = Vector3.up * mX/2;
cam.eulerAngles = Vector3.right * mY;
float inputX = Input.GetAxis("Horizontal");
float inputY = Input.GetAxis("Fly");
float inputZ = Input.GetAxis("Vertical");
Vector3 dirForward = Vector3.ProjectOnPlane(transform.forward, Vector3.up).normalized;
Vector3 dirSide = transform.right;
Vector3 dirUp = Vector3.up;
Vector3 moveDir = (inputX * dirSide) + (inputY * dirUp) + (inputZ * dirForward);
transform.position += moveDir * Speed * Time.deltaTime;
I'm using this code for my 3d movements. Try it, it should work
public class free_cam_view : MonoBehaviour
{
public float mouseSensitivity = 100f;
float xr_1 = 0f;
void Update()
{
float y = 2 * Input.GetAxis("Mouse Y") * mouseSensitivity * Time.deltaTime;
xr_1 -= y;
xr_1 = Mathf.Clamp(xr_1, -90f, 63f);
transform.localRotation = Quaternion.Euler(xr_1, 0f, 0f);
}
}
Just add code to move forward by pressing "w"

My camera move script moves backwards on the y axis

My camera move script moves backwards on the y axis.
Here I leave the script
public class PlayerCam : MonoBehaviour
{
public float sensX;
public float sensY;
public Transform orientation;
float xRotation;
float yRotation;
void Start()
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
void Update()
{
//Get mouse input
float mouseX = Input.GetAxisRaw("Mouse X") * Time.deltaTime * sensX;
float mouseY = Input.GetAxisRaw("Mouse Y") * Time.deltaTime * sensY;
yRotation += mouseX;
xRotation += mouseY;
xRotation = Mathf.Clamp(xRotation, -90f, 90f);
//rotate cam and orientation
transform.rotation = Quaternion.Euler(xRotation, yRotation, 0);
orientation.rotation = Quaternion.Euler(0, yRotation, 0);
}
}
I havent tried anything yet
I would really appreciate it if you could help me solve this problem, it can be simple and I'm sorry, I'm new to programming
If by
moves backwards on the y axis
You mean that your camera moves up when your mouses goes down and vice versa.
Then why not just multiply the mouseY variable by -1 ?
Something like this:
float mouseY = Input.GetAxisRaw("Mouse Y") * Time.deltaTime * sensY * -1;
If your problem is something different, then give more details please.

Problem to rotate Quaternion on two axes with reference to a plane in Unity

I have only been able to rotate it in the x axis but I would also like to do it in the z with the movement of the mouse. Sorry for the mistakes is google translator.
[SerializeField] private float camRotationAmount = 0.2f;
public Quaternion newRotation;
newRotation *= Quaternion.Euler(Vector3.up * Input.GetAxis("Mouse X"));
transform.rotation = Quaternion.Lerp(transform.rotation, newRotation, Time.deltaTime * camSmoothness);
I would like to add Input.GetAxis ("Mouse Y") for Vector3.left without tilting the camera. it's for a rts game. Thanks
In general you will want to separate the Y and X rotation the following way:
rotate around Y in global space
rotate around X in local space.
Whether you do this purely by logic or using a parent-child hierarchy is up to you ... second is easier to understand in my opinion.
Using the Hierarchy
There you would simply have a hierarchy like e.g.
CameraAnchor
|--Camera
and have a script on the CameraAnchor like e.g.
public class CameraAnchorController : MonoBehaviour
{
public float cameraSmoothness = 5f;
private Quaternion targetGlobalRotation;
private Quaternion targetLocalRotation;
private Transform child;
private void Start()
{
child = transform.GetChild(0);
targetGlobalRotation = transform.rotation;
targetLocalRotation = transform.GetChild(0).localRotation;
}
private void Update()
{
targetGlobalRotation *= Quaternion.Euler(Vector3.up * Input.GetAxis("Mouse X"));
targetLocalRotation *= Quaternion.Euler(Vector3.right * -Input.GetAxis("Mouse Y"));
var lerpFactor = cameraSmoothness * Time.deltaTime;
transform.rotation = Quaternion.Lerp(transform.rotation, targetGlobalRotation, lerpFactor);
child.localRotation = Quaternion.Lerp(child.localRotation, targetLocalRotation, lerpFactor);
}
}
Using Quaternion math
As said you could do the same thing in one single object but I would still keep both rotations separated:
public class CameraController : MonoBehaviour
{
public float cameraSmoothness = 5f;
private Quaternion targetGlobalRotation;
private Quaternion targetLocalRotation = Quaternion.identity;
private void Start()
{
targetGlobalRotation = transform.rotation;
}
private void Update()
{
targetGlobalRotation *= Quaternion.Euler(Vector3.up * Input.GetAxis("Mouse X"));
targetLocalRotation *= Quaternion.Euler(Vector3.right * -Input.GetAxis("Mouse Y"));
transform.rotation = Quaternion.Lerp(transform.rotation, targetGlobalRotation * targetLocalRotation, cameraSmoothness * Time.deltaTime);
}
}
Now why does this work when we are still using Vector3.right now?
By doing targetGlobalRotation * targetLocalRotation we first rotate around the global Y axis and then apply the rotation on the X axis based on this already applied rotation -> it is now an additional local rotation!

3rd person controller spinning the wrong way around

i've been trying to make a third person controller and its going ok. Right unltil i startet on the movement itself.
When the Y axis reaches anything above 360 it spins all the way from 360>300..150>50>5 instead of just 360>5 and i dont know how i could make it do what i want
Below is the two scripts that im using
Camera Rotation:
public bool LockMouse;
public Transform target;
public float Sens;
[Range(0,10)]
public float Distance = 2;
public Vector2 MinMaxPitch = new Vector2(-40, 85);
public float RotSmoothTime = 0.12f;
Vector3 rotationSmoothVelocity;
Vector3 currentRot;
float pitch;
float yaw;
private void Start()
{
if(LockMouse)
Cursor.lockState = CursorLockMode.Locked;
}
void LateUpdate()
{
yaw += Input.GetAxis("Mouse X") * Sens * Time.deltaTime;
pitch -= Input.GetAxis("Mouse Y") * Sens * Time.deltaTime;
pitch = Mathf.Clamp(pitch, MinMaxPitch.x, MinMaxPitch.y);
currentRot = Vector3.SmoothDamp(currentRot, new Vector3(pitch, yaw), ref rotationSmoothVelocity, RotSmoothTime);
transform.eulerAngles = currentRot;
transform.position = target.position - transform.forward * Distance;
}
Player Movement:
public float speed;
public float SmoothSpeed;
Transform camT;
Rigidbody rb;
Vector3 rot;
private Vector3 vel = new Vector3(0, 0, 0);
// Start is called before the first frame update
void Start()
{
camT = Camera.main.transform;
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
rb.velocity = (transform.right * Input.GetAxis("Horizontal") * Time.deltaTime * speed) + (transform.forward * Input.GetAxis("Vertical") * Time.deltaTime * speed) + (transform.up * rb.velocity.y);
if(new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical")).magnitude > 0)
{
rot = new Vector3(0, camT.eulerAngles.y, 0);
Debug.Log(rot);
if(rot.y > 358)
{
transform.eulerAngles = new Vector3(rot.x, 3, rot.z);
}
if (rot.y < 2)
{
transform.eulerAngles = new Vector3(rot.x, 357, rot.z);
}
}
transform.eulerAngles = Vector3.SmoothDamp(transform.eulerAngles, rot, ref vel, SmoothSpeed);
}
Vector3.Smoothdamp doesn't understand that e.g., (x,359,z) can wrap around to (x,0,z).
Use Quaternions instead of vectors and use Quaternion.RotateTowards to calculate the rotation to use between the current rotation and rot:
public float speed;
public float smoothSpeed; // naming convention for fields is camelCase
Transform camT;
Rigidbody rb;
Quaternion rot;
private Vector3 vel = new Vector3(0, 0, 0);
// Start is called before the first frame update
void Start()
{
camT = Camera.main.transform;
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
rb.velocity = (transform.right * Input.GetAxis("Horizontal") * Time.deltaTime * speed) + (transform.forward * Input.GetAxis("Vertical") * Time.deltaTime * speed) + (transform.up * rb.velocity.y);
if(new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical")).magnitude > 0)
{
rot = Quaternion.Euler(0f,camT.eulerAngles.y,0f);
}
transform.rotation = Quaternion.RotateTowards(transform.rotation, rot, Time.deltaTime * smoothSpeed);
}

Categories