using UnityEngine; using Mirror; using TMPro; using Characters; using Debuffs; using Koptilnya; /* Note: animations are called via the controller for both the character and capsule using animator null checks */ namespace StarterAssets { [RequireComponent(typeof(CharacterController))] public class PersonController : Pawn { [Header("Oscar nasral v kod")] public GameObject headPosition; public GameObject floatingInfo; public TMP_Text nicknameInput; public AudioSource audioSource; public AudioClip footStepClip; private AudioClip _gotEnergyClip; private Interactions _interactions; private Vector2 _lerpInputVec, _inputVec; private float _controllerVelocity, lerp; private bool _inputJump; private Vector2 _inputMove; public float _stepCycle, _stepTiming = 1; [Header("Player")] [Tooltip("Move speed of the character in m/s")] public float MoveSpeed = 2.0f; [Tooltip("Sprint speed of the character in m/s")] public float SprintSpeed = 5.335f; [Tooltip("Acceleration and deceleration")] public float SpeedChangeRate = 10.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.50f; [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.28f; [Tooltip("What layers the character uses as ground")] public LayerMask GroundLayers; public bool LockCameraPosition = false; private float _cinemachineTargetYaw; [SyncVar] public Transform _parent; private float _speed; private float _animationBlend; private float _verticalVelocity; private float _terminalVelocity = 53.0f; private float _jumpTimeoutDelta; private float _fallTimeoutDelta; // animation IDs private int _animIDSpeed, _animIDGrounded, _animIDJump, _animIDFreeFall, _animIDMotionSpeed, _animIDX, _animIDY; public Animator _animator; private CharacterController _controller; public GameObject mainCamera; private const float _threshold = 0.01f; private bool _hasAnimator = true; [SyncVar(hook = nameof(OnPlayerSetup))] public string playerName; [SyncVar, HideInInspector] public Color gunColor; private Vector3 _position; private float _rotationVelocity; private Vector2 _mouseLook; [SyncVar] public float _cinemachineTargetPitch; public GameObject CinemachineCameraTarget; public float RotationSpeed = 1f; public float BottomClamp = -90.0f; public float TopClamp = 90.0f; [Command] public void CmdSetupPlayer(string _name, float r, float g, float b) { gunColor = new Color(r, g, b); playerName = _name; } public void OnPlayerSetup(string _Old, string _New) { nicknameInput.text = playerName; } public override void OnStartLocalPlayer() { CmdSetupPlayer( PlayerPrefs.GetString("NickName"), PlayerPrefs.GetFloat("GunColorR"), PlayerPrefs.GetFloat("GunColorG"), PlayerPrefs.GetFloat("GunColorB") ); } private void Start() { RotationSpeed = PlayerPrefs.GetFloat("Sensitivity"); _controller = GetComponent(); _gotEnergyClip = Resources.Load("Audio/CharacterSounds/GetEnergy"); Live(); _interactions = GetComponent(); if (isLocalPlayer) { floatingInfo.SetActive(false); } if (!isLocalPlayer) return; AssignAnimationIDs(); _jumpTimeoutDelta = JumpTimeout; _fallTimeoutDelta = FallTimeout; } private void Update() { if (Alive) { CalculateFootstepTriggers(); setParent(); } if (!isLocalPlayer) { if (netIdentity.isActiveAndEnabled && floatingInfo != null && Camera.main) floatingInfo.transform.LookAt(Camera.main.transform); return; } if (Cursor.lockState == CursorLockMode.None) return; if (Alive) { CalculateEnergy(); GroundedCheck(); JumpAndGravity(); Move(); } else { SpectatorMove(); } } private void LateUpdate() { if (!isLocalPlayer) return; if (Cursor.lockState == CursorLockMode.None) return; CameraRotation(); SetCamToHeadPos(); } void CameraRotation() { if (Cursor.lockState == CursorLockMode.None) return; _mouseLook = new Vector2(Input.GetAxis("Mouse X"), -Input.GetAxis("Mouse Y")); _cinemachineTargetPitch += _mouseLook.y * RotationSpeed; _rotationVelocity = _mouseLook.x * RotationSpeed; _cinemachineTargetPitch = _cinemachineTargetPitch.ClampAngle(BottomClamp, TopClamp); transform.Rotate(Vector3.up * _rotationVelocity); CinemachineCameraTarget.transform.localRotation = Quaternion.Euler(_cinemachineTargetPitch, 0.0f, 0.0f); // CmdSetCameraPitch(_cinemachineTargetPitch); } private void SetCamToHeadPos() { CinemachineCameraTarget.transform.position = headPosition.transform.position; } private void AssignAnimationIDs() { _animIDSpeed = Animator.StringToHash("Speed"); _animIDGrounded = Animator.StringToHash("Grounded"); _animIDJump = Animator.StringToHash("Jump"); _animIDFreeFall = Animator.StringToHash("FreeFall"); _animIDMotionSpeed = Animator.StringToHash("MotionSpeed"); _animIDX = Animator.StringToHash("x"); _animIDY = Animator.StringToHash("y"); } 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); if (_hasAnimator) { _animator.SetBool(_animIDGrounded, Grounded); } } public float currentEnergy = 100f, shootDepletion = 15f, _flashLightDepletion = 0.3f; private float _maxEnergy = 1000f, _depletionSpeed = 0.5f, _regenerationSpeed = 1f, _jumpDepletion = 5f; private void CalculateEnergy() { if (Input.GetKey(KeyCode.LeftShift) && _inputMove.magnitude != 0) { currentEnergy = Mathf.MoveTowards(currentEnergy, 0, _depletionSpeed * Time.deltaTime); } else if (currentEnergy <= _maxEnergy) { currentEnergy = Mathf.MoveTowards(currentEnergy, _maxEnergy, _regenerationSpeed * Time.deltaTime); } if (currentEnergy <= 0) { CmdDie(); } } public void InstantStaminaReduction(float Reduction) { currentEnergy = Mathf.Clamp(currentEnergy -= Reduction, 0, _maxEnergy); } public void InstantStaminaRegeneration(float Regeneration) { currentEnergy = Mathf.Clamp(currentEnergy += Regeneration, 0, _maxEnergy); CmdGotEnergy(); } [Command(requiresAuthority = false)] void CmdGotEnergy() { RpcGotEnergy(); } [ClientRpc] void RpcGotEnergy() { audioSource.PlayOneShot(_gotEnergyClip); } [Command] void CmdSetCameraPitch(float value) { _cinemachineTargetPitch = value; } void SetCameraPitch() { lerp = Mathf.Lerp(lerp, _cinemachineTargetPitch, Time.deltaTime * 10f); CinemachineCameraTarget.transform.localRotation = Quaternion.Euler(lerp, 0.0f, 0.0f); } private void Move() { _inputMove = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical")); float targetSpeed = Input.GetKey(KeyCode.LeftShift) ? (currentEnergy <= _depletionSpeed ? MoveSpeed : SprintSpeed) : MoveSpeed; targetSpeed *= _speedMul; if (_inputMove == Vector2.zero) targetSpeed = 0.0f; float currentHorizontalSpeed = new Vector3(_controller.velocity.x, 0.0f, _controller.velocity.z).magnitude; float speedOffset = 0.1f; float inputMagnitude = 1f; if (currentHorizontalSpeed < targetSpeed - speedOffset || currentHorizontalSpeed > targetSpeed + speedOffset) { _speed = Mathf.Lerp(currentHorizontalSpeed, targetSpeed * inputMagnitude, Time.deltaTime * SpeedChangeRate); _speed = Mathf.Round(_speed * 1000f) / 1000f; } else { _speed = targetSpeed; } _animationBlend = Mathf.Lerp(_animationBlend, targetSpeed, Time.deltaTime * SpeedChangeRate); Vector3 inputDirection = new Vector3(_inputMove.x, 0.0f, _inputMove.y).normalized; if (_inputMove != Vector2.zero) { inputDirection = transform.right * _inputMove.x + transform.forward * _inputMove.y; } RaycastHit hit; if (Physics.Raycast(transform.position, -transform.up, out hit, 1f, LayerMask.NameToLayer("Player"))) { if (hit.collider.tag == "MovingPlatform" && hit.collider.GetComponentInParent() != null) { CmdSetParent(hit.collider.transform.parent); } else { CmdSetParent(null); } } _controller.Move(inputDirection.normalized * (_speed * Time.deltaTime) + new Vector3(0.0f, _verticalVelocity, 0.0f) * Time.deltaTime); if (_hasAnimator) { _lerpInputVec = Vector2.Lerp(_lerpInputVec, _inputMove, Time.deltaTime * 10); _animator.SetFloat(_animIDSpeed, _animationBlend); _animator.SetFloat(_animIDMotionSpeed, inputMagnitude); _animator.SetFloat(_animIDX, _lerpInputVec.x); _animator.SetFloat(_animIDY, _lerpInputVec.y); } } void SpectatorMove() { float inputZ = (Input.GetKey(KeyCode.E) ? 1 : 0) - (Input.GetKey(KeyCode.Q) ? 1 : 0) + (Input.GetKey(KeyCode.Space) ? 1 : 0) - (Input.GetKey(KeyCode.LeftShift) ? 1 : 0); float targetSpeed = MoveSpeed; //Input.GetKey(KeyCode.LeftShift) ? SprintSpeed : MoveSpeed; _inputMove = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical")); Vector3 inputDirection = transform.right * _inputMove.x + transform.forward * _inputMove.y + transform.up * inputZ; transform.position += inputDirection * Time.deltaTime * targetSpeed * 10f; } void setParent() { transform.parent = _parent; } [Command] void CmdSetParent(Transform transf) { _parent = transf; } public override void TakeDamage() { _animator.SetTrigger("damage"); InstantStaminaReduction(shootDepletion * 0.7f); // Debug.Log(self.GetComponent().playerName); // hitVFX.Stop(); // hitVFX.Play(); // self.GetComponent().DropProp(); } private void JumpAndGravity() { if (Grounded) { _inputJump = Input.GetKeyDown(KeyCode.Space); // reset the fall timeout timer _fallTimeoutDelta = FallTimeout; // update animator if using character if (_hasAnimator) { _animator.SetBool(_animIDJump, false); _animator.SetBool(_animIDFreeFall, false); } // stop our velocity dropping infinitely when grounded if (_verticalVelocity < 0.0f) { _verticalVelocity = -2f; } // Jump if (_inputJump && _jumpTimeoutDelta <= 0.0f && currentEnergy >= _jumpDepletion) { // the square root of H * -2 * G = how much velocity needed to reach desired height _verticalVelocity = Mathf.Sqrt(JumpHeight * -2f * Gravity); InstantStaminaReduction(_jumpDepletion); // update animator if using character if (_hasAnimator) { _animator.SetBool(_animIDJump, true); } } // 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; } else { // update animator if using character if (_hasAnimator) { _animator.SetBool(_animIDFreeFall, true); } } // if we are not grounded, do not jump _inputJump = 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 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); } void CalculateFootstepTriggers() { float _controllerVelocity = ((_position - transform.position) / Time.deltaTime).magnitude; // Debug.Log(_controllerVelocity); float clampedVelocity = Mathf.Clamp(SprintSpeed / _controllerVelocity + 1, 1, SprintSpeed); if (Time.time > _stepCycle && Grounded && _controllerVelocity > 0.1) { CallFootstepClip(); _stepCycle = Time.time + (clampedVelocity * _stepTiming); } _position = transform.position; } public void CallFootstepClip() { audioSource.pitch = 1f + Random.Range(-0.1f, 0.1f); audioSource.PlayOneShot(footStepClip); } } }