254 lines
8.5 KiB
C#
254 lines
8.5 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using Management;
|
|
using UnityEngine;
|
|
using UnityEngine.InputSystem;
|
|
|
|
namespace Player
|
|
{
|
|
[RequireComponent(typeof(Rigidbody2D))]
|
|
public class Movement : MonoBehaviour
|
|
{
|
|
public event Action OnDeath;
|
|
|
|
private static readonly int Spring = Animator.StringToHash("spring");
|
|
private static readonly int Grounded = Animator.StringToHash("grounded");
|
|
private static readonly int Speed = Animator.StringToHash("speed");
|
|
private static readonly int Vspeed = Animator.StringToHash("vspeed");
|
|
[SerializeField] private float runSpeed;
|
|
[SerializeField] private float springPower;
|
|
[SerializeField] private float jumpForce;
|
|
[SerializeField] private float airJumpForce;
|
|
[SerializeField] private SpriteRenderer spriteRenderer;
|
|
[SerializeField] private float turnDelay;
|
|
[SerializeField] private float impactPauseTime;
|
|
[SerializeField] private float bouncePower;
|
|
[SerializeField] private Animator animator;
|
|
[SerializeField] private GameObject deathScreenPrefab;
|
|
|
|
[Header("Audio")]
|
|
[SerializeField] private AudioClip jumpSound;
|
|
[SerializeField] private AudioClip airJumpSound;
|
|
[SerializeField] private AudioClip pickupSound;
|
|
[SerializeField] private AudioClip springSound;
|
|
[SerializeField] private AudioClip bumpSound;
|
|
|
|
[Header("Wind Sound")]
|
|
[SerializeField] private AudioSource windSound;
|
|
[SerializeField] private float maxSpeedWindSound;
|
|
|
|
private Animator _springAnimator;
|
|
private Rigidbody2D _rb;
|
|
private bool _grounded = true;
|
|
private bool _facingLeft;
|
|
private float _turnDelayTimer;
|
|
private float _groundedCheckTimer;
|
|
private bool _interact;
|
|
private int _airJumpCharges;
|
|
private bool _jumpPressedThisFrame;
|
|
private bool _fireSpring;
|
|
private bool _jump;
|
|
private bool _airJump;
|
|
private Vector2 _airJumpDir;
|
|
private bool _autoDrive = true;
|
|
private bool _deathArmed;
|
|
|
|
private void Awake()
|
|
{
|
|
_rb = GetComponent<Rigidbody2D>();
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
Cursor.lockState = CursorLockMode.None;
|
|
Cursor.visible = true;
|
|
Services.Instance.InputRouter.OnInteract += HandleInteraction;
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
Services.Instance.InputRouter.OnInteract -= HandleInteraction;
|
|
}
|
|
|
|
private void HandleInteraction(bool pressed)
|
|
{
|
|
_interact = pressed;
|
|
_jumpPressedThisFrame = _interact;
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
Vector2 mouseScreenPos = Mouse.current.position.ReadValue();
|
|
|
|
Vector3 mouseWorldPos = Camera.main.ScreenToWorldPoint(
|
|
new Vector3(mouseScreenPos.x, mouseScreenPos.y, -Camera.main.transform.position.z)
|
|
);
|
|
|
|
_airJumpDir = ((Vector2)mouseWorldPos - (Vector2)transform.position).normalized;
|
|
|
|
_groundedCheckTimer += Time.deltaTime;
|
|
_turnDelayTimer += Time.deltaTime;
|
|
if (!_autoDrive && Mathf.Abs(_rb.linearVelocityX) > 0.1f)
|
|
_facingLeft = _rb.linearVelocity.x < 0;
|
|
spriteRenderer.flipX = !_facingLeft;
|
|
if (_springAnimator && _jumpPressedThisFrame)
|
|
{
|
|
_groundedCheckTimer = 0f;
|
|
_springAnimator.SetTrigger(Spring);
|
|
_springAnimator = null;
|
|
_grounded = false;
|
|
_fireSpring = true;
|
|
_autoDrive = false;
|
|
}
|
|
|
|
if (_grounded && _jumpPressedThisFrame)
|
|
{
|
|
_grounded = false;
|
|
_groundedCheckTimer = 0f;
|
|
_jump = true;
|
|
_jumpPressedThisFrame = false;
|
|
}
|
|
|
|
if (!_grounded && _airJumpCharges > 0 && _jumpPressedThisFrame)
|
|
{
|
|
_airJump = true;
|
|
}
|
|
|
|
windSound.volume = Mathf.Lerp(0, 1, Mathf.Abs(_rb.linearVelocityY / maxSpeedWindSound));
|
|
_jumpPressedThisFrame = false;
|
|
}
|
|
|
|
private void FixedUpdate()
|
|
{
|
|
if (_jump)
|
|
{
|
|
Services.Instance.SFX.PlayOneShot(jumpSound);
|
|
_jump = false;
|
|
_grounded = false;
|
|
_rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
|
|
}
|
|
|
|
if (_airJump)
|
|
{
|
|
Services.Instance.SFX.PlayOneShot(airJumpSound);
|
|
StartCoroutine(ImpactPause(impactPauseTime));
|
|
_airJump = false;
|
|
_airJumpCharges--;
|
|
_rb.linearVelocity = Vector3.zero;
|
|
_rb.AddForce(_airJumpDir * airJumpForce, ForceMode2D.Impulse);
|
|
}
|
|
|
|
if (_fireSpring)
|
|
{
|
|
Services.Instance.SFX.PlayOneShot(springSound);
|
|
Services.Instance.BGM.FadeIn(BGM.TrackType.Core);
|
|
_fireSpring = false;
|
|
_rb.linearVelocity = Vector2.zero;
|
|
_rb.AddForce(Vector2.up * springPower, ForceMode2D.Impulse);
|
|
}
|
|
if (_autoDrive)
|
|
{
|
|
_rb.linearVelocityX = _facingLeft ? -runSpeed : runSpeed;
|
|
}
|
|
|
|
animator.SetBool(Grounded, _grounded);
|
|
animator.SetFloat(Speed, Mathf.Abs(_rb.linearVelocity.x));
|
|
animator.SetFloat(Vspeed, _rb.linearVelocity.y);
|
|
}
|
|
|
|
private IEnumerator ImpactPause(float pauseTime)
|
|
{
|
|
Time.timeScale = 0f;
|
|
yield return new WaitForSecondsRealtime(pauseTime);
|
|
Time.timeScale = 1f;
|
|
}
|
|
|
|
private void OnTriggerEnter2D(Collider2D other)
|
|
{
|
|
if (_deathArmed && other.gameObject.layer == LayerMask.NameToLayer("DeathBox"))
|
|
{
|
|
HandleDeath();
|
|
return;
|
|
}
|
|
|
|
if (other.gameObject.layer == LayerMask.NameToLayer("Spring"))
|
|
_springAnimator = other.gameObject.GetComponent<Animator>();
|
|
if (other.gameObject.layer == LayerMask.NameToLayer("Pickup"))
|
|
{
|
|
Services.Instance.SFX.PlayOneShot(pickupSound);
|
|
_airJumpCharges++;
|
|
Destroy(other.gameObject);
|
|
}
|
|
}
|
|
|
|
private void HandleDeath()
|
|
{
|
|
OnDeath?.Invoke();
|
|
}
|
|
|
|
private void OnTriggerExit2D(Collider2D other)
|
|
{
|
|
if (other.gameObject.layer == LayerMask.NameToLayer("DeathBox"))
|
|
{
|
|
_deathArmed = true;
|
|
return;
|
|
}
|
|
|
|
if (other.gameObject.layer == LayerMask.NameToLayer("Spring"))
|
|
{
|
|
_springAnimator = null;
|
|
}
|
|
}
|
|
|
|
private void OnCollisionEnter2D(Collision2D other)
|
|
{
|
|
CheckCollisions(other);
|
|
}
|
|
|
|
private void OnCollisionStay2D(Collision2D other)
|
|
{
|
|
CheckCollisions(other);
|
|
}
|
|
|
|
private void CheckCollisions(Collision2D other)
|
|
{
|
|
var contacts = new List<ContactPoint2D>();
|
|
other.GetContacts(contacts);
|
|
if (_turnDelayTimer >= turnDelay &&
|
|
other.gameObject.layer != LayerMask.NameToLayer("Spring") &&
|
|
other.gameObject.layer != LayerMask.NameToLayer("Pickup"))
|
|
{
|
|
foreach (var c in contacts)
|
|
{
|
|
var x = c.normal.x;
|
|
if (Mathf.Abs(x) > 0.1f)
|
|
{
|
|
_facingLeft = !_facingLeft;
|
|
_turnDelayTimer = 0f;
|
|
if (!_autoDrive)
|
|
_rb.AddForce(new Vector2(x, 0f) * bouncePower, ForceMode2D.Impulse);
|
|
Services.Instance.SFX.PlayOneShot(bumpSound);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
_grounded = false;
|
|
if (_groundedCheckTimer > turnDelay)
|
|
{
|
|
foreach (var c in contacts)
|
|
{
|
|
var y = c.normal.y;
|
|
_grounded = Mathf.Approximately(1f, y);
|
|
if (_grounded)
|
|
{
|
|
_autoDrive = true;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|