using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
// [Header("运动")]
[SerializeField]
private float speed = 5f;
[SerializeField]
private float jumpForce = 12f;
// [Header("碰撞")]
[SerializeField]
private LayerMask groundLayer;
[SerializeField]
private float wallCheckDistance = 0.5f;
private Rigidbody2D body;
private Animator anim;
private CapsuleCollider2D capsuleCollider;
private float horizontalInput;
private bool isWallDetected;
private bool canWallSlide;
private bool isWallSliding;
[HideInInspector]
public bool ledgeDetected;
// [Header("ledge信息")]
[SerializeField]
private Vector2 offset1;
[SerializeField]
private Vector2 offset2;
private Vector2 climbBegunPosition;
private Vector2 climbOverPosition;
private bool canGrabLedge = true;
private bool canClimb;
private void Awake()
{
body = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
capsuleCollider = GetComponent<CapsuleCollider2D>();
}
private void Update()
{
// 输入
horizontalInput = Input.GetAxis("Horizontal");
// 翻转控制器
FlipController();
// 检查墙壁
CollisionCheck();
// 如果在墙壁滑行状态则只保留垂直速度
if (isWallSliding)
{
// 只保留垂直速度
body.linearVelocity = new Vector2(0, body.linearVelocity.y);
}
else
{
// 在水平方向上进行正常移动
body.linearVelocity = new Vector2(horizontalInput * speed, body.linearVelocity.y);
}
// 跳跃
if (Input.GetKeyDown(KeyCode.Space))
{
Jump();
}
CheckForLedge();
// 处理动画
HandleAnimations();
}
private void FixedUpdate()
{
// wallslide
if (isWallDetected && canWallSlide)
{
isWallSliding = true;
// 限制垂直速度
body.linearVelocity = new Vector2(body.linearVelocity.x, Mathf.Clamp(body.linearVelocity.y, -2f, float.MaxValue));
}
else
{
isWallSliding = false;
}
}
private void FlipController()
{
if (horizontalInput > 0.01f)
{
transform.localScale = new Vector3(3, 3, 1);
}
else if (horizontalInput < -0.01f)
{
transform.localScale = new Vector3(-3, 3, 1);
}
}
private void Jump()
{
if (isGrounded())
{
body.linearVelocity = new Vector2(body.linearVelocity.x, jumpForce);
anim.SetTrigger("jump");
}
}
private void CollisionCheck()
{
Vector2 direction = new Vector2(Mathf.Sign(transform.localScale.x), 0f);
RaycastHit2D hit = Physics2D.BoxCast(
capsuleCollider.bounds.center,
capsuleCollider.bounds.size,
0f,
direction,
wallCheckDistance,
groundLayer
);
isWallDetected = hit.collider != null;
canWallSlide = isWallDetected && !isGrounded() && body.linearVelocity.y < 0;
}
private void CheckForLedge()
{
if (ledgeDetected && canGrabLedge)
{
//
canGrabLedge = false;
Vector2 LedgePosition = GetComponentInChildren<LedgeDetection>().transform.position;
climbBegunPosition = LedgePosition + offset1;
climbOverPosition = LedgePosition + offset2;
canClimb = true;
}
//
if (canClimb)
{
Vector2 target = climbBegunPosition;
body.MovePosition(Vector2.Lerp(body.position, target, Time.fixedDeltaTime * 5f));
if (Vector2.Distance(body.position, target) < 0.05f)
{
LedgeClimbOver();
}
}
}
private void LedgeClimbOver()
{
canClimb = false;
transform.position = climbOverPosition;
Invoke("AllowLedgeGrab", 0.1f);
}
private void AllowLedgeGrab() => canGrabLedge = true;
private void HandleAnimations()
{
if (isWallSliding)
{
anim.SetBool("Run", false);
anim.SetBool("fall", false);
anim.SetBool("isWallSliding", true);
}
else
{
anim.SetBool("Run", horizontalInput != 0);
anim.SetBool("grounded", isGrounded());
anim.SetBool("fall", body.linearVelocity.y < -0.1f && !isGrounded());
anim.SetBool("isWallSliding", false);
anim.SetBool("canClimb", canClimb);
}
}
private bool isGrounded()
{
RaycastHit2D raycastHit = Physics2D.BoxCast(
capsuleCollider.bounds.center,
capsuleCollider.bounds.size,
0f,
Vector2.down,
0.1f,
groundLayer
);
return raycastHit.collider != null;
}
private void OnDrawGizmos()
{
if (capsuleCollider == null) return;
Gizmos.color = Color.red;
Vector3 direction3 = Application.isPlaying ? new Vector3(Mathf.Sign(transform.localScale.x), 0, 0) : Vector3.right;
Gizmos.DrawLine(capsuleCollider.bounds.center, capsuleCollider.bounds.center + direction3 * wallCheckDistance);
}
}
评论 (0)