Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using UnityEngine;
- #if ENABLE_INPUT_SYSTEM
- using UnityEngine.InputSystem;
- #endif
- using AC;
- namespace StarterAssets
- {
- [RequireComponent(typeof(CharacterController))]
- #if ENABLE_INPUT_SYSTEM
- [RequireComponent(typeof(UnityEngine.InputSystem.PlayerInput))]
- #endif
- public class FirstPersonController : MonoBehaviour
- {
- const string PrefMouse = "MouseLookSensitivity";
- const string PrefController = "ControllerLookSensitivity";
- const string PrefInvertY = "InvertY";
- [Header("Player")]
- [Tooltip("Move speed of the character in m/s")]
- public float MoveSpeed = 4.0f;
- [Tooltip("Sprint speed of the character in m/s")]
- public float SprintSpeed = 6.0f;
- [Tooltip("Rotation speed of the character")]
- public float RotationSpeed = 1.0f;
- [Tooltip("Acceleration and deceleration")]
- public float SpeedChangeRate = 10.0f;
- [Tooltip("Multiplier for controller look sensitivity")]
- public float ControllerLookMultiplier = 0.5f;
- public bool invertY = false;
- private const float YAxisReduction = 0.75f;
- [Header("Look")]
- [Tooltip("Multiplier for mouse look sensitivity")]
- [Range(0.1f, 3f)]
- public float MouseLookMultiplier = 1.0f;
- [Space(10)]
- [Tooltip("The height the player can jump")]
- public float JumpHeight = 1.2f;
- [Tooltip("The character uses its own gravity value. The engine default is -9.81f")]
- public float Gravity = -15.0f;
- [Space(10)]
- [Tooltip("Time required to pass before being able to jump again. Set to 0f to instantly jump again")]
- public float JumpTimeout = 0.1f;
- [Tooltip("Time required to pass before entering the fall state. Useful for walking down stairs")]
- public float FallTimeout = 0.15f;
- [Header("Player Grounded")]
- [Tooltip("If the character is grounded or not. Not part of the CharacterController built in grounded check")]
- public bool Grounded = true;
- [Tooltip("Useful for rough ground")]
- public float GroundedOffset = -0.14f;
- [Tooltip("The radius of the grounded check. Should match the radius of the CharacterController")]
- public float GroundedRadius = 0.5f;
- [Tooltip("What layers the character uses as ground")]
- public LayerMask GroundLayers;
- [Header("Cinemachine")]
- [Tooltip("The follow target set in the Cinemachine Virtual Camera that the camera will follow")]
- public GameObject CinemachineCameraTarget;
- [Tooltip("How far in degrees can you move the camera up")]
- public float TopClamp = 90.0f;
- [Tooltip("How far in degrees can you move the camera down")]
- public float BottomClamp = -90.0f;
- // cinemachine
- private float _cinemachineTargetPitch;
- // player
- private float _speed;
- private float _rotationVelocity;
- private float _verticalVelocity;
- private float _terminalVelocity = 53.0f;
- // timeout deltatime
- private float _jumpTimeoutDelta;
- private float _fallTimeoutDelta;
- #if ENABLE_INPUT_SYSTEM
- private UnityEngine.InputSystem.PlayerInput _playerInput;
- #endif
- private CharacterController _controller;
- private StarterAssetsInputs _input;
- private GameObject _mainCamera;
- private const float _threshold = 0.01f;
- private bool IsCurrentDeviceMouse
- {
- get
- {
- #if ENABLE_INPUT_SYSTEM
- return _playerInput.currentControlScheme == "KeyboardMouse";
- #else
- return false;
- #endif
- }
- }
- private void Awake()
- {
- if (_mainCamera == null)
- {
- _mainCamera = GameObject.FindGameObjectWithTag("MainCamera");
- }
- }
- private void Start()
- {
- _controller = GetComponent<CharacterController>();
- _input = GetComponent<StarterAssetsInputs>();
- #if ENABLE_INPUT_SYSTEM
- _playerInput = GetComponent<UnityEngine.InputSystem.PlayerInput>();
- #else
- Debug.LogError("Starter Assets package is missing dependencies. Please use Tools/Starter Assets/Reinstall Dependencies to fix it");
- #endif
- _jumpTimeoutDelta = JumpTimeout;
- _fallTimeoutDelta = FallTimeout;
- }
- private void OnEnable()
- {
- if (PlayerPrefs.HasKey(PrefInvertY))
- {
- invertY = PlayerPrefs.GetInt(PrefInvertY) == 1;
- }
- else
- {
- GVar invertVar = GlobalVariables.GetVariable("InvertY");
- if (invertVar != null)
- invertY = invertVar.BooleanValue;
- }
- if (PlayerPrefs.HasKey(PrefMouse))
- {
- float m = Mathf.Clamp(PlayerPrefs.GetFloat(PrefMouse), 0.1f, 4f);
- MouseLookMultiplier = Mathf.Round(m * 10f) / 10f;
- }
- if (PlayerPrefs.HasKey(PrefController))
- {
- float c = Mathf.Clamp(PlayerPrefs.GetFloat(PrefController), 0.1f, 1f);
- ControllerLookMultiplier = Mathf.Round(c * 100f) / 100f;
- }
- }
- private void Update()
- {
- JumpAndGravity();
- GroundedCheck();
- Move();
- }
- private void LateUpdate()
- {
- CameraRotation();
- }
- private void GroundedCheck()
- {
- Vector3 spherePosition = new Vector3(transform.position.x, transform.position.y - GroundedOffset, transform.position.z);
- Grounded = Physics.CheckSphere(spherePosition, GroundedRadius, GroundLayers, QueryTriggerInteraction.Ignore);
- }
- private void CameraRotation()
- {
- if (_input.look.sqrMagnitude >= _threshold)
- {
- float deltaTimeMultiplier = IsCurrentDeviceMouse ? 1.0f : Time.deltaTime;
- float deviceMultiplier = IsCurrentDeviceMouse ? MouseLookMultiplier : ControllerLookMultiplier;
- float yInput = _input.look.y;
- if (!IsCurrentDeviceMouse && invertY)
- yInput = -yInput;
- _cinemachineTargetPitch += yInput * RotationSpeed * deltaTimeMultiplier * deviceMultiplier * YAxisReduction;
- _rotationVelocity = _input.look.x * RotationSpeed * deltaTimeMultiplier * deviceMultiplier;
- // clamp our pitch rotation
- _cinemachineTargetPitch = ClampAngle(_cinemachineTargetPitch, BottomClamp, TopClamp);
- // Update Cinemachine camera target pitch
- CinemachineCameraTarget.transform.localRotation = Quaternion.Euler(_cinemachineTargetPitch, 0.0f, 0.0f);
- // rotate the player left and right
- transform.Rotate(Vector3.up * _rotationVelocity);
- }
- }
- public void SetMouseSensitivity(float value)
- {
- MouseLookMultiplier = value;
- }
- public void SetInvertY(bool on)
- {
- invertY = on;
- PlayerPrefs.SetInt(PrefInvertY, on ? 1 : 0);
- GVar invertVar = GlobalVariables.GetVariable("InvertY");
- if (invertVar != null)
- invertVar.BooleanValue = on;
- }
- private void Move()
- {
- // set target speed based on move speed, sprint speed and if sprint is pressed
- float targetSpeed = _input.sprint ? SprintSpeed : MoveSpeed;
- // a simplistic acceleration and deceleration designed to be easy to remove, replace, or iterate upon
- // note: Vector2's == operator uses approximation so is not floating point error prone, and is cheaper than magnitude
- // if there is no input, set the target speed to 0
- if (_input.move == Vector2.zero) targetSpeed = 0.0f;
- // a reference to the players current horizontal velocity
- float currentHorizontalSpeed = new Vector3(_controller.velocity.x, 0.0f, _controller.velocity.z).magnitude;
- float speedOffset = 0.1f;
- float inputMagnitude = _input.analogMovement ? _input.move.magnitude : 1f;
- // accelerate or decelerate to target speed
- if (currentHorizontalSpeed < targetSpeed - speedOffset || currentHorizontalSpeed > targetSpeed + speedOffset)
- {
- // creates curved result rather than a linear one giving a more organic speed change
- // note T in Lerp is clamped, so we don't need to clamp our speed
- _speed = Mathf.Lerp(currentHorizontalSpeed, targetSpeed * inputMagnitude, Time.deltaTime * SpeedChangeRate);
- // round speed to 3 decimal places
- _speed = Mathf.Round(_speed * 1000f) / 1000f;
- }
- else
- {
- _speed = targetSpeed;
- }
- // normalise input direction
- Vector3 inputDirection = new Vector3(_input.move.x, 0.0f, _input.move.y).normalized;
- // note: Vector2's != operator uses approximation so is not floating point error prone, and is cheaper than magnitude
- // if there is a move input rotate player when the player is moving
- if (_input.move != Vector2.zero)
- {
- // move
- inputDirection = transform.right * _input.move.x + transform.forward * _input.move.y;
- }
- // move the player
- _controller.Move(inputDirection.normalized * (_speed * Time.deltaTime) + new Vector3(0.0f, _verticalVelocity, 0.0f) * Time.deltaTime);
- }
- private void JumpAndGravity()
- {
- if (Grounded)
- {
- // reset the fall timeout timer
- _fallTimeoutDelta = FallTimeout;
- // stop our velocity dropping infinitely when grounded
- if (_verticalVelocity < 0.0f)
- {
- _verticalVelocity = -2f;
- }
- // Jump
- if (_input.jump && _jumpTimeoutDelta <= 0.0f)
- {
- // the square root of H * -2 * G = how much velocity needed to reach desired height
- _verticalVelocity = Mathf.Sqrt(JumpHeight * -2f * Gravity);
- }
- // jump timeout
- if (_jumpTimeoutDelta >= 0.0f)
- {
- _jumpTimeoutDelta -= Time.deltaTime;
- }
- }
- else
- {
- // reset the jump timeout timer
- _jumpTimeoutDelta = JumpTimeout;
- // fall timeout
- if (_fallTimeoutDelta >= 0.0f)
- {
- _fallTimeoutDelta -= Time.deltaTime;
- }
- // if we are not grounded, do not jump
- _input.jump = false;
- }
- // apply gravity over time if under terminal (multiply by delta time twice to linearly speed up over time)
- if (_verticalVelocity < _terminalVelocity)
- {
- _verticalVelocity += Gravity * Time.deltaTime;
- }
- }
- private static float ClampAngle(float lfAngle, float lfMin, float lfMax)
- {
- if (lfAngle < -360f) lfAngle += 360f;
- if (lfAngle > 360f) lfAngle -= 360f;
- return Mathf.Clamp(lfAngle, lfMin, lfMax);
- }
- private void OnDrawGizmosSelected()
- {
- Color transparentGreen = new Color(0.0f, 1.0f, 0.0f, 0.35f);
- Color transparentRed = new Color(1.0f, 0.0f, 0.0f, 0.35f);
- if (Grounded) Gizmos.color = transparentGreen;
- else Gizmos.color = transparentRed;
- // when selected, draw a gizmo in the position of, and matching radius of, the grounded collider
- Gizmos.DrawSphere(new Vector3(transform.position.x, transform.position.y - GroundedOffset, transform.position.z), GroundedRadius);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment