using RR.Game2D.Core; using UnityEngine; using UnityEngine.InputSystem; namespace RR.Game2D.Behaviour { [DisallowMultipleComponent] [RequireComponent(typeof(Rigidbody2D), typeof(Collider2D), typeof(Animator))] public class PlayerController : MonoBehaviour { [Header("Управление")] [SerializeField] private InputActionReference moveAction; // Value(Vector2), например "Move" (A/D, ←/→, stick) [SerializeField] private InputActionReference jumpAction; [Header("Горизонтальное движение")] [SerializeField] private float moveSpeed = 8f; [SerializeField] private float accel = 40f; [SerializeField] private float decel = 20f; [Header("Вертикальное движение")] [SerializeField] public float jumpVelocity = 50f; [SerializeField] private float jumpCut = 2f; [Header("Проверка призмеления")] [SerializeField] private Transform groundCheck; [SerializeField] private float groundCheckRadius = 0.05f; [SerializeField] private LayerMask groundMask; [Header("Аниматор [Опционально]")] [SerializeField] private Animator animator; // оставить в инспекторе на всякий случай [Header("Настройки для уровней")] [SerializeField] private float deathY = -5f; private Rigidbody2D rb; //private Collider2D col; private float inputX; private bool jumpPressed, jumpReleased, jumpHold; private float _fallSpeedYDampingChangeThreshold; private bool IsGrounded => Grounded(); void OnEnable() { moveAction.action.Enable(); jumpAction.action.Enable(); } void OnDisable() { moveAction.action.Disable(); jumpAction.action.Disable(); } void Awake() { rb = GetComponent(); //col = GetComponent(); rb.freezeRotation = true; _fallSpeedYDampingChangeThreshold = CameraManager.instance._fallSpeedYDampingChangeThreshold; // если не задано в инспекторе — находим автоматически if (animator == null) animator = GetComponent(); if (animator == null) animator = GetComponentInChildren(true); if (animator == null) Debug.LogError($"[{name}] Animator не найден!"); } void Update() { // --- Ввод --- Vector2 move = moveAction ? moveAction.action.ReadValue() : Vector2.zero; inputX = Mathf.Abs(move.x) > 0.01f ? Mathf.Sign(move.x) : 0f; jumpPressed |= jumpAction.action.WasPressedThisFrame(); jumpReleased |= jumpAction.action.WasReleasedThisFrame(); jumpHold |= jumpAction.action.IsPressed(); if (inputX != 0f) transform.localEulerAngles = Mathf.Sign(inputX) > 0 ? Vector3.zero : new Vector3(0, 180f, 0); if (rb.linearVelocity.y < _fallSpeedYDampingChangeThreshold && !CameraManager.instance.IsLerpingYDamping && !CameraManager.instance.LerpedFromPlayerFalling) { CameraManager.instance.LerpYDamping(true); } if (rb.linearVelocity.y >= 0 && !CameraManager.instance.IsLerpingYDamping && CameraManager.instance.LerpedFromPlayerFalling) { CameraManager.instance.LerpedFromPlayerFalling = false; CameraManager.instance.LerpYDamping(false); } // --- Анимации --- animator.SetFloat("Speed", Mathf.Abs(rb.linearVelocity.x)); animator.SetFloat("VSpeed", rb.linearVelocity.y); animator.SetBool("Grounded", IsGrounded); } private void FixedUpdate() { // Горизонтальное движение float target = inputX * moveSpeed; float rate = (Mathf.Abs(target) > 0.01) ? accel : decel; float velocityX = Mathf.MoveTowards(rb.linearVelocity.x, target, rate * Time.fixedDeltaTime); Vector2 newVelocity = rb.linearVelocity; newVelocity.x = velocityX; // Вертикальное движение if ((jumpPressed || jumpHold)&& IsGrounded) newVelocity.y = jumpVelocity; if (jumpReleased && newVelocity.y > 0) newVelocity.y /= Mathf.Max(1f, jumpCut); rb.linearVelocity = newVelocity; jumpPressed = jumpReleased = jumpHold = false; // Смерть if (transform.position.y < deathY) Die(); } private void OnTriggerEnter2D(Collider2D collision) { if (collision.CompareTag("Coin")) { GameManager.Instance.AddCoin(); Destroy(collision.gameObject); } if (collision.CompareTag("Finish")) { GameManager.Instance.NextLevel(); } } //private void OnDestroy() => Debug.Log("Player destroyed"); /// /// Метод для проверки соприкосновения с землей /// /// bool isGrounded - на земле ли игрок bool Grounded() { Collider2D hit = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, groundMask); bool isGrounded = hit != null && hit.CompareTag("Ground"); //&& rb.linearVelocity.y < 0.01f; animator.SetBool("Jump", !isGrounded); return isGrounded; } /// /// Метод смерти персонажа. /// Базовое поведение - сброс уровня в GameManager /// public void Die() { GameManager.Instance.ResetLevel(); } } }