illiden

FirstPersonController

Feb 11th, 2023
769
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 8.66 KB | Source Code | 0 0
  1. using UnityEngine;
  2. #if ENABLE_INPUT_SYSTEM && STARTER_ASSETS_PACKAGES_CHECKED
  3. using UnityEngine.InputSystem;
  4. #endif
  5.  
  6. namespace StarterAssets
  7. {
  8.     [RequireComponent(typeof(CharacterController))]
  9. #if ENABLE_INPUT_SYSTEM && STARTER_ASSETS_PACKAGES_CHECKED
  10.     [RequireComponent(typeof(PlayerInput))]
  11. #endif
  12.     public class FirstPersonController : MonoBehaviour
  13.     {
  14.         [Header("Player")]
  15.         [Tooltip("Move speed of the character in m/s")]
  16.         public float MoveSpeed = 4.0f;
  17.         [Tooltip("Sprint speed of the character in m/s")]
  18.         public float SprintSpeed = 6.0f;
  19.         [Tooltip("Rotation speed of the character")]
  20.         public float RotationSpeed = 1.0f;
  21.         [Tooltip("Acceleration and deceleration")]
  22.         public float SpeedChangeRate = 10.0f;
  23.  
  24.         [Space(10)]
  25.         [Tooltip("The height the player can jump")]
  26.         public float JumpHeight = 1.2f;
  27.         [Tooltip("The character uses its own gravity value. The engine default is -9.81f")]
  28.         public float Gravity = -15.0f;
  29.  
  30.         [Space(10)]
  31.         [Tooltip("Time required to pass before being able to jump again. Set to 0f to instantly jump again")]
  32.         public float JumpTimeout = 0.1f;
  33.         [Tooltip("Time required to pass before entering the fall state. Useful for walking down stairs")]
  34.         public float FallTimeout = 0.15f;
  35.  
  36.         [Header("Player Grounded")]
  37.         [Tooltip("If the character is grounded or not. Not part of the CharacterController built in grounded check")]
  38.         public bool Grounded = true;
  39.         [Tooltip("Useful for rough ground")]
  40.         public float GroundedOffset = -0.14f;
  41.         [Tooltip("The radius of the grounded check. Should match the radius of the CharacterController")]
  42.         public float GroundedRadius = 0.5f;
  43.         [Tooltip("What layers the character uses as ground")]
  44.         public LayerMask GroundLayers;
  45.  
  46.         [Header("Cinemachine")]
  47.         [Tooltip("The follow target set in the Cinemachine Virtual Camera that the camera will follow")]
  48.         public GameObject CinemachineCameraTarget;
  49.         [Tooltip("How far in degrees can you move the camera up")]
  50.         public float TopClamp = 90.0f;
  51.         [Tooltip("How far in degrees can you move the camera down")]
  52.         public float BottomClamp = -90.0f;
  53.  
  54.         // cinemachine
  55.         private float _cinemachineTargetPitch;
  56.  
  57.         // player
  58.         private float _speed;
  59.         private float _rotationVelocity;
  60.         private float _verticalVelocity;
  61.         private float _terminalVelocity = 53.0f;
  62.  
  63.         // timeout deltatime
  64.         private float _jumpTimeoutDelta;
  65.         private float _fallTimeoutDelta;
  66.  
  67.    
  68. #if ENABLE_INPUT_SYSTEM && STARTER_ASSETS_PACKAGES_CHECKED
  69.         private PlayerInput _playerInput;
  70. #endif
  71.         private CharacterController _controller;
  72.         private StarterAssetsInputs _input;
  73.         private GameObject _mainCamera;
  74.  
  75.         private const float _threshold = 0.01f;
  76.  
  77.         private bool IsCurrentDeviceMouse
  78.         {
  79.             get
  80.             {
  81.                 #if ENABLE_INPUT_SYSTEM && STARTER_ASSETS_PACKAGES_CHECKED
  82.                 return _playerInput.currentControlScheme == "KeyboardMouse";
  83.                 #else
  84.                 return false;
  85.                 #endif
  86.             }
  87.         }
  88.  
  89.         private void Awake()
  90.         {
  91.             // get a reference to our main camera
  92.             if (_mainCamera == null)
  93.             {
  94.                 _mainCamera = GameObject.FindGameObjectWithTag("MainCamera");
  95.             }
  96.         }
  97.  
  98.         private void Start()
  99.         {
  100.             _controller = GetComponent<CharacterController>();
  101.             _input = GetComponent<StarterAssetsInputs>();
  102. #if ENABLE_INPUT_SYSTEM && STARTER_ASSETS_PACKAGES_CHECKED
  103.             _playerInput = GetComponent<PlayerInput>();
  104. #else
  105.             Debug.LogError( "Starter Assets package is missing dependencies. Please use Tools/Starter Assets/Reinstall Dependencies to fix it");
  106. #endif
  107.  
  108.             // reset our timeouts on start
  109.             _jumpTimeoutDelta = JumpTimeout;
  110.             _fallTimeoutDelta = FallTimeout;
  111.         }
  112.  
  113.         private void Update()
  114.         {
  115.             JumpAndGravity();
  116.             GroundedCheck();
  117.             Move();
  118.         }
  119.  
  120.         private void LateUpdate()
  121.         {
  122.             CameraRotation();
  123.         }
  124.  
  125.         private void GroundedCheck()
  126.         {
  127.             // set sphere position, with offset
  128.             Vector3 spherePosition = new Vector3(transform.position.x, transform.position.y - GroundedOffset, transform.position.z);
  129.             Grounded = Physics.CheckSphere(spherePosition, GroundedRadius, GroundLayers, QueryTriggerInteraction.Ignore);
  130.         }
  131.  
  132.         private void CameraRotation()
  133.         {
  134.             // if there is an input
  135.             if (_input.look.sqrMagnitude >= _threshold)
  136.             {
  137.                 //Don't multiply mouse input by Time.deltaTime
  138.                 float deltaTimeMultiplier = IsCurrentDeviceMouse ? 1.0f : Time.deltaTime;
  139.                
  140.                 _cinemachineTargetPitch += _input.look.y * RotationSpeed * deltaTimeMultiplier;
  141.                 _rotationVelocity = _input.look.x * RotationSpeed * deltaTimeMultiplier;
  142.  
  143.                 // clamp our pitch rotation
  144.                 _cinemachineTargetPitch = ClampAngle(_cinemachineTargetPitch, BottomClamp, TopClamp);
  145.  
  146.                 // Update Cinemachine camera target pitch
  147.                 CinemachineCameraTarget.transform.localRotation = Quaternion.Euler(_cinemachineTargetPitch, 0.0f, 0.0f);
  148.  
  149.                 // rotate the player left and right
  150.                 transform.Rotate(Vector3.up * _rotationVelocity);
  151.             }
  152.         }
  153.  
  154.         private void Move()
  155.         {
  156.             // set target speed based on move speed, sprint speed and if sprint is pressed
  157.             float targetSpeed = _input.sprint ? SprintSpeed : MoveSpeed;
  158.  
  159.             // a simplistic acceleration and deceleration designed to be easy to remove, replace, or iterate upon
  160.  
  161.             // note: Vector2's == operator uses approximation so is not floating point error prone, and is cheaper than magnitude
  162.             // if there is no input, set the target speed to 0
  163.             if (_input.move == Vector2.zero) targetSpeed = 0.0f;
  164.  
  165.             // a reference to the players current horizontal velocity
  166.             float currentHorizontalSpeed = new Vector3(_controller.velocity.x, 0.0f, _controller.velocity.z).magnitude;
  167.  
  168.             float speedOffset = 0.1f;
  169.             float inputMagnitude = _input.analogMovement ? _input.move.magnitude : 1f;
  170.  
  171.             // accelerate or decelerate to target speed
  172.             if (currentHorizontalSpeed < targetSpeed - speedOffset || currentHorizontalSpeed > targetSpeed + speedOffset)
  173.             {
  174.                 // creates curved result rather than a linear one giving a more organic speed change
  175.                 // note T in Lerp is clamped, so we don't need to clamp our speed
  176.                 _speed = Mathf.Lerp(currentHorizontalSpeed, targetSpeed * inputMagnitude, Time.deltaTime * SpeedChangeRate);
  177.  
  178.                 // round speed to 3 decimal places
  179.                 _speed = Mathf.Round(_speed * 1000f) / 1000f;
  180.             }
  181.             else
  182.             {
  183.                 _speed = targetSpeed;
  184.             }
  185.  
  186.             // normalise input direction
  187.             Vector3 inputDirection = new Vector3(_input.move.x, 0.0f, _input.move.y).normalized;
  188.  
  189.             // note: Vector2's != operator uses approximation so is not floating point error prone, and is cheaper than magnitude
  190.             // if there is a move input rotate player when the player is moving
  191.             if (_input.move != Vector2.zero)
  192.             {
  193.                 // move
  194.                 inputDirection = transform.right * _input.move.x + transform.forward * _input.move.y;
  195.             }
  196.  
  197.             // move the player
  198.             _controller.Move(inputDirection.normalized * (_speed * Time.deltaTime) + new Vector3(0.0f, _verticalVelocity, 0.0f) * Time.deltaTime);
  199.         }
  200.  
  201.         private void JumpAndGravity()
  202.         {
  203.             if (Grounded)
  204.             {
  205.                 // reset the fall timeout timer
  206.                 _fallTimeoutDelta = FallTimeout;
  207.  
  208.                 // stop our velocity dropping infinitely when grounded
  209.                 if (_verticalVelocity < 0.0f)
  210.                 {
  211.                     _verticalVelocity = -2f;
  212.                 }
  213.  
  214.                 // Jump
  215.                 if (_input.jump && _jumpTimeoutDelta <= 0.0f)
  216.                 {
  217.                     // the square root of H * -2 * G = how much velocity needed to reach desired height
  218.                     _verticalVelocity = Mathf.Sqrt(JumpHeight * -2f * Gravity);
  219.                 }
  220.  
  221.                 // jump timeout
  222.                 if (_jumpTimeoutDelta >= 0.0f)
  223.                 {
  224.                     _jumpTimeoutDelta -= Time.deltaTime;
  225.                 }
  226.             }
  227.             else
  228.             {
  229.                 // reset the jump timeout timer
  230.                 _jumpTimeoutDelta = JumpTimeout;
  231.  
  232.                 // fall timeout
  233.                 if (_fallTimeoutDelta >= 0.0f)
  234.                 {
  235.                     _fallTimeoutDelta -= Time.deltaTime;
  236.                 }
  237.  
  238.                 // if we are not grounded, do not jump
  239.                 _input.jump = false;
  240.             }
  241.  
  242.             // apply gravity over time if under terminal (multiply by delta time twice to linearly speed up over time)
  243.             if (_verticalVelocity < _terminalVelocity)
  244.             {
  245.                 _verticalVelocity += Gravity * Time.deltaTime;
  246.             }
  247.         }
  248.  
  249.         private static float ClampAngle(float lfAngle, float lfMin, float lfMax)
  250.         {
  251.             if (lfAngle < -360f) lfAngle += 360f;
  252.             if (lfAngle > 360f) lfAngle -= 360f;
  253.             return Mathf.Clamp(lfAngle, lfMin, lfMax);
  254.         }
  255.  
  256.         private void OnDrawGizmosSelected()
  257.         {
  258.             Color transparentGreen = new Color(0.0f, 1.0f, 0.0f, 0.35f);
  259.             Color transparentRed = new Color(1.0f, 0.0f, 0.0f, 0.35f);
  260.  
  261.             if (Grounded) Gizmos.color = transparentGreen;
  262.             else Gizmos.color = transparentRed;
  263.  
  264.             // when selected, draw a gizmo in the position of, and matching radius of, the grounded collider
  265.             Gizmos.DrawSphere(new Vector3(transform.position.x, transform.position.y - GroundedOffset, transform.position.z), GroundedRadius);
  266.         }
  267.     }
  268. }
Advertisement
Add Comment
Please, Sign In to add comment