using System.Collections; using System.Collections.Generic; using UnityEngine; using static scr_Models; // allows you to use data members of all classes in the scr_Models script public class scr_CharacterController : MonoBehaviour { private CharacterController characterController; // a reference to the character controller component (assigned a value in the awake method) private DefaultInput defaultInput; // makes a variable of type DefaultInput called defaultInput CursorLockMode lockMode; [Header("Input Monitoring")] [ReadOnly] public Vector2 input_Movement; // use to monitor raw input [ReadOnly] public Vector2 input_View; // use to monitor raw input private Vector3 newCameraRotation; // the rotation the cameraHolder will be set to in CalculateView private Vector3 newCharacterRotation; // the rotation the character will be set to in CalculateView [Header("References")] public Transform cameraHolder; // a reference to the CameraHolder component of the Player public Transform feetTransform; // a reference to the FeetTransform component of the Player [Header("View and Movement Settings")] public PlayerSettingsModel playerSettings; // a reference to the PlayerSettingsModel class in the scr_Models script public float viewClampYMin = -70; // the lowest you can look public float viewClampYMax = 80; // the highest you can look public LayerMask playerMask; // used to exclude the player private Vector3 newMovementSpeed; // used in the CalculateMovement method to help calculate movementSpeed private Vector3 newMovementSpeedVelocity; [Header("Weapon")] public scr_WeaponController currentWeapon; // creates a reference to our weapon controller [Header("Gravity Settings")] public float gravityAmount; // how much gravity is applied public float gravityMin; // the minimum that gravity can reach, i.e. terminal velocity essentially [ReadOnly] public float characterGravity; // the current amount of gravity the character experiences [Header("Jumping Force Settings and Monitoring")] [ReadOnly] public Vector3 jumpingForce; // declares a Vector3 class called jumpingForce private Vector3 jumpingForceVelocity; [Header("Stance Settings")] public PlayerStance playerStance; public float playerStanceSmoothing; public CharacterStance playerStandStance; // creates a CharacterStance class variable for standing public CharacterStance playerCrouchStance; // creates a CharacterStance class variable for crouching private float stanceCheckErrorMargin = 0.05f; private float cameraHeight; // The height the cameraHolder.localPosition.y will be set to based on your stance (CameraStandHeight or CameraCrouchHeight) private float cameraHeightVelocity; private Vector3 stanceCapsuleCenterVelocity; private float stanceCapsuleHeightVelocity; //[ReadOnly] public bool test; private void Awake() { lockMode = CursorLockMode.Locked; Cursor.lockState = lockMode; Cursor.visible = false; #region -- INPUTS defaultInput = new DefaultInput(); // instantiates the defaultInput defaultInput.Character.Movement.performed += e => input_Movement = e.ReadValue(); // sets the value of input_Movement based on WSAD input defaultInput.Character.View.performed += e => input_View = e.ReadValue(); // sets the value of input_View based on raw mouse input defaultInput.Character.Jump.performed += e => Jump(); // calls the Jump function when the Jump action from the input controller is performed defaultInput.Character.Crouch.performed += e => Crouch(); // calls the Crouch function when the Crouch action from the input controller is performed defaultInput.Enable(); // inputs won't work until defaultInput is enabled #endregion newCameraRotation = cameraHolder.localRotation.eulerAngles; // sets the initial value of newCameraRotation (which is basically just the cameraHolder's default rotation) newCharacterRotation = transform.localRotation.eulerAngles; // sets the initial value of newCharacterRotation characterController = GetComponent(); // assigns characterController variable an actual value of the CharacterController component cameraHeight = cameraHolder.localPosition.y; // may not be necessary // initializes the currentWeapon; assigns this scr_CharacterController to be characterController in currentWeapon if (currentWeapon) { currentWeapon.Initialize(this); } } private void Update() { CalculateView(); CalculateMovement(); CalculateJump(); CalculateStance(); //test = StanceCheck(playerStandStance.StanceCollider.height); } private void CalculateView() { newCharacterRotation.y += playerSettings.ViewXSensitivity * (playerSettings.ViewXInverted ? -input_View.x : input_View.x) * Time.deltaTime; // calculates left and right float of newCharacterRotation transform.localRotation = Quaternion.Euler(newCharacterRotation); // sets the local rotation of the character (which is a quaternion) to be equal to newCharacterRotation (which is a Vector3) converted into a quaternion newCameraRotation.x += playerSettings.ViewYSensitivity * (playerSettings.ViewYInverted ? input_View.y : -input_View.y) * Time.deltaTime; // calculates up and down float of newCameraRotation newCameraRotation.x = Mathf.Clamp(newCameraRotation.x, viewClampYMin, viewClampYMax); // clamps up and down rotation cameraHolder.localRotation = Quaternion.Euler(newCameraRotation); // sets the local rotation of the cameraHolder (which is a quaternion) to be equal to newCameraRotation (which is a Vector3) converted into a quaternion } // sets the value of movementSpeed, which is what moves our character. private void CalculateMovement() { var verticalSpeed = playerSettings.WalkingForwardSpeed; // local float called verticalSpeed given default value var horizontalSpeed = playerSettings.WalkingStrafeSpeed; // local float called horizontalSpeed given default value #region -- Effectors if (!characterController.isGrounded) // if you aren't grounded, have the FallingSpeedEffector be in place { playerSettings.SpeedEffector = playerSettings.FallingSpeedEffector; } else if(playerStance == PlayerStance.Crouch) // if you are crouched, have the CrouchSpeedEffector be in place { playerSettings.SpeedEffector = playerSettings.CrouchSpeedEffector; } else { playerSettings.SpeedEffector = 1; } verticalSpeed *= playerSettings.SpeedEffector; // has SpeedEffector affect verticalSpeed horizontalSpeed *= playerSettings.SpeedEffector; // has SpeedEffector affect horizontalSpeed #endregion #region -- Calculate newMovementSpeed Vector3 and local targetMovementSpeed Vector3 Vector3 targetMovementSpeed = new Vector3(horizontalSpeed * input_Movement.x * Time.deltaTime, 0, verticalSpeed * input_Movement.y * Time.deltaTime); // makes a new local Vector3 instance called targetMovementSpeed using horizontalSpeed and verticalSpeed newMovementSpeed = Vector3.SmoothDamp(newMovementSpeed, targetMovementSpeed, ref newMovementSpeedVelocity, characterController.isGrounded ? playerSettings.MovementSmoothing : playerSettings.FallingSmoothing); // makes newMovementSpeed's value smoothdamp to targetMovementSpeed (also checks to see if you are grounded so it knows whether to use MovementSmoothing or FallingSmoothing #endregion var movementSpeed = transform.TransformDirection(newMovementSpeed); // makes a new local variable called movementSpeed and makes it equal to newMovementSpeed but relative to the player's rotation #region --Calculate characterGravity // if character hasn't reached terminal velocity, keep reducing their gravity if (characterGravity > gravityMin) { characterGravity -= gravityAmount * Time.deltaTime; } // so gravity doesn't grow to a crazy value when the player is grounded, so we only increase while in the air if (characterGravity < -0.1f && characterController.isGrounded) { characterGravity = -0.1f; // ensures we will stick to the ground but won't clip through it due to too much gravity } #endregion movementSpeed.y += characterGravity; // has characterGravity affect the y axis of movementSpeed movementSpeed += jumpingForce * Time.deltaTime; // has jumpingForce affect movementSpeed playerSettings.CurrentMovementSpeed = new Vector3(playerSettings.WalkingStrafeSpeed * input_Movement.x, 0, playerSettings.WalkingForwardSpeed * input_Movement.y); // just for monitoring your current movement speed characterController.Move(movementSpeed); // actually moves the character based on movementSpeed } // calculates jumpingForce based off of a SmoothDamp function private void CalculateJump() { jumpingForce = Vector3.SmoothDamp(jumpingForce, Vector3.zero, ref jumpingForceVelocity, playerSettings.JumpingFalloff); } // sets the local variable (of type CharacterStance) currentStance based on playerStance enum // calculates cameraHeight variable and has it affect the cameraHolder.localPosition // makes the height and center of the characterController match the height and center of your currentStance.StanceCollider private void CalculateStance() { var currentStance = playerStandStance; // makes a local CharacterStance class variable called currentStance and gives it a default value of playerStandStance // if playerStance enum is set to crouch, set currentStance to be equal to playerCrouchStance if (playerStance == PlayerStance.Crouch) { currentStance = playerCrouchStance; } cameraHeight = Mathf.SmoothDamp(cameraHolder.localPosition.y, currentStance.CameraHeight, ref cameraHeightVelocity, playerStanceSmoothing); // calculates cameraHeight cameraHolder.localPosition = new Vector3(cameraHolder.localPosition.x, cameraHeight, cameraHolder.localPosition.z); // has cameraHeight affect the cameraHolder's local position characterController.height = Mathf.SmoothDamp(characterController.height, currentStance.StanceCollider.height, ref stanceCapsuleHeightVelocity, playerStanceSmoothing); // changes the height of the character controller to match the currentStance.StanceCollider.height characterController.center = Vector3.SmoothDamp(characterController.center, currentStance.StanceCollider.center, ref stanceCapsuleCenterVelocity, playerStanceSmoothing); // changes the center of the character controller to match the currentStance.StanceCollider.center } private void Jump() { // if you are crouching and you choose the jump action, stand instead if (playerStance == PlayerStance.Crouch) { Crouch(); return; } // if the character is not grounded, don't jump if (!characterController.isGrounded) { return; // if not grounded, do not perform anything else of the Jump method (so do not Jump) } // Jump script jumpingForce = Vector3.up * playerSettings.JumpingHeight; // sets jumpingForce based on JumpingHeight characterGravity = 0; // when jumping, set characterGravity to 0 } // toggles the playerStance private void Crouch() { // if the character is not grounded, don't allow them to manually change their stance if (!characterController.isGrounded) { return; // if not grounded, don't do anything } // if the player is standing when they press crouch, make them crouch if (playerStance == PlayerStance.Stand) { playerStance = PlayerStance.Crouch; return; } // if the player is crouching when they press crouch, make them stand if (playerStance == PlayerStance.Crouch) { // if there will be a collision if you stand if(StanceCheck(playerStandStance.StanceCollider.height)) { return; } else // if there won't be a collision, make the player stand { playerStance = PlayerStance.Stand; } } } // tests to see if there will be an obstruction above you if you stand up private bool StanceCheck(float stanceCheckHeight) { var start = new Vector3(feetTransform.position.x, feetTransform.position.y + characterController.radius + stanceCheckErrorMargin, feetTransform.position.z); var end = new Vector3(feetTransform.position.x, feetTransform.position.y - characterController.radius - stanceCheckErrorMargin + stanceCheckHeight, feetTransform.position.z); return Physics.CheckCapsule(start, end, characterController.radius, playerMask); } }