using System.Collections; using System.Collections.Generic; using UnityEngine; using Chronos; using static scr_Models; public class scr_CharacterController : MonoBehaviour { private CharacterController characterController; // create a variable of type CharacterController and call it characterController private DefaultInput defaultInput; // create a variable of type DefaultInput and call it defaultInput private Vector2 input_Movement; // NOTE: can make it public if you want to monitor it private Vector2 input_View; // NOTE: can make it public if you want to monitor it private Vector3 newCameraRotation; private Vector3 newCharacterRotation; // private float timeMovementMultiplier; // timeMovementMultiplier is used in CalculateView and CalculateMovement to counteract any slow motion going on (allowing the player to move at a different pace then everything else) private bool isSlowMo = false; [Header("References")] public Transform cameraHolder; public Transform feetTransform; public scr_TimeManager timeManager; public Timekeeper timeKeeper; public LocalClock localClock; [Header("Settings")] public PlayerSettingsModel playerSettings; // make sure you have "using static scr_Models;" up top. public float viewClampYMin = -70; public float viewClampYMax = 80; public LayerMask playerMask; // used to exclude the player from being detected on the stance check [Header("Gravity")] public float gravityAmount; public float gravityMin; public float playerGravity; // NOTE: can make it public if you want to monitor player gravity public Vector3 jumpingForce; private Vector3 jumpingForceVelocity; [Header("Stance")] public PlayerStance playerStance; // an enum with the different stances public float playerStanceSmoothing; // time in seconds in takes to move to different player stances public CharacterStance playerStandStance; public CharacterStance playerCrouchStance; public CharacterStance playerProneStance; private float stanceCheckErrorMargin = 0.05f; // since feetTransform is at our feet (0,0,0), we need a margin of error or else the stance check will detect the floor. private float cameraHeight; private float cameraHeightVelocity; private Vector3 stanceCapsuleCenterVelocity; private float stanceCapsuleHeightVelocity; private float stanceCapsuleRadiusVelocity; private void Awake() // Awake is called when the script instance is being loaded { Cursor.lockState = CursorLockMode.Locked; // locks the cursor to the middle of the screen when you click the screen #region - Input related script defaultInput = new DefaultInput(); // creates a new instance of a DefaultInput for the private variable defaultInput to be equal to #region - Input Events defaultInput.Character.Movement.performed += e => input_Movement = e.ReadValue(); defaultInput.Character.View.performed += e => input_View = e.ReadValue(); defaultInput.Character.Jump.performed += e => Jump(); defaultInput.Character.SlowMo.performed += e => SlowMo(); defaultInput.Character.Crouch.performed += e => Crouch(); defaultInput.Character.Prone.performed += e => Prone(); #endregion defaultInput.Enable(); // allows Actions from that Input system to be performed #endregion newCameraRotation = cameraHolder.localRotation.eulerAngles; // gives newCameraRotation a default value newCharacterRotation = transform.localRotation.eulerAngles; // gives newCharacterRotation a default value characterController = GetComponent(); // assign the characterController variable an actual value of the player's own CharacterController component cameraHeight = cameraHolder.localPosition.y; // gives the cameraHeight an initial value based on the cameraHolder's y position } private void Update() { CalculateView(); CalculateMovement(); CalculateJump(); CalculateStance(); // CalculateTimeMovementMultiplier(); } private void OnCollisionEnter (Collision collision) { if (collision.gameObject.tag == "Object") { Debug.Log("Collided"); } } // test collisions with an object that has the Objects tag /* private void CalculateTimeMovementMultiplier() { // timeMovementMultiplier = (1 / Time.timeScale); timeMovementMultiplier = (1 / (Time.timeScale + .2f)); } */ private void CalculateView() { #region - Calculate view rotating around y axis (left and right) newCharacterRotation.y += playerSettings.ViewXSensitivity * (playerSettings.ViewXInverted ? -input_View.x : input_View.x) * Time.deltaTime; // updates the newCharacterRotation transform.localRotation = Quaternion.Euler(newCharacterRotation); // sets the localRotation of the character to be same as the newCharacterRotation #endregion #region - Calculate view rotating around x axis (up and down) newCameraRotation.x += playerSettings.ViewYSensitivity * (playerSettings.ViewYInverted ? input_View.y : -input_View.y) * Time.deltaTime; // updates the newCameraRotation newCameraRotation.x = Mathf.Clamp(newCameraRotation.x, viewClampYMin, viewClampYMax); // clamps rotation around x axis (moving camera up and down) cameraHolder.localRotation = Quaternion.Euler(newCameraRotation); // updates the cameraHolder localRotationto be the same as the newCameraRotation #endregion } private void CalculateMovement() { var verticalSpeed = playerSettings.WalkingForwardSpeed * input_Movement.y * Time.deltaTime; // calculates and sets your verticalSpeed var horizontalSpeed = playerSettings.WalkingStrafeSpeed * input_Movement.x * Time.deltaTime; // calculates and sets your horizontalSpeed var newMovementSpeed = new Vector3(horizontalSpeed, 0, verticalSpeed); // calculates and sets your newMovementSpeed based on your horizontal and vertical speeds newMovementSpeed = transform.TransformDirection(newMovementSpeed); // makes movement act relative to the player's rotation if (playerGravity > gravityMin) // if playerGravity > gravityMin, start applying gravity { playerGravity -= gravityAmount * Time.deltaTime * localClock.localTimeScale; } if (playerGravity < -0.1f && characterController.isGrounded) // "so the value doesn't grow to a tremendous value when we're grounded, so only increase while we're in the air" { playerGravity = -0.1f; } newMovementSpeed.y += playerGravity; // makes playerGravity affect the y axis of newMovementSpeed newMovementSpeed += jumpingForce * Time.deltaTime; // has jumpingForce affect newMovementSpeed characterController.Move(newMovementSpeed * localClock.localTimeScale); // makes your characterController move based on your newMovementSpeed } private void CalculateJump() { jumpingForce = Vector3.SmoothDamp(jumpingForce, Vector3.zero, ref jumpingForceVelocity, playerSettings.JumpingFalloff * (1 / localClock.localTimeScale)); // calculates the jumpForce that you can monitor in Unity if (characterController.isGrounded) // if the characterController is grounded, set the jumpingForce.y to 0. { jumpingForce.y = 0; } } private void CalculateStance() { var currentStance = playerStandStance; // currentStance is the current stance of the player if (playerStance == PlayerStance.Crouch) { currentStance = playerCrouchStance; } else if (playerStance == PlayerStance.Prone) { currentStance = playerProneStance; } cameraHeight = Mathf.SmoothDamp(cameraHolder.localPosition.y, currentStance.CameraHeight, ref cameraHeightVelocity, playerStanceSmoothing); // Calculates and changes what the value of cameraHeight will be. Mathf.SmoothDamp gradually changes a value towards a desired goal over time. cameraHolder.localPosition = new Vector3(cameraHolder.localPosition.x, cameraHeight, cameraHolder.localPosition.z); // has the cameraHeight affect the actual camerHolder.localPosition.y characterController.height = Mathf.SmoothDamp(characterController.height, currentStance.StanceCollider.height, ref stanceCapsuleHeightVelocity, playerStanceSmoothing); // Calculates and changes what the value of the characterController's height will be. characterController.center = Vector3.SmoothDamp(characterController.center, currentStance.StanceCollider.center, ref stanceCapsuleCenterVelocity, playerStanceSmoothing); // Calculates and changes what the value of the characterController's center will be. characterController.radius = Mathf.SmoothDamp(characterController.radius, currentStance.StanceCollider.radius, ref stanceCapsuleRadiusVelocity, playerStanceSmoothing); // Not neccessary unless you change the values of the radius among capsules; calculates and changes what the value of the characterController's radius will be. } private void Jump() { if (!characterController.isGrounded) // if the character isn't grounded, don't jump { return; } // Jump jumpingForce = Vector3.up * playerSettings.JumpingHeight; // has JumpingHeight setting affect jumpingForce playerGravity = 0; // basically disables playerGravity when you jump } private void SlowMo() { if (isSlowMo == false) // is the isSlowMo boolean false? { // timeManager.DoSlowMotion(); // GetComponent().localTimeScale = 0.3f; timeKeeper.GetComponent().localTimeScale = 0.3f; // sets the global clock's time scale localClock.localTimeScale = 0.5f; // sets the player's time scale isSlowMo = true; Debug.Log("SlowMo"); } else // if the isSlowMo boolean is true { // timeManager.ReturnNormalSpeed(); // GetComponent().localTimeScale = 1.0f; timeKeeper.GetComponent().localTimeScale = 1.0f; // sets the global clock's time scale back to normal localClock.localTimeScale = 1.0f; // sets the player's time scale back to normal isSlowMo = false; Debug.Log("Normal speed"); } } private void Crouch() // sets the value of playerStance { if (playerStance == PlayerStance.Crouch) // if you are already crouching { if (StanceCheck(playerStandStance.StanceCollider.height)) // will there be a collision if you stand again? { return; // if there will be a collision, don't stand up } playerStance = PlayerStance.Stand; // if the player is already crouched and there won't be a collision if they stand up, stand up return; } if (StanceCheck(playerCrouchStance.StanceCollider.height)) // will there be a collision if you crouch? { return; // if there will be a collision, don't crouch } playerStance = PlayerStance.Crouch; // if there won't be a collision, crouch } private void Prone() // sets the value of playerStance { playerStance = PlayerStance.Prone; } private bool StanceCheck(float stanceCheckHeight) // stanceCheckHeight is the height of the capsule { var start = new Vector3(feetTransform.position.x, feetTransform.position.y + characterController.radius + stanceCheckErrorMargin, feetTransform.position.z); // establishes where the capsule check starts at (at the very bottom) var end = new Vector3(feetTransform.position.x, feetTransform.position.y - characterController.radius - stanceCheckErrorMargin + stanceCheckHeight, feetTransform.position.z); // establishes where the capsule check ends at (at the very top) return Physics.CheckCapsule(start, end, characterController.radius, playerMask); } }