Lol, I started using my PC again after a long time and I’m using whatever versions are set as default, so I’m using Unity version 2020.3.17f1.
And also, do think upgrading Cinemachine might help?
Anyways, I tried to add the suggested “LookAt” line, and it seems to mess up all the transitions. Either by not looking at the player at all, or, with both cameras aim settings set to “Do Nothing”, the follow works but all transitions still have the problem. I couldn’t figure this out, so I deleted the aim constraint.
As for my intentions mechanics-wise, the player cube rolls freely on the current face of the big cube, and when trying to move to a different face the coroutine “ChangeFaces” described below executes, which does the following things:
public IEnumerator ChangeFaces(Vector3 targetPosition, Vector3 previousNormal, Vector3 targetNormal)
{
SmartInput.InputManager.freezeInput = true;
MoveInactiveCamera(targetPosition, previousNormal, targetNormal);
SwitchCameras();
yield return new WaitForSeconds(cmBrain.m_DefaultBlend.m_Time);
MatchCameras();
SmartInput.InputManager.freezeInput = false;
}
MoveInactiveCamera - The currently inactive camera is moved to its desired new position which is calculated by rotating the follow offset of the active camera a rotation I get from the normals of the new and current face. Then the camera is rotated using the Transform.LookAt function.
public void MoveInactiveCamera(Vector3 targetPosition, Vector3 previousNormal, Vector3 targetNormal)
{
Debug.Log($"previous: {previousNormal}, target: {targetNormal}");
Quaternion faceRotation = Quaternion.FromToRotation(previousNormal, targetNormal);
var transposer = inactiveCamera().GetTransposer();
transposer.m_FollowOffset = faceRotation * transposer.m_FollowOffset;
inactiveCamera().transform.position = targetPosition + transposer.m_FollowOffset;
inactiveCamera().transform.LookAt(targetPosition, targetNormal);
}
SwitchCameras - The cameras switch priorities and the blend begins
public void SwitchCameras()
{
virtualCamera1.Priority = 1 - virtualCamera1.Priority;
virtualCamera2.Priority = 1 - virtualCamera2.Priority;
}
MatchCameras - The now inactive camera’s transform is set to match that of the active one
public void MatchCameras()
{
//Match Values : follow offset, position & rotation
inactiveCamera().GetTransposer().m_FollowOffset = activeCamera().GetTransposer().m_FollowOffset;
inactiveCamera().transform.position = activeCamera().transform.position;
inactiveCamera().transform.rotation = activeCamera().transform.rotation;
}
Afterwards, the input manager recalculates the input bindings based on the camera’s local forward and right vectors projected on the current face’s plane.
public void RecalculateInputs(Vector3 normal)
{
Vector3 _right = Vector3.ProjectOnPlane(cameraPivotTransform.right, normal);
right.direction = _right.normalized.toV3Int();
Vector3 _left = Vector3.ProjectOnPlane(-cameraPivotTransform.right, normal);
left.direction = _left.normalized.toV3Int();
Vector3 _up = Vector3.ProjectOnPlane(cameraPivotTransform.forward, normal);
up.direction = _up.normalized.toV3Int();
Vector3 _down = Vector3.ProjectOnPlane(-cameraPivotTransform.forward, normal);
down.direction = _down.normalized.toV3Int();
}
}
The entire process executes from a function in the player script:
protected override void MoveInDirection(Vector3Int direction)
{
Vector3 prevNormal = normal();
cubidCoordinate = cubidCoordinate + direction;
bool faceChange = normal() != prevNormal;
//move to new world position
RotateCube(GetPosition(), faceChange);
OnMove?.Invoke(faceChange, normal());
if (faceChange)
{
StartCoroutine(cameraController.ChangeFaces(GetPosition(), prevNormal, normal()));
inputManager.RecalculateInputs(normal());
}
}
Sorry this is all so messy… thanks again for your help!