Danro/Assets/Resources/Scripts/PlayerController.cs

155 lines
5.3 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 RR.Game2D.Core;
namespace RR.Game2D.Behaviour
{
[DisallowMultipleComponent]
[RequireComponent(typeof(Rigidbody2D),
typeof(Collider2D),
typeof(Animator))]
public class PlayerController : MonoBehaviour
{
[Header("Горизонтальное движение")]
[SerializeField] private float moveSpeed = 8f;
[SerializeField] private float accel = 40f;
[SerializeField] private float decel = 20f;
[Header("Вертикальное движение")]
[SerializeField] private float maxJumpHeight = 5f;
[SerializeField] private float jumpCooldown = 0.1f;
[SerializeField] private float jumpBuffer = 0.1f;
[SerializeField, Range(0f, 1f)] private float jumpCut = 0.5f;
private float spriteScale = 0.35f;
private Rigidbody2D rb;
private Collider2D col;
float inputX;
float lastGroundedTime;
float lastJumpPressedTime;
bool IsGrounded => Grounded();
[Header("Аниматор [Опционально]")]
[SerializeField] private Animator animator; // оставить в инспекторе на всякий случай
void Awake()
{
rb = GetComponent<Rigidbody2D>();
col = GetComponent<Collider2D>();
rb.freezeRotation = true;
lastJumpPressedTime = -999f;
// если не задано в инспекторе — находим автоматически
if (animator == null)
animator = GetComponent<Animator>();
if (animator == null)
animator = GetComponentInChildren<Animator>(true);
if (animator == null)
Debug.LogError($"[{name}] Animator не найден!");
}
void Update()
{
// Передвижение
inputX = Input.GetAxisRaw("Horizontal");
if (Input.GetButtonDown("Jump"))
lastJumpPressedTime = Time.time;
if (Input.GetButtonUp("Jump")) // && rb.linearVelocity.y > 0f)
rb.linearVelocity = new Vector2(rb.linearVelocity.x, rb.linearVelocity.y * jumpCut);
if (inputX != 0f)
transform.localScale = new Vector3(Mathf.Sign(inputX) * spriteScale, spriteScale, spriteScale);
if (IsGrounded) lastGroundedTime = Time.time;
// Данные для анимаций
animator.SetFloat("Speed", Mathf.Abs(rb.linearVelocity.x));
animator.SetFloat("VSpeed", rb.linearVelocity.y);
animator.SetBool("Grounded", IsGrounded);
}
void FixedUpdate()
{
float target = inputX * moveSpeed;
float rate = (Mathf.Abs(target) > 0.01f) ? accel : decel;
float vx = Mathf.MoveTowards(rb.linearVelocity.x, target, rate * Time.fixedDeltaTime);
if (transform.position.y < -5) Die();
// Возможность прыжка
bool canJump = (Time.time - lastGroundedTime) <= jumpCooldown;
bool wantJump = (Time.time - lastJumpPressedTime) <= jumpBuffer;
if (wantJump && canJump && IsGrounded)
{
float vy = CalcJumpSpeed(maxJumpHeight);
rb.linearVelocity = new Vector2(vx, vy);
animator.SetBool("Jump", true);
lastJumpPressedTime = -999f;
return;
}
rb.linearVelocity = new Vector2(vx, rb.linearVelocity.y);
}
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>
/// <param name="height">Высота прыжка (высшая точка по y)</param>
/// <returns>float jumpSpeed - высчитанная скорость прыжка</returns>
float CalcJumpSpeed(float height)
{
float g = Physics2D.gravity.y * rb.gravityScale;
return Mathf.Sqrt(-2f * g * height);
}
/// <summary>
/// Метод для проверки соприкосновения с землей
/// </summary>
/// <returns>bool isGrounded - на земле ли игрок</returns>
bool Grounded()
{
RaycastHit2D hit = Physics2D.CircleCast(new Vector2(col.bounds.center.x, col.bounds.min.y), 0.01f, Vector2.down, 0.1f);
bool isGrounded = hit.collider != null;
animator.SetBool("Jump", !isGrounded);
return isGrounded;
}
/// <summary>
/// Метод смерти персонажа.
/// Базовое поведение - сброс уровня в GameManager
/// </summary>
public void Die()
{
GameManager.Instance.ResetLevel();
}
}
}