how do i Limit camera rotation on Y-Axis
Hello
I have a problems with (Mathf.Clamp) for camera Y axis. This is a simple camera controller script, everything is good the code work too, but the problem is when i try to use (Mathf.Clamp) for Y axis the camera automatic rotating !! pls what should i do ?? this is a code of script. i need another way to limit camera rotation on Y-Axis!!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class camera_follow : MonoBehaviour {
[Header("Target")]
public Transform target;
public float distance = 3.5f;
[Header("Camera speeds")]
public float follow_speed = 20f;
public float y_sensitivity = 1f;
public float x_sensitivity = 1f;
[Header("Axis")]
public float y_max_axis = 2f;
public float y_min_axis = 0.1f;
// Other private variables
private Vector3 offset;
private Vector3 direction;
private float x_axis;
private float y_axis;
// Start
void Start() {
offset = target.position * distance;
}
// Update
void Update() {
// Get axis of X & Y using mouse
x_axis = Input.GetAxis("Mouse X") * x_sensitivity;
y_axis = Input.GetAxis("Mouse Y") * y_sensitivity;
// Clamp Y axis
// there will be no any problem if i disable this clamp
//y_axis = Mathf.Clamp(y_axis, y_min_axis, y_max_axis);
}
// Fixed update
void FixedUpdate() {
// Offset
offset = Quaternion.AngleAxis(y_axis, Vector3.right) * Quaternion.AngleAxis(x_axis, Vector3.up) * offset;
// Set direction of target
direction = target.position + offset * distance;
// Trans & Look
transform.position = Vector3.Lerp (transform.position, direction, follow_speed * Time.deltaTime);
transform.LookAt(target.position);
}
}
you can just do
if position.x> something
position.x = something
Answer by streeetwalker · Mar 09, 2020 at 01:53 PM
HI Osama! The problem is that when you don't move the mouse y_axis is zero. But you're clamping it between your min and max,
Therefore, when y_axis = 0, the camp returns your min value and you get constant rotation at that value. You want to limit the resulting angle based on y_axis, so clamp that, not y_axis.
@osamaamir You're using Quaternions already, you just need to make sense of them - and I'm still learning!
You got me going on this quest to build the perfect follower script. it is not complete yet. It doesn't do any "animation" of the camera - the camera is always the same relative distance from the player. I'm working now to limit the camera orbit angles, and also to do a spring like player-camera distance, so you get a little lag in the camera position when as move the player and the camera speed sup a little as it catches up
Create a new project, put a cube (the "player") and a camera in the scene and place this script on the camera, and the second script on the cube. Position the camera a few meters away from the cube. Put some ground and other objects so you have a visual reference when you move around.
Use ASWD to move and rotate the cube. In this script you have to drag to orbit the camera. Read the code comments.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraFollow : MonoBehaviour {
public Transform target;
public float distance = 3.5f; // not yet
public float y_sensitivity = 1f;
public float x_sensitivity = 1f;
public float y_max_axis = 2f; // not implemented yet
private Vector3 offset;
private float pitch, yaw;
private Quaternion oldRotation;
private bool dragging = false;
void Start() {
GameObject g = gameObject;
// to do: positon game object using distance
transform.LookAt( g.transform ); // start out focusing on object
// record these for use later
offset = transform.position - target.position;
oldRotation = target.transform.rotation;
}
// Update
void Update() {
// Get axis of X & Y using mouse to use when we
// orbit the mouse around the object
// here we are making the user left click and drag
// if you want free movment without dragging, delete all the mousedown code
if( Input.GetMouseButtonDown( 0 ) ) {
dragging = true;
}
if( Input.GetMouseButtonUp( 0 ) ) {
dragging = false;
}
if( Input.GetMouseButton( 0 ) && dragging ) {
// to do: check if angles are between max or min, if not don't allow input
yaw = Input.GetAxis( "Mouse X" ) * x_sensitivity;
pitch = Input.GetAxis( "Mouse Y" ) * y_sensitivity;
}
}
void FixedUpdate() {
// only update if input was made
if( Mathf.Abs(pitch - yaw) > 0.001f ) {
// rotate around is much easier - Quaternions do it for you
transform.RotateAround( target.position, Vector3.up, yaw );
transform.RotateAround( target.position, -transform.right, pitch );
// update the offset positon if we have orbited the camera
offset = transform.position - target.position;
}
// only update if we have rotated our player
if( Quaternion.Dot( target.rotation, oldRotation ) <= 1f - 0.000001f ) {
// get the change in rotation
Quaternion deltaQ = target.rotation * Quaternion.Inverse( oldRotation );
oldRotation = target.rotation;
// apply rotation to camera offset location and rotation
offset = deltaQ * offset ;
transform.rotation = deltaQ * transform.rotation;
}
// finally, apply all the changes to the camera
transform.position = target.position + offset;
}
}
cube "player" script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MovePlayer : MonoBehaviour
{
public float speed = 0.05f;
// Update is called once per frame
void Update()
{
if( Input.GetKey( KeyCode.A ) ) {
float angle = transform.eulerAngles.y + 1;
transform.rotation = Quaternion.Euler( new Vector3( 0, angle, 0 ) );
} else if( Input.GetKey( KeyCode.D ) ) {
float angle = transform.eulerAngles.y - 1;
transform.rotation = Quaternion.Euler( new Vector3( 0, angle, 0 ) );
}
if( Input.GetKey( KeyCode.W ) ) {
transform.Translate( Vector3.forward * speed );
} else if( Input.GetKey( KeyCode.S ) ) {
transform.Translate( Vector3.forward * -speed );
}
}
}
@streeetwalker thank you for your comment. now i understand this :) but what can i do to limit camera rotation on Y axis. can you pleas fix this for me ?
@osamaamir , that is not simple, because you are dealing with Quaternions. It's not simple no matter what you have with angles!
I adapted this from this post, so I have not tested it. Look at the last reply here: https://forum.unity.com/threads/how-do-i-clamp-a-quaternion.370041/
This will do it, I think, so good luck! ;-)
You need a new function:
private Quaternion ClampRotation(Quaternion q, float $$anonymous$$, float max)
{
q.x /= q.w;
q.y /= q.w;
q.z /= q.w;
q.w = 1.0f;
float angleY = 2.0f * $$anonymous$$athf.Rad2Deg * $$anonymous$$athf.Atan(q.y);
angleY = $$anonymous$$athf.Clamp(angleY, $$anonymous$$, max);
q.y = $$anonymous$$athf.Tan(0.5f * $$anonymous$$athf.Deg2Rad * angleY);
return q;
}
// Then in your fixedupdate loop, before you calculate your
// offset rotation - $$anonymous$$Angle and maxAngle in degrees
Quaternion tempRot = Quaternion.AngleAxis(y_axis, Vector3.right)
Quaternion clampedRot = ClampRotation(tempRot, $$anonymous$$Angle, maxAngle);
// Offset -- this replaces what you have
offset = clampedRot * Quaternion.AngleAxis(x_axis, Vector3.up) * offset;
@streeetwalker if this not simple is there anther way to do this ? i mean without using transform.LookAt() ? and you know why i'm using this code because it's very smooth even when i set (targetFrameRate) to 30f.