Danro/Assets/Scripts/Behaviour/Controllers/PlayerController.cs

204 lines
7.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using UnityEngine;
using UnityEngine.InputSystem;
using RR.Common.Interfaces;
using RR.Game2D.Core.Managers;
namespace RR.Game2D.Behaviour
{
[DisallowMultipleComponent]
[RequireComponent(typeof(Rigidbody2D),
typeof(Collider2D),
typeof(Animator))]
public class PlayerController : MonoBehaviour, IDamageable
{
[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;
public bool IsGrounded => Grounded();
[Header("Проверка призмеления")]
[SerializeField] private Transform groundCheck;
[SerializeField] private float groundCheckRadius = 0.05f;
[SerializeField] private LayerMask groundMask;
[Header("Аниматор [Опционально]")]
[SerializeField] private Animator animator; // оставить в инспекторе на всякий случай
[Header("Здоровье")]
[SerializeField] private int maxHealth = 3;
private Health health;
public float CurrentHealth => health?.CurrentHealth ?? 0;
public float MaxHealth => health?.MaxHealth ?? 0;
private Rigidbody2D rb;
// private Collider2D col;
private float inputX;
private bool jumpPressed, jumpReleased, jumpHold;
private float _fallSpeedYDampingChangeThreshold;
// Аниматор
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");
private static readonly int Death = Animator.StringToHash("Death");
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 не найден!");
health = GetComponent<Health>();
if (health == null)
{
health = gameObject.AddComponent<Health>();
}
health.ResetHealth();
health.SetOwner(this);
health.SetMaxHealth(maxHealth);
}
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();
}
if (collision.CompareTag("Enemy"))
{
TakeDamage(1f);
}
}
public void TakeDamage(float amount)
{
health.TakeDamage(amount);
}
public void Heal(float amount)
{
health.Heal(amount);
}
public void Die()
{
gameObject.layer = LayerMask.NameToLayer("No Collision");
rb.constraints = RigidbodyConstraints2D.FreezeAll;
animator.SetTrigger(Death);
}
/// <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;
}
}
}