using System; using Code.UI; using UnityEngine; namespace Code.Gameplay.Player { public class PlayerController : MonoBehaviour { [SerializeField] private float forwardSpeed = 10f; [SerializeField] private float maxSpeed = 40f; [SerializeField] private float laneDistance = 5f; [SerializeField] private float jumpForce = 11f; [SerializeField] private float gravity = 20f; [SerializeField] private Animator animator; [SerializeField] private RuntimeAnimatorController runController; [SerializeField] private RuntimeAnimatorController jumpController; private int _targetLane = 1; private CharacterController _controller; private Vector3 _direction; public Action OnPlayerDeath; private bool _isDead; private bool _isDoubleCoins; private float _bonusTimer; private void Start() { _controller = GetComponent(); } private void Update() { if (_isDead) return; if (Input.GetKeyDown(KeyCode.RightArrow) || Input.GetKeyDown(KeyCode.D)) { _targetLane = Mathf.Min(_targetLane + 1, 2); } else if (Input.GetKeyDown(KeyCode.LeftArrow) || Input.GetKeyDown(KeyCode.A)) { _targetLane = Mathf.Max(_targetLane - 1, 0); } var targetPosition = transform.position.z * transform.forward + transform.position.y * transform.up; switch (_targetLane) { case 0: targetPosition += Vector3.left * laneDistance; break; case 2: targetPosition += Vector3.right * laneDistance; break; } if (_controller.isGrounded) { _direction.y = -1f; if (Input.GetKeyDown(KeyCode.Space)) { animator.runtimeAnimatorController = jumpController; _direction.y = jumpForce; } else { animator.runtimeAnimatorController = runController; } } else { _direction.y -= gravity * Time.deltaTime; } _direction.z = forwardSpeed; var diff = targetPosition - transform.position; var moveDir = diff.normalized * (25f * Time.deltaTime); var moveX = Mathf.Clamp(diff.x, -moveDir.magnitude, moveDir.magnitude); var finalMove = new Vector3(moveX, _direction.y * Time.deltaTime, _direction.z * Time.deltaTime); _controller.Move(finalMove); CheckForDeath(); HandleBonusTimer(); } public void IncreaseSpeed(float amount) { if (forwardSpeed < maxSpeed) { var desirableSpeed = forwardSpeed + amount; forwardSpeed = Mathf.Min(desirableSpeed, maxSpeed); } } private void OnTriggerEnter(Collider foreign) { if (foreign.CompareTag("Obstacle")) { Die(); } if (foreign.CompareTag("Coin")) { var amount = _isDoubleCoins ? 2 : 1; for(var i = 0; i < amount; i++) GameplayController.Instance.AddCoin(); Destroy(foreign.gameObject); } if (foreign.CompareTag("BonusX2")) { ActivateDoubleCoins(10f); Destroy(foreign.gameObject); } } private void ActivateDoubleCoins(float duration) { _isDoubleCoins = true; _bonusTimer = duration; } private void HandleBonusTimer() { if (_bonusTimer > 0) { _bonusTimer -= Time.deltaTime; if (_bonusTimer <= 0) { _isDoubleCoins = false; } } } private void CheckForDeath() { if (_isDead) return; if (Time.timeSinceLevelLoad > 1f && _controller.velocity.z <= 0.1f) { Die(); } } private void Die() { _isDead = true; forwardSpeed = 0; _direction = Vector3.zero; OnPlayerDeath?.Invoke(); } } }