角色能力,存档

This commit is contained in:
2026-05-19 11:50:21 +08:00
parent d25f237e76
commit 2dcb7a961a
136 changed files with 36035 additions and 27551 deletions

View File

@@ -39,6 +39,20 @@ namespace BaseGames.Player
private SurfaceType _currentSurface = SurfaceType.Ground;
private readonly Collider2D[] _groundBuffer = new Collider2D[4];
#if UNITY_EDITOR
// ── 运行时调试Inspector 中可见)───────────────────────────────
[Header("\u2500\u2500 \u8fd0\u884c\u65f6\u8c03\u8bd5 \u2500\u2500")]
[SerializeField] private string _dbg_Position;
[SerializeField] private float _dbg_VelocityX;
[SerializeField] private float _dbg_VelocityY;
[SerializeField] private bool _dbg_IsGrounded;
[SerializeField] private bool _dbg_HasCoyoteTime;
[SerializeField] private bool _dbg_IsWallLeft;
[SerializeField] private bool _dbg_IsWallRight;
[SerializeField] private bool _dbg_CancelWindowOpen;
[SerializeField] private int _dbg_FacingDirection;
#endif
public bool IsGrounded => _isGrounded;
public bool HasCoyoteTime => _coyoteTimer > 0f;
public bool IsWallLeft => _isWallLeft;
@@ -53,10 +67,13 @@ namespace BaseGames.Player
private void Awake()
{
Debug.Assert(_config != null, "[PlayerMovement] _config 未赋值,请在 Inspector 中指定 PlayerMovementConfigSO。", this);
Debug.Assert(_config != null, "[PlayerMovement] _config 未赋值,请在 Inspector 中指定 PlayerMovementConfigSO。", this);
Debug.Assert(_groundCheck != null, "[PlayerMovement] GroundCheck 子节点未赋值,地面检测将无法工作,请在 Inspector 中指定 GroundCheck Transform。", this);
_rb = GetComponent<Rigidbody2D>();
// 关闭位置插值:若开启插值,渲染位置会在速度清零后仍追赶 1~2 渲染帧,产生视觉滑行
_rb.interpolation = RigidbodyInterpolation2D.None;
// 开启位置插值:在物理帧50Hz与渲染帧60Hz+)之间平滑视觉位置,消除跳帧抖动
// SpritePixelSnapperLateUpdate +1000在插值结果基础上吸附到像素网格
// 与 CameraPixelSnapper 同格对齐,消除亚像素模糊;停止时 ≤2 帧像素追赶不可感知。
_rb.interpolation = RigidbodyInterpolation2D.Interpolate;
if (_spriteRenderer == null)
_spriteRenderer = GetComponentInChildren<SpriteRenderer>();
}
@@ -77,6 +94,18 @@ namespace BaseGames.Player
_coyoteTimer = _config.CoyoteTime;
else
_coyoteTimer = Mathf.Max(0f, _coyoteTimer - Time.fixedDeltaTime);
#if UNITY_EDITOR
_dbg_VelocityX = _rb.velocity.x;
_dbg_VelocityY = _rb.velocity.y;
_dbg_IsGrounded = _isGrounded;
_dbg_HasCoyoteTime = _coyoteTimer > 0f;
_dbg_IsWallLeft = _isWallLeft;
_dbg_IsWallRight = _isWallRight;
_dbg_CancelWindowOpen = _cancelWindowOpen;
_dbg_FacingDirection = _facingDirection;
_dbg_Position = $"({transform.position.x:F1}, {transform.position.y:F1})";
#endif
}
// ── 移动 ──────────────────────────────────────────────────────────────
@@ -169,8 +198,8 @@ namespace BaseGames.Player
}
/// <summary>
/// 壁滑:将垂直速度限制为 -WallSlideSpeed向下缓慢滑动
/// WallSlideState.OnStateFixedUpdate 每帧调用。
/// 壁滑:将垂直速度限制为 -WallSlideSpeed受限抓墙时向下缓慢滑动)。
/// WallSlideState.OnStateFixedUpdate 在受限模式下每帧调用。
/// </summary>
public void ApplyWallSlide()
{
@@ -180,29 +209,42 @@ namespace BaseGames.Player
}
/// <summary>
/// 墙跳:对墙方向施加相反水平力 + 向上力
/// wallDir = +1 (右墙) 或 -1 (左墙)跳跃方向与之相反。
/// 墙跳Jump Away远离墙壁斜上方弹出
/// wallDir = +1 (右墙) 或 -1 (左墙)水平方向与之相反。
/// </summary>
public void WallJump(int wallDir)
public void WallJumpAway(int wallDir)
{
float forceX = -wallDir * _config.WallJumpForceX;
float forceY = _config.WallJumpForceY;
_rb.velocity = new Vector2(forceX, forceY);
_rb.velocity = new Vector2(-wallDir * _config.WallJumpAwayForceX, _config.WallJumpAwayForceY);
_coyoteTimer = 0f;
}
/// <summary>
/// 对墙跳Jump Toward沿墙壁方向偏向正上方弹出水平分量较小。
/// wallDir = +1 (右墙) 或 -1 (左墙),水平方向与之相同。
/// </summary>
public void WallJumpToward(int wallDir)
{
_rb.velocity = new Vector2(wallDir * _config.WallJumpTowardForceX, _config.WallJumpTowardForceY);
_coyoteTimer = 0f;
}
/// <summary>将垂直速度归零(抓墙悬挂时每帧调用,防止下滑)。</summary>
public void ZeroVerticalVelocity()
{
if (_rb.velocity.y < 0f)
_rb.velocity = new Vector2(_rb.velocity.x, 0f);
}
/// <summary>单向平台穿透(输入下行 + 跳跃键时触发)。</summary>
public void DropThroughPlatform() { }
// ── Physics 检测 ──────────────────────────────────────────────────────
private void CheckGrounded()
{
bool wasGrounded = _isGrounded;
Vector2 origin = _groundCheck != null
? (Vector2)_groundCheck.position
: (Vector2)transform.position + Vector2.down * 0.5f;
if (_groundCheck == null) return;
_isGrounded = Physics2D.OverlapBoxNonAlloc(origin, _groundCheckSize, 0f, _groundBuffer, _groundLayer) > 0;
bool wasGrounded = _isGrounded;
_isGrounded = Physics2D.OverlapBoxNonAlloc(_groundCheck.position, _groundCheckSize, 0f, _groundBuffer, _groundLayer) > 0;
if (_isGrounded && !wasGrounded)
_coyoteTimer = _config.CoyoteTime;
@@ -234,15 +276,24 @@ namespace BaseGames.Player
Vector3 arrowEnd = center + new Vector3(_facingDirection * 0.55f, 0f, 0f);
DrawArrow2D(center, arrowEnd, new Color(1f, 0.85f, 0.1f, 0.95f));
// ── 3. 站立检测框(落地亮绿 / 未落地淡绿)──────────────────────
Vector2 gOrigin = _groundCheck != null
? (Vector2)_groundCheck.position
: (Vector2)transform.position + Vector2.down * 0.5f;
bool grounded = Application.isPlaying && _isGrounded;
Gizmos.color = grounded
? new Color(0.1f, 1f, 0.3f, 0.9f)
: new Color(0.4f, 0.85f, 0.4f, 0.35f);
BaseGames.Combat.HitBox.DrawWireRect2D(gOrigin, _groundCheckSize);
// ── 3. 站立检测框(落地亮绿 / 未落地淡绿;未赋值时显示红色警告框)──
if (_groundCheck == null)
{
Gizmos.color = new Color(1f, 0.1f, 0.1f, 0.9f);
Gizmos.DrawWireSphere(transform.position, 0.25f);
#if UNITY_EDITOR
UnityEditor.Handles.color = new Color(1f, 0.1f, 0.1f, 1f);
UnityEditor.Handles.Label(transform.position + Vector3.up * 0.6f, "GroundCheck 未赋值!");
#endif
}
else
{
bool grounded = Application.isPlaying && _isGrounded;
Gizmos.color = grounded
? new Color(0.1f, 1f, 0.3f, 0.9f)
: new Color(0.4f, 0.85f, 0.4f, 0.35f);
BaseGames.Combat.HitBox.DrawWireRect2D(_groundCheck.position, _groundCheckSize);
}
// ── 4. 靠墙检测射线(碰墙橙色 / 未碰淡黄,带端点圆点)─────────
if (_config == null) return;