This example demonstrates how to implement a first-person controller in Unity using Cinemachine. It utilizes the CinemachineVirtual Camera's 3rd Person Follow for a comprehensive experience. The script includes configurations for camera settings, mouse sensitivity, and managing player input for movement, rotation, crouching, and jumping.
Furthermore, the example seamlessly integrates events to handle camera transitions during crouch and uncrouch actions. Overall, it provides a solid foundation for a first-person perspective with Cinemachine integration, effectively managing both camera and player interactions.
In this setup, the Character will manage the yaw rotation (rotation along the character's up-axis), while the parented 'Camera Target' GameObject will handle the camera's pitch rotation.
publicclassFirstPersonController:MonoBehaviour{ .. /// <summary> /// Add input (affecting Yaw). /// This is applied to the Character's rotation. /// </summary>publicvoidAddControlYawInput(float value) {_character.AddYawInput(value); } /// <summary> /// Add input (affecting Pitch). /// This is applied to the cameraTarget's local rotation. /// </summary>publicvoidAddControlPitchInput(float value,float minValue =-80.0f,float maxValue =80.0f) {if (value ==0.0f)return; _cameraTargetPitch =MathLib.ClampAngle(_cameraTargetPitch + value, minValue, maxValue);cameraTarget.transform.localRotation=Quaternion.Euler(-_cameraTargetPitch,0.0f,0.0f); }}
It's important to disable the character's rotation mode since, in this example, we'll handle it ourselves.
privatevoidStart(){Cursor.lockState=CursorLockMode.Locked; // Disable Character's rotation mode, we'll handle it here_character.SetRotationMode(Character.RotationMode.None);}
Additionally, we'll use the CharacterCrouched and UnCrouched events to trigger a crouch/uncrouch animation, relying on Cinemachine's transitions.
privatevoidOnEnable(){ // Subscribe to Character events_character.Crouched+= OnCrouched;_character.UnCrouched+= OnUnCrouched;}privatevoidOnDisable(){ // Unsubscribe to Character events_character.Crouched-= OnCrouched;_character.UnCrouched-= OnUnCrouched;}../// <summary>/// When character crouches, toggle Crouched / UnCrouched cameras./// </summary>privatevoidOnCrouched(){crouchedCamera.SetActive(true);unCrouchedCamera.SetActive(false);}/// <summary>/// When character un-crouches, toggle Crouched / UnCrouched cameras./// </summary>privatevoidOnUnCrouched(){crouchedCamera.SetActive(false);unCrouchedCamera.SetActive(true);}
Finally, we handle player input:
privatevoidUpdate(){ // Movement inputVector2 moveInput =newVector2 { x =Input.GetAxisRaw("Horizontal"), y =Input.GetAxisRaw("Vertical") }; // Movement direction relative to Character's forwardVector3 movementDirection =Vector3.zero; movementDirection +=_character.GetRightVector() *moveInput.x; movementDirection +=_character.GetForwardVector() *moveInput.y; // Set Character movement direction_character.SetMovementDirection(movementDirection); // Look inputVector2 lookInput =newVector2 { x =Input.GetAxisRaw("Mouse X"), y =Input.GetAxisRaw("Mouse Y") }; // Add yaw input, this update character's yaw rotationAddControlYawInput(lookInput.x*lookSensitivity.x); // Add pitch input (look up / look down), this update cameraTarget's local rotationAddControlPitchInput(lookInput.y*lookSensitivity.y, minPitch, maxPitch); // Crouch inputif (Input.GetKeyDown(KeyCode.LeftControl) ||Input.GetKeyDown(KeyCode.C))_character.Crouch();elseif (Input.GetKeyUp(KeyCode.LeftControl) ||Input.GetKeyUp(KeyCode.C))_character.UnCrouch(); // Jump inputif (Input.GetButtonDown("Jump"))_character.Jump();elseif (Input.GetButtonUp("Jump"))_character.StopJumping();}
Third-Person Controller
The following example illustrates the implementation of a third-person controller in Unity using Cinemachine. It leverages the Cinemachine Virtual Camera's 3rd Person Follow feature for a comprehensive experience. The controller encompasses configurations for camera settings, mouse sensitivity, and the management of player input for movement, rotation, crouching, and jumping.
Initially, we implement methods to control the camera's rotation and adjust its follow distance:
/// <summary>/// Add input (affecting Yaw). /// This is applied to the followTarget's yaw rotation./// </summary>publicvoidAddControlYawInput(float value,float minValue =-180.0f,float maxValue =180.0f){if (value !=0.0f) _cameraTargetYaw =MathLib.ClampAngle(_cameraTargetYaw + value, minValue, maxValue);}/// <summary>/// Add input (affecting Pitch). /// This is applied to the followTarget's pitch rotation./// </summary>publicvoidAddControlPitchInput(float value,float minValue =-80.0f,float maxValue =80.0f){if (value ==0.0f)return;if (invertLook) value =-value; _cameraTargetPitch =MathLib.ClampAngle(_cameraTargetPitch + value, minValue, maxValue);}/// <summary>/// Adds input (affecting follow distance)./// </summary>publicvirtualvoidAddControlZoomInput(float value){ followDistance =Mathf.Clamp(followDistance - value, followMinDistance, followMaxDistance);}
Subsequently, we adjust both the rotation of the followTargetGameObject and the CameraDistance of the Cinemachine virtual camera. This essentially means that we are exerting control over the Cinemachine camera by manipulating the followTargetGameObject.
/// <summary>/// Update followTarget rotation using _cameraTargetYaw and _cameraTargetPitch values and its follow distance./// </summary>privatevoidUpdateCamera(){followTarget.transform.rotation=Quaternion.Euler(_cameraTargetPitch, _cameraTargetYaw,0.0f);_cmThirdPersonFollow.CameraDistance=Mathf.SmoothDamp(_cmThirdPersonFollow.CameraDistance, followDistance,ref _followDistanceSmoothVelocity,0.1f);}privatevoidLateUpdate(){ // Update cameraTarget rotation using our yaw and pitch valuesUpdateCamera();}
Finally, we handle player input:
privatevoidUpdate(){ // Movement inputVector2 inputMove =newVector2() { x =Input.GetAxisRaw("Horizontal"), y =Input.GetAxisRaw("Vertical") }; // Set Movement direction in world spaceVector3 movementDirection =Vector3.zero; movementDirection +=Vector3.right*inputMove.x; movementDirection +=Vector3.forward*inputMove.y; // If character has a camera assigned...if (_character.camera) { // Make movement direction relative to its camera view direction movementDirection =movementDirection.relativeTo(_character.cameraTransform); } // Set Character movement direction_character.SetMovementDirection(movementDirection); // Crouch inputif (Input.GetKeyDown(KeyCode.LeftControl) ||Input.GetKeyDown(KeyCode.C))_character.Crouch();elseif (Input.GetKeyUp(KeyCode.LeftControl) ||Input.GetKeyUp(KeyCode.C))_character.UnCrouch(); // Jump inputif (Input.GetButtonDown("Jump"))_character.Jump();elseif (Input.GetButtonUp("Jump"))_character.StopJumping(); // Look inputVector2 lookInput =newVector2 { x =Input.GetAxisRaw("Mouse X"), y =Input.GetAxisRaw("Mouse Y") };AddControlYawInput(lookInput.x*lookSensitivity.x);AddControlPitchInput(lookInput.y*lookSensitivity.y, minPitch, maxPitch); // Zoom (in / out) inputfloat mouseScrollInput =Input.GetAxisRaw("Mouse ScrollWheel");AddControlZoomInput(mouseScrollInput);}