单向平台

This commit is contained in:
2026-05-21 11:44:01 +08:00
parent 94113a9c1b
commit 67e2d3a8ff
7 changed files with 107 additions and 14 deletions

View File

@@ -1,3 +1,4 @@
using BaseGames.Core;
using UnityEngine;
namespace BaseGames.Player
@@ -34,7 +35,8 @@ namespace BaseGames.Player
private int _facingDirection = 1;
private bool _cancelWindowOpen;
private SurfaceType _currentSurface = SurfaceType.Ground;
private readonly Collider2D[] _groundBuffer = new Collider2D[4];
private readonly Collider2D[] _groundBuffer = new Collider2D[4];
private int _groundHitCount;
#if UNITY_EDITOR
// ── 运行时调试Inspector 中可见)───────────────────────────────
@@ -43,6 +45,7 @@ namespace BaseGames.Player
[SerializeField] private float _dbg_VelocityX;
[SerializeField] private float _dbg_VelocityY;
[SerializeField] private bool _dbg_IsGrounded;
[SerializeField] private bool _dbg_OnOneWayPlatform;
[SerializeField] private bool _dbg_HasCoyoteTime;
[SerializeField] private bool _dbg_IsWallLeft;
[SerializeField] private bool _dbg_IsWallRight;
@@ -91,10 +94,11 @@ namespace BaseGames.Player
_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_VelocityX = _rb.velocity.x;
_dbg_VelocityY = _rb.velocity.y;
_dbg_IsGrounded = _isGrounded;
_dbg_OnOneWayPlatform = _onOneWayPlatform;
_dbg_HasCoyoteTime = _coyoteTimer > 0f;
_dbg_IsWallLeft = _isWallLeft;
_dbg_IsWallRight = _isWallRight;
_dbg_CancelWindowOpen = _cancelWindowOpen;
@@ -243,19 +247,54 @@ namespace BaseGames.Player
_rb.velocity = new Vector2(_rb.velocity.x, 0f);
}
/// <summary>单向平台穿透(输入下行 + 跳跃键时触发)。</summary>
public void DropThroughPlatform() { }
/// <summary>
/// 单向平台穿落(↓ + 跳跃键触发)。
/// 找到脚下的 <see cref="IDropThrough"/> 并临时禁用其碰撞器;
/// 同帧清除 IsGrounded / OnOneWayPlatform状态机无需等到下一物理帧即可转换到 FallState。
/// </summary>
public void DropThroughPlatform()
{
if (!_onOneWayPlatform) return;
for (int i = 0; i < _groundHitCount; i++)
{
if (_groundBuffer[i] != null &&
_groundBuffer[i].TryGetComponent<IDropThrough>(out var platform))
{
platform.TriggerDropThrough();
// 立即清除着地状态,让状态机本帧即可切换到 FallState
_isGrounded = false;
_onOneWayPlatform = false;
_coyoteTimer = 0f;
break;
}
}
}
// ── Physics 检测 ──────────────────────────────────────────────────────
private void CheckGrounded()
{
if (_groundCheck == null) return;
bool wasGrounded = _isGrounded;
_isGrounded = Physics2D.OverlapBoxNonAlloc(_groundCheck.position, _groundCheckSize, 0f, _groundBuffer, _groundLayer) > 0;
_groundHitCount = Physics2D.OverlapBoxNonAlloc(
_groundCheck.position, _groundCheckSize, 0f, _groundBuffer, _groundLayer);
_isGrounded = _groundHitCount > 0;
if (_isGrounded && !wasGrounded)
_coyoteTimer = _config.CoyoteTime;
// 检测是否站在单向平台(含 IDropThrough 组件的碰撞体)
_onOneWayPlatform = false;
for (int i = 0; i < _groundHitCount; i++)
{
if (_groundBuffer[i] != null &&
_groundBuffer[i].TryGetComponent<IDropThrough>(out _))
{
_onOneWayPlatform = true;
break;
}
}
_currentSurface = (_isGrounded && _onOneWayPlatform)
? SurfaceType.OneWayPlatform
: SurfaceType.Ground;
}
private void CheckWalls()

View File

@@ -26,6 +26,13 @@ namespace BaseGames.Player.States
_owner.TransitionTo(_owner.GetState<FallState>());
return;
}
// 单向平台穿落:↓ + 跳跃键,优先于普通跳跃,避免误消耗跳跃缓冲
if (Move.OnOneWayPlatform && Input.MoveInput.y < -0.5f && Buffer.ConsumeJump())
{
Move.DropThroughPlatform();
_owner.TransitionTo(_owner.GetState<FallState>());
return;
}
if (Buffer.ConsumeJump())
{
_owner.TransitionTo(_owner.GetState<JumpState>());

View File

@@ -25,6 +25,13 @@ namespace BaseGames.Player.States
_owner.TransitionTo(_owner.GetState<FallState>());
return;
}
// 单向平台穿落:↓ + 跳跃键,优先于普通跳跃
if (Move.OnOneWayPlatform && Input.MoveInput.y < -0.5f && Buffer.ConsumeJump())
{
Move.DropThroughPlatform();
_owner.TransitionTo(_owner.GetState<FallState>());
return;
}
if (Buffer.ConsumeJump())
{
_owner.TransitionTo(_owner.GetState<JumpState>());