Reputation: 47
I didn't think that far ahead as I was focused on fixing my x-axis mouse clamp, and now I can't make my Quaternion.RotateTowards
rotate slower. When I enter a trigger, the code below which is inside the Update
method of my MouseLook/Camera script activates for a different kind of mouse movement.
[Range(0f, 90f)][SerializeField] float xRotationLimit = 35f;
void Update()
{
transform.position = player.position + offset;
if (trigger.clampRotation)
{
clampHorizontalRotation();
}
else
{
NormalCameraMovement();
}
}
void clampHorizontalRotation()
{
Vector2 mouseDelta = Input.GetAxis(xAxis) * Vector2.right + Input.GetAxis(yAxis) * Vector2.up;
rotation.x += mouseDelta.x * sensitivity;
rotation.y += mouseDelta.y * sensitivity;
rotation.y = Mathf.Clamp(rotation.y, -yRotationLimit, yRotationLimit);
var yQuat = Quaternion.AngleAxis(rotation.y, Vector3.left);
var xQuat = Quaternion.RotateTowards(climbing.CubeObj.rotation, Quaternion.AngleAxis(rotation.x, Vector3.up), rotationSpeed * Time.deltaTime);
rotation.x = xQuat.eulerAngles.y;
transform.localRotation = yQuat;
player.transform.localRotation = xQuat;
}
void NormalCameraMovement()
{
// Normal mouse movement goes here
}
The issue is the var xQuat
line with the RotateTowards
. The reason for my code the way it is with Quaternion.AngleAxis
inside the Quaternion.RotateTowards
, is to prevent gimbal lock. But now when I enter the trigger of the "CubeObj", my player instantly rotates towards it, rather than slowly.
What should happen in real time is: I walk up to my trigger object (CubeObject) and then my player automatically rotates slowly towards the CubeObject, so that my player is facing it. From there, my vertical axis is clamped (which is easy) and my x-axis mouse rotation is also clamped so that I cannot move left or right beyond a certain degrees.
Upvotes: 3
Views: 529
Reputation: 4056
You could try lerping (interpolate) the rotation by a set speed instead:
[SerializeField]
private float rotationSpeed = 5f;
// ...
void clampHorizontalRotation()
{
Vector2 mouseDelta = Input.GetAxis(xAxis) * Vector2.right + Input.GetAxis(yAxis) * Vector2.up;
rotation.x += mouseDelta.x * sensitivity;
rotation.y += mouseDelta.y * sensitivity;
rotation.y = Mathf.Clamp(rotation.y, -yRotationLimit, yRotationLimit);
var yQuat = Quaternion.AngleAxis(rotation.y, Vector3.left);
Quaternion targetXRotation = Quaternion.AngleAxis(rotation.x, Vector3.up);
// Slerp between the current rotation to the target rotation..
player.transform.localRotation = Quaternion.Slerp(climbing.CubeObj.rotation, targetXRotation, rotationSpeed * Time.deltaTime);
transform.localRotation = yQuat;
// To match the player's rotation as well...
rotation.x = player.transform.localEulerAngles.y;
// When rotation angle reaches extremely close,
// just snap it to the target.
if (Quaternion.Angle(climbing.CubeObj.rotation, targetXRotation) < 0.1f)
{
climbing.CubeObj.rotation = targetXRotation;
}
}
Also, it would help a lot to show your whole code, so that we can replicate the problem
Upvotes: 0
Reputation: 90724
I think this line is wrong
var xQuat = Quaternion.RotateTowards(climbing.CubeObj.rotation, Quaternion.AngleAxis(rotation.x, Vector3.up), rotationSpeed * Time.deltaTime);
you here get a rotation from the climbing.rotation
towards the Quaternion.AngleAxis(rotation.x, Vector3.up)
. Since the climbing.CubeObj.rotation
doesn't change this will always be more or less the same rotation assuming the mouse didn't move.
=> You do not rotate smooth towards a target rotation here! You only smooth out the target direction itself but still immediately snap to it.
If I understand correctly what you actually want is to clamp your rotation around the X axis to be 35° around the rotation of climbing.CubeObj
.
Then you rather want to smoothly rotate your player to this target rotation.
So your target rotation should probably be something like e.g.
rotation.x = Mathf.Clamp(rotation.x, -xRotationLimit, xRotationLimit);
// This is now a rotation within 35 degrees from the climbing.CubeObj.rotation
var xQuat = climbing.CubeObj.rotation * Quaternion.AngleAxis(rotation.x, Vector3.up);
and then
// In general: careful with mixing local and global rotations
// this now smoothly rotates the player towards the target rotation
player.transform.rotation = Quaternion.RotateTowards(player.transform.rotation, xQuat, rotationSpeed * Time.deltaTime);
Upvotes: 0
Reputation: 579
From the docs: public static Quaternion RotateTowards(Quaternion from, Quaternion to, float maxDegreesDelta);
"The from
quaternion is rotated towards to
by an angular step of maxDegreesDelta
. [This happens each time this function is called!]"
Thus, you want to decrease maxDegreesDelta
.
Keep in mind that if you run this function in Update
it may happen 60 times a second, assuming a framerate of 60. Thus if you set maxDegreesDelta
to a number as small as 1
, you still get up to 60°
of rotation in just a second. That's pretty fast considering an entire rotation is only 360°
!
Now if you just started building your game, you may get framerates up to 300 FPS. Thus allowing for up to 300°
of rotation in a second, making your rotations look instant.
Start with a very small number like 0.01
. Now multiply it with Time.deltaTime
to make it consistent across devices. Then, if it's rotating too slow, up the value from there. Add it as a public or serialized float and play around with the speed in the inspector in Play Mode until you are satisfied. Take note of the 'right' value and then apply that value when you're not in PlayMode.
Upvotes: 0