2026-02-02 05:24:20 +00:00
|
|
|
using System.Numerics;
|
2026-01-30 06:16:16 +00:00
|
|
|
using UnityEngine;
|
|
|
|
|
using UnityEngine.InputSystem;
|
2026-02-02 12:33:32 +00:00
|
|
|
using UnityEngine.SceneManagement;
|
2026-02-02 05:24:20 +00:00
|
|
|
using Quaternion = UnityEngine.Quaternion;
|
|
|
|
|
using Vector2 = UnityEngine.Vector2;
|
2026-01-30 06:16:16 +00:00
|
|
|
|
|
|
|
|
public class PlayerMovement : MonoBehaviour
|
|
|
|
|
{
|
|
|
|
|
private Rigidbody2D _rigidbody2D;
|
2026-01-30 07:02:37 +00:00
|
|
|
private Collider2D _collider2D;
|
2026-02-02 11:13:47 +00:00
|
|
|
private Animator _animator;
|
2026-01-30 06:16:16 +00:00
|
|
|
|
2026-02-02 05:24:20 +00:00
|
|
|
[Header("속도 설정")]
|
2026-01-30 06:16:16 +00:00
|
|
|
[SerializeField] private float moveSpeed = 5f;
|
|
|
|
|
[SerializeField] private float jumpForce = 10f;
|
2026-02-02 05:24:20 +00:00
|
|
|
[SerializeField] private float poleForce = 3f;
|
2026-01-30 06:16:16 +00:00
|
|
|
|
2026-02-02 05:24:20 +00:00
|
|
|
[Header("감지 설정")]
|
2026-02-12 12:17:38 +00:00
|
|
|
[SerializeField] private Vector2 groundCheckSize = new Vector2(0.5f, 0.2f);
|
|
|
|
|
[SerializeField] private Vector2 groundCheckOffset = new Vector2(0f, -0.6f);
|
|
|
|
|
|
|
|
|
|
[SerializeField] private Vector2 hangCheckSize = new Vector2(0.3f, 0.5f);
|
|
|
|
|
[SerializeField] private Vector2 hangCheckOffset = new Vector2(0.4f, 0.5f);
|
|
|
|
|
|
2026-01-30 06:16:16 +00:00
|
|
|
[SerializeField] private LayerMask groundLayer;
|
2026-02-02 11:13:47 +00:00
|
|
|
[SerializeField] private LayerMask hangingWallLayer;
|
2026-02-02 05:24:20 +00:00
|
|
|
|
2026-02-03 05:59:13 +00:00
|
|
|
[SerializeField] private Collider2D hangingWallCollider;
|
|
|
|
|
[SerializeField] private Rigidbody2D hangingWallRigidBody;
|
2026-02-06 08:21:16 +00:00
|
|
|
|
2026-02-10 08:18:34 +00:00
|
|
|
// [Header("사운드 설정")]
|
|
|
|
|
// [SerializeField] private float footstepRate = 0.3f;
|
2026-02-06 08:21:16 +00:00
|
|
|
|
2026-01-30 06:16:16 +00:00
|
|
|
private Vector2 inputVector;
|
2026-01-30 07:02:37 +00:00
|
|
|
private bool isHanging = false;
|
2026-02-06 08:21:16 +00:00
|
|
|
private float footstepTimer;
|
2026-02-10 08:18:34 +00:00
|
|
|
// private bool isDead = false;
|
2026-02-07 14:41:29 +00:00
|
|
|
private bool isPlayer;
|
2026-02-10 08:18:34 +00:00
|
|
|
// private bool isStageClear = false;
|
2026-02-07 14:41:29 +00:00
|
|
|
|
2026-01-30 06:16:16 +00:00
|
|
|
private void Awake()
|
|
|
|
|
{
|
2026-01-30 07:02:37 +00:00
|
|
|
_rigidbody2D = GetComponent<Rigidbody2D>();
|
2026-01-30 10:53:09 +00:00
|
|
|
_collider2D = GetComponent<BoxCollider2D>();
|
2026-02-02 11:13:47 +00:00
|
|
|
_animator = GetComponent<Animator>();
|
2026-02-12 12:17:38 +00:00
|
|
|
isPlayer = gameObject.CompareTag("Player");
|
2026-01-30 06:16:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void FixedUpdate()
|
|
|
|
|
{
|
2026-02-10 08:18:34 +00:00
|
|
|
// Playing 이 아닐때 ( Clear 또는 Die ) 못 움직이게 하기
|
|
|
|
|
if (GameManager.instance.gameState != GameState.Playing)
|
2026-02-04 11:43:12 +00:00
|
|
|
{
|
|
|
|
|
_rigidbody2D.linearVelocity = new Vector2(0, _rigidbody2D.linearVelocity.y);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-12 12:17:38 +00:00
|
|
|
bool isGrounded = IsGrounded();
|
|
|
|
|
|
2026-02-07 09:33:35 +00:00
|
|
|
float yVel = _rigidbody2D.linearVelocity.y;
|
|
|
|
|
|
2026-02-12 12:17:38 +00:00
|
|
|
_animator.SetBool("isRun", inputVector.x != 0 && isGrounded);
|
|
|
|
|
_animator.SetBool("isGround", isGrounded);
|
2026-02-07 09:33:35 +00:00
|
|
|
_animator.SetFloat("yVelocity", yVel);
|
2026-02-22 06:56:21 +00:00
|
|
|
|
|
|
|
|
if (isPlayer)
|
|
|
|
|
{
|
|
|
|
|
if (inputVector.x != 0 && isGrounded)
|
|
|
|
|
{
|
|
|
|
|
SoundManager.instance.PlaySFX(SfxType.Walk);
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-02-10 08:18:34 +00:00
|
|
|
|
|
|
|
|
// 메달릴때 이동
|
2026-01-30 07:02:37 +00:00
|
|
|
if (isHanging)
|
|
|
|
|
{
|
2026-02-02 05:24:20 +00:00
|
|
|
if (inputVector.x != 0)
|
|
|
|
|
{
|
|
|
|
|
hangingWallRigidBody.AddForce(Vector2.right * inputVector.x * poleForce);
|
|
|
|
|
}
|
2026-01-30 07:02:37 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2026-02-01 11:12:05 +00:00
|
|
|
|
2026-01-30 07:02:37 +00:00
|
|
|
HandleRotation();
|
2026-02-10 08:18:34 +00:00
|
|
|
|
2026-02-12 12:17:38 +00:00
|
|
|
// 이동 로직
|
2026-01-30 06:16:16 +00:00
|
|
|
_rigidbody2D.linearVelocity = new Vector2(inputVector.x * moveSpeed, _rigidbody2D.linearVelocity.y);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-01 11:12:05 +00:00
|
|
|
public void SetMoveInput(Vector2 input)
|
2026-01-30 06:16:16 +00:00
|
|
|
{
|
2026-02-01 11:12:05 +00:00
|
|
|
inputVector = input;
|
2026-01-30 06:16:16 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-01 11:12:05 +00:00
|
|
|
public void TryJump()
|
2026-01-30 06:16:16 +00:00
|
|
|
{
|
2026-02-10 08:18:34 +00:00
|
|
|
if (GameManager.instance.gameState != GameState.Playing)
|
2026-02-04 11:43:12 +00:00
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-10 08:18:34 +00:00
|
|
|
// 매달린 상태에선 취소하기
|
2026-02-01 11:12:05 +00:00
|
|
|
if (isHanging)
|
|
|
|
|
{
|
|
|
|
|
CancelHanging();
|
2026-02-10 08:18:34 +00:00
|
|
|
// 플레이어면 점프 소리
|
2026-02-22 06:56:21 +00:00
|
|
|
if (isPlayer)
|
|
|
|
|
{
|
|
|
|
|
SoundManager.instance.PlaySFX(SfxType.Jump);
|
|
|
|
|
}
|
2026-02-01 11:12:05 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-10 08:18:34 +00:00
|
|
|
// 땅이라면 점프하기
|
2026-02-01 11:12:05 +00:00
|
|
|
else if (IsGrounded())
|
2026-01-30 06:16:16 +00:00
|
|
|
{
|
2026-02-10 08:18:34 +00:00
|
|
|
// 플레이어면 점프 사운드
|
|
|
|
|
|
2026-02-22 06:56:21 +00:00
|
|
|
if (isPlayer)
|
|
|
|
|
{
|
|
|
|
|
SoundManager.instance.PlaySFX(SfxType.Jump);
|
|
|
|
|
}
|
2026-02-01 11:12:05 +00:00
|
|
|
_rigidbody2D.linearVelocity = new Vector2(_rigidbody2D.linearVelocity.x, jumpForce);
|
2026-01-30 06:16:16 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-01 11:12:05 +00:00
|
|
|
public void TryHang()
|
2026-01-30 07:02:37 +00:00
|
|
|
{
|
2026-02-10 08:18:34 +00:00
|
|
|
if (GameManager.instance.gameState != GameState.Playing)
|
2026-02-04 11:43:12 +00:00
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
2026-02-10 08:18:34 +00:00
|
|
|
|
2026-02-01 11:12:05 +00:00
|
|
|
if (isHanging)
|
|
|
|
|
{
|
|
|
|
|
CancelHanging();
|
|
|
|
|
}
|
2026-02-02 06:18:23 +00:00
|
|
|
else
|
2026-01-30 07:02:37 +00:00
|
|
|
{
|
2026-02-12 12:17:38 +00:00
|
|
|
Vector2 checkPos = transform.TransformPoint(hangCheckOffset);
|
|
|
|
|
|
|
|
|
|
Collider2D hit = Physics2D.OverlapBox(checkPos, hangCheckSize, 0, hangingWallLayer);
|
2026-02-02 06:18:23 +00:00
|
|
|
if (hit != null)
|
|
|
|
|
{
|
|
|
|
|
HangingObject();
|
|
|
|
|
}
|
2026-01-30 07:02:37 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void CancelHanging()
|
|
|
|
|
{
|
|
|
|
|
isHanging = false;
|
|
|
|
|
_rigidbody2D.bodyType = RigidbodyType2D.Dynamic;
|
2026-02-02 05:24:20 +00:00
|
|
|
if (hangingWallCollider != null)
|
|
|
|
|
{
|
|
|
|
|
Physics2D.IgnoreCollision(_collider2D, hangingWallCollider, false);
|
|
|
|
|
hangingWallCollider = null;
|
|
|
|
|
}
|
2026-02-02 02:31:20 +00:00
|
|
|
transform.SetParent(null, true);
|
2026-02-12 12:17:38 +00:00
|
|
|
if (hangingWallRigidBody != null)
|
|
|
|
|
{
|
|
|
|
|
_rigidbody2D.linearVelocity = hangingWallRigidBody.linearVelocity * 4;
|
|
|
|
|
hangingWallRigidBody = null;
|
|
|
|
|
}
|
2026-01-30 07:02:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HangingObject()
|
|
|
|
|
{
|
2026-02-03 05:59:13 +00:00
|
|
|
float direction = transform.rotation.eulerAngles.y == 180 ? -1f : 1f;
|
|
|
|
|
RaycastHit2D hit = Physics2D.Raycast(transform.position, Vector2.right * direction, 1f, hangingWallLayer);
|
|
|
|
|
|
|
|
|
|
if (hit.collider != null)
|
|
|
|
|
{
|
|
|
|
|
isHanging = true;
|
|
|
|
|
_rigidbody2D.linearVelocity = Vector2.zero;
|
|
|
|
|
_rigidbody2D.bodyType = RigidbodyType2D.Kinematic;
|
|
|
|
|
|
|
|
|
|
hangingWallCollider = hit.collider;
|
|
|
|
|
hangingWallRigidBody = hit.collider.attachedRigidbody;
|
|
|
|
|
Physics2D.IgnoreCollision(_collider2D, hangingWallCollider, true);
|
|
|
|
|
|
|
|
|
|
transform.position = new Vector2(hit.point.x, transform.position.y);
|
|
|
|
|
|
|
|
|
|
gameObject.transform.SetParent(hit.transform, true);
|
|
|
|
|
transform.localRotation = Quaternion.identity;
|
|
|
|
|
}
|
2026-01-30 07:02:37 +00:00
|
|
|
}
|
|
|
|
|
|
2026-01-30 06:16:16 +00:00
|
|
|
private bool IsGrounded()
|
|
|
|
|
{
|
2026-02-12 12:17:38 +00:00
|
|
|
Vector2 checkPos = (Vector2)transform.position + groundCheckOffset;
|
|
|
|
|
return Physics2D.OverlapBox(checkPos, groundCheckSize, 0f, groundLayer);
|
2026-01-30 07:02:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void HandleRotation()
|
|
|
|
|
{
|
|
|
|
|
if (inputVector.x > 0)
|
|
|
|
|
{
|
|
|
|
|
transform.rotation = Quaternion.Euler(0, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
else if (inputVector.x < 0)
|
|
|
|
|
{
|
|
|
|
|
transform.rotation = Quaternion.Euler(0, 180, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-02-12 12:17:38 +00:00
|
|
|
private void OnDrawGizmosSelected()
|
|
|
|
|
{
|
|
|
|
|
Gizmos.color = Color.green;
|
|
|
|
|
Gizmos.DrawWireCube((Vector2)transform.position + groundCheckOffset, groundCheckSize);
|
|
|
|
|
Gizmos.color = Color.cyan;
|
|
|
|
|
Vector2 hangPos = transform.TransformPoint(hangCheckOffset);
|
|
|
|
|
Gizmos.DrawWireCube(hangPos, hangCheckSize);
|
|
|
|
|
}
|
2026-01-30 07:02:37 +00:00
|
|
|
}
|