177 lines
6.4 KiB
C#
177 lines
6.4 KiB
C#
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; // оставить в инспекторе на всякий случай
|
||
|
||
private Rigidbody2D rb;
|
||
//private Collider2D col;
|
||
|
||
private float inputX;
|
||
private bool jumpPressed, jumpReleased, jumpHold;
|
||
|
||
private float _fallSpeedYDampingChangeThreshold;
|
||
|
||
private bool IsGrounded => Grounded();
|
||
|
||
// Аниматор
|
||
private static readonly int Jump = Animator.StringToHash("Jump");
|
||
private static readonly int Speed = Animator.StringToHash("Speed");
|
||
private static readonly int VSpeed = Animator.StringToHash("VSpeed");
|
||
private static readonly int GroundedAnimator = Animator.StringToHash("Grounded");
|
||
|
||
void OnEnable()
|
||
{
|
||
moveAction.action.Enable();
|
||
jumpAction.action.Enable();
|
||
}
|
||
|
||
void OnDisable()
|
||
{
|
||
moveAction.action.Disable();
|
||
jumpAction.action.Disable();
|
||
}
|
||
|
||
void Awake()
|
||
{
|
||
rb = GetComponent<Rigidbody2D>();
|
||
//col = GetComponent<Collider2D>();
|
||
rb.freezeRotation = true;
|
||
|
||
_fallSpeedYDampingChangeThreshold = CameraManager.instance._fallSpeedYDampingChangeThreshold;
|
||
|
||
// если не задано в инспекторе — находим автоматически
|
||
if (animator == null)
|
||
animator = GetComponent<Animator>();
|
||
if (animator == null)
|
||
animator = GetComponentInChildren<Animator>(true);
|
||
|
||
if (animator == null)
|
||
Debug.LogError($"[{name}] Animator не найден!");
|
||
}
|
||
|
||
void Update()
|
||
{
|
||
// --- Ввод ---
|
||
Vector2 move = moveAction ? moveAction.action.ReadValue<Vector2>() : 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(GroundedAnimator, 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");
|
||
|
||
/// <summary>
|
||
/// Метод для проверки соприкосновения с землей
|
||
/// </summary>
|
||
/// <returns>bool isGrounded - на земле ли игрок</returns>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Метод смерти персонажа.
|
||
/// Базовое поведение - сброс уровня в GameManager
|
||
/// </summary>
|
||
public void Die()
|
||
{
|
||
GameManager.Instance.ResetLevel();
|
||
}
|
||
}
|
||
} |