Hello everyone,
I’m just starting to develop with unity.
My game contains ship movement on the horizontal plane only I stay at x distance from the ground only.
I’ve integrated a framing camera set at x distance from my ship, so I can turn around it and I’ve also coded a zoom.
Movements are made with the keyboard and the facing direction and always the camera direction.
So far, that’s just to explain how my game works.
The problem I’m having is that when I turn my ship with the keyboard keys, it’s fluid, but when I steer with my camera, the ship jerks.
I have no idea where to start looking to solve this problem.
Thanks in advance to anyone who tries to help me.
Can you please show an image of your virtual camera inspector?
Also, please post an image of your hierarchy showing the main camera, virtual camera, and ship (I want to check the parenting).
Also please: what versions of Unity and Cinemachine?
A video of the jittering would be helpful too.
And what do you mean by “steer with my camera”?
Thanks.
From your video, I’ guessing that you have a FixedUpdate vs Update mismatch in your ship rotation code.
When the game is playing , please look at the Virtual Camera inspector and tell me what it says next to se Solo button when the ship is rotating (it should say either “Late Update” or “Fixed Update”).
Good, thanks.
Can you show me the code that moves your ship? I want to see everything that sets the ship’s transform in any way.
My hypothesis is that it’s happening in Update in some places, and FixedUpdate in others.
EDIT: Also, can you show me the inspector of the ship? I want to see if it has a Rigidbody and if so, what are the settings.
classe publique PlayerMovementState : IState
{
protégé PlayerMovementStateMachine stateMachine ;
entrée de mouvement Vector2 protégée ;
base flottante protégéeVitesse = 18f ;
speedModifier flottant protégé = 1f ;
protégé Vector3 currentTargetRotation ;
protégé Vector3 timeToReachTargetRotation ;
protégé Vector3 amortiTargetRotationCurrentVelocity ;
protégé Vector3 amortiTargetRotationPassedTime ;
public PlayerMovementState (PlayerMovementStateMachine playerMovementStateMachine)
{
stateMachine = joueurMovementStateMachine ;
InitializeData();
}
vide privé InitializeData()
{
timeToReachTargetRotation.y = 0,5f ; //0,14
}
#region Méthodes IState
vide virtuel public Entrée()
{
Debug.Log("State : " + GetType().Name);
}
vide virtuel public Quitter()
{
}
vide virtuel public HandleInput()
{
ReadMovementInput();
}
mise à jour du vide virtuel public ()
{
}
vide virtuel public PhysicsUpdate()
{
Se déplacer();
}
#endregion
#region Principales méthodes
vide privé ReadMovementInput()
{
moveInput = stateMachine.Player.Input.PlayerActions.Movement.ReadValue<Vector2>();
}
privé vide Move()
{
si (movementInput == Vector2.zero || speedModifier == 0f)
{
retour;
}
Vector3 mouvementDirection = GetMovementInputDirection();
float targetRotationYAngle = Rotation (movementDirection);
Vector3 targetRotationDirection = GetTargetRotationDirection(targetRotationYAngle);
float mouvementSpeed = GetMovementSpeed();
Vector3 currentPlayerHorizontalVelocity = GetPlayerHorizontalVelocity();
stateMachine.Player.Rigidbody.AddForce(targetRotationDirection * moveSpeed - currentPlayerHorizontalVelocity, ForceMode.Acceleration);
}
Rotation du flotteur privé (direction Vector3)
{
float directionAngle = UpdateTargetRotation(direction);
RotationVersTargetRotation();
direction de retourAngle ;
}
flotteur privé GetDirectionAngle (direction Vector3)
{
float directionAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg;
si (directionAngle < 0f)
{
directionAngle += 360f ;
}
direction de retourAngle ;
}
flotteur privé AddCameraRotationToAngle (angle flottant)
{
angle += stateMachine.Player.MainCameraTransform.eulerAngles.y;
si (angle > 360f)
{
angle-= 360f ;
}
angle de retour ;
}
vide privé UpdateTargetRotationData (float targetAngle)
{
currentTargetRotation.y = targetAngle;
amortiTargetRotationPassedTime.y = 0f;
}
#endregion
#region Méthodes réutilisables
Vector3 protégé GetMovementInputDirection()
{
renvoie le nouveau Vector3 (movementInput.x, 0f, moveInput.y);
}
flotteur protégé GetMovementSpeed()
{
retourner baseSpeed * speedModifier ;
}
Vector3 protégé GetPlayerHorizontalVelocity()
{
Vector3 playerHorizontalVelocity = stateMachine.Player.Rigidbody.velocity;
joueurHorizontalVelocity.y = 0f;
retourner le joueurHorizontalVelocity ;
}
vide protégé RotateTowardsTargetRotation()
{
float currentYAngle = stateMachine.Player.Rigidbody.rotation.eulerAngles.y;
si (currentYAngle == currentTargetRotation.y)
{
retour;
}
float smoothedYAngle = Mathf.SmoothDampAngle (currentYAngle, currentTargetRotation.y, réf DamedTargetRotationCurrentVelocity.y, timeToReachTargetRotation.y - DamdedTargetRotationPassedTime.y);
DampedTargetRotationPassedTime.y += Time.deltaTime ;
Quaternion targetRotation = Quaternion.Euler(0f, smoothedYAngle, 0f);
stateMachine.Player.Rigidbody.MoveRotation(targetRotation);
}
float protégé UpdateTargetRotation (direction Vector3, bool sholdConsiderCameraRotation = true)
{
float directionAngle = GetDirectionAngle(direction);
si (sholdConsiderCameraRotation)
{
directionAngle = AddCameraRotationToAngle(directionAngle);
}
si (directionAngle != currentTargetRotation.y)
{
UpdateTargetRotationData(directionAngle);
}
direction de retourAngle ;
}
protégé Vector3 GetTargetRotationDirection (float targetAngle)
{
return Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward;
}
#endregion
}
I move Parent empty object of my ship with this Rigidbody, and i have a mesh collider on my ship.
Whaaa? What’s that weird c# in franglais? Never seen anything like that before.
I’m going to assume that all the code that changes the Rigidbody is ultimately being called from FixedUpdate, and not Update or LateUpdate. Can you confirm that this is the case?
Can you try an experiment?
Set the Brain Update Mode to Smart Update (if it’s not there already).
Turn off Interpolation on the ship.
Play the scene.
Verify that the text next to the Solo button of the vcam inspector now says “Fixed Update”
Is the rotation smooth now?
Oh sorry I didn’t see, my automatic translator translated everything ^^
Here’s the good code :
public class PlayerMovementState : IState
{
protected PlayerMovementStateMachine stateMachine;
protected Vector2 movementInput;
protected float baseSpeed = 18f;
protected float speedModifier = 1f;
protected Vector3 currentTargetRotation;
protected Vector3 timeToReachTargetRotation;
protected Vector3 dampedTargetRotationCurrentVelocity;
protected Vector3 dampedTargetRotationPassedTime;
public PlayerMovementState(PlayerMovementStateMachine playerMovementStateMachine)
{
stateMachine = playerMovementStateMachine;
InitializeData();
}
private void InitializeData()
{
timeToReachTargetRotation.y = 0.5f; //0.14
}
#region IState Methods
public virtual void Enter()
{
Debug.Log("State: " + GetType().Name);
}
public virtual void Exit()
{
}
public virtual void HandleInput()
{
ReadMovementInput();
}
public virtual void Update()
{
}
public virtual void PhysicsUpdate()
{
Move();
}
#endregion
#region Main Methods
private void ReadMovementInput()
{
movementInput = stateMachine.Player.Input.PlayerActions.Movement.ReadValue<Vector2>();
}
private void Move()
{
if (movementInput == Vector2.zero || speedModifier == 0f)
{
return;
}
Vector3 movementDirection = GetMovementInputDirection();
float targetRotationYAngle = Rotate(movementDirection);
Vector3 targetRotationDirection = GetTargetRotationDirection(targetRotationYAngle);
float movementSpeed = GetMovementSpeed();
Vector3 currentPlayerHorizontalVelocity = GetPlayerHorizontalVelocity();
stateMachine.Player.Rigidbody.AddForce(targetRotationDirection * movementSpeed - currentPlayerHorizontalVelocity, ForceMode.Acceleration);
}
private float Rotate(Vector3 direction)
{
float directionAngle = UpdateTargetRotation(direction);
RotateTowardsTargetRotation();
return directionAngle;
}
private float GetDirectionAngle(Vector3 direction)
{
float directionAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg;
if (directionAngle < 0f)
{
directionAngle += 360f;
}
return directionAngle;
}
private float AddCameraRotationToAngle(float angle)
{
angle += stateMachine.Player.MainCameraTransform.eulerAngles.y;
if (angle > 360f)
{
angle -= 360f;
}
return angle;
}
private void UpdateTargetRotationData(float targetAngle)
{
currentTargetRotation.y = targetAngle;
dampedTargetRotationPassedTime.y = 0f;
}
#endregion
#region Reusable Methods
protected Vector3 GetMovementInputDirection()
{
return new Vector3(movementInput.x, 0f, movementInput.y);
}
protected float GetMovementSpeed()
{
return baseSpeed * speedModifier;
}
protected Vector3 GetPlayerHorizontalVelocity()
{
Vector3 playerHorizontalVelocity = stateMachine.Player.Rigidbody.velocity;
playerHorizontalVelocity.y = 0f;
return playerHorizontalVelocity;
}
protected void RotateTowardsTargetRotation()
{
float currentYAngle = stateMachine.Player.Rigidbody.rotation.eulerAngles.y;
if (currentYAngle == currentTargetRotation.y)
{
return;
}
float smoothedYAngle = Mathf.SmoothDampAngle(currentYAngle, currentTargetRotation.y, ref dampedTargetRotationCurrentVelocity.y, timeToReachTargetRotation.y - dampedTargetRotationPassedTime.y);
dampedTargetRotationPassedTime.y += Time.deltaTime;
Quaternion targetRotation = Quaternion.Euler(0f, smoothedYAngle, 0f);
stateMachine.Player.Rigidbody.MoveRotation(targetRotation);
}
protected float UpdateTargetRotation(Vector3 direction, bool sholdConsiderCameraRotation = true)
{
float directionAngle = GetDirectionAngle(direction);
if (sholdConsiderCameraRotation)
{
directionAngle = AddCameraRotationToAngle(directionAngle);
}
if (directionAngle != currentTargetRotation.y)
{
UpdateTargetRotationData(directionAngle);
}
return directionAngle;
}
protected Vector3 GetTargetRotationDirection(float targetAngle)
{
return Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward;
}
#endregion
}
and I test your suggestion in few minutes
Update Methode on smart and Blend on late or fixed?
Put Blend mode on LateUpdate
it seems better, but I have swiths between Fixed update and late update that create parasites, and my mouse sensitivity isn’t always the same.
I don’t understand. What switches between fixed and late update? The text next to the Solo button?
Yes the text next to the Solo button switches between fixed and late update.
ok, this means that you’re not moving the ship consistently to be compatible with Rigidbody interpolation, and so therefore the ship’s rotation is not smooth.
Cinemachine will work smoothly so long as the targeted object is moving smoothly. The job now is to find where in the code the rotation is being set incorrectly.
To be clear: turning off Interpolation was just a diagnostic experiment. I would recommend turning it back on and finding and correcting the mistake in your code. The goal is to have the vcam update in LateUpdate.
ok thanks, I’ll look for the source of my problem, but on the kinemachine side it’s fine, I have to leave the settings as they are, reset the interpolation on my rigidbody and find the source of the problem in my code.
Seiikow:
ok thanks, I’ll look for the source of my problem, but on the kinemachine side it’s fine, I have to leave the settings as they are, reset the interpolation on my rigidbody and find the source of the problem in my code.
Yes that is correct. Please let me know if you make any progress.