Wall Slide执行一次Wall Jump后失效,无法再次触发求助
问题
Wall Slide功能初始运行正常,但执行一次Wall Jump后,Wall Slide彻底失效,且无法再次触发Wall Jump。以下是Player Movement代码:
public class PlayerMovement : MonoBehaviour { [Header("Movement Options")] public float speed; public float jumpForce; public float acceleration; private float currentSpeed; private float horizontal; private bool isFacingRight = true; [SerializeField] private bool isWallSliding; private float wallSlidingSpeed = 2f; private bool isWallJumping; private float wallJumpingDirection; private float wallJumpingTime = 0.2f; private float wallJumpingCounter; private float wallJumpingDuration = 0.4f; private Vector2 wallJumpingPower = new Vector2(8f, 16f); [SerializeField] private Transform wallCheck; [SerializeField] private LayerMask wallLayer; [Header("Coyote and Buffer")] public float coyoteTime; private float coyoteCounter; public float bufferTime; private float buffetCounter; [Header("Components")] public Rigidbody2D rb; public Transform groundCheck; public LayerMask groundLayer; void Start() { currentSpeed = 0; } void Update() { Debug.Log($"isWallJumping: {isWallJumping}, isWallSliding: {isWallSliding}, isWalled: {isWalled()}, isGrounded: {isGrounded()}"); horizontal = Input.GetAxisRaw("Horizontal"); Jump(); BetterJump(); WallSlide(); WallJump(); if (!isWallJumping && !isWallSliding) { Flip(); } } void FixedUpdate() { if (!isWallJumping) { if (horizontal != 0) { currentSpeed = Mathf.MoveTowards(currentSpeed, speed * horizontal, acceleration * Time.fixedDeltaTime); } else { currentSpeed = Mathf.MoveTowards(currentSpeed, 0, acceleration * Time.fixedDeltaTime); } rb.velocity = new Vector2(currentSpeed, rb.velocity.y); } } bool isGrounded() { return Physics2D.OverlapCircle(groundCheck.position, 0.2f, groundLayer); } private bool isWalled() { return Physics2D.OverlapCircle(wallCheck.position, 0.2f, wallLayer); } private void WallSlide() { if (isWalled() && !isGrounded() && horizontal != 0) { isWallSliding = true; rb.velocity = new Vector2(rb.velocity.x, Mathf.Clamp(rb.velocity.y, -wallSlidingSpeed, float.MaxValue)); } else { isWallSliding = false; } } private void WallJump() { if (isWallSliding) { isWallJumping = false; wallJumpingDirection = -transform.localScale.x; wallJumpingCounter = wallJumpingTime; CancelInvoke(nameof(StopWallJumping)); } else { wallJumpingCounter -= Time.deltaTime; } if (Input.GetButtonDown("Jump") && (wallJumpingCounter > 0f || isWallSliding)) { isWallJumping = true; isWallSliding = false; rb.velocity = new Vector2(wallJumpingDirection * wallJumpingPower.x, wallJumpingPower.y); wallJumpingCounter = 0f; if (transform.localScale.x != wallJumpingDirection) { isFacingRight = !isFacingRight; Vector3 localScale = transform.localScale; localScale.x *= -1f; transform.localScale = localScale; } Invoke(nameof(StopWallJumping), wallJumpingDuration); } // Verifica se o personagem está na parede após o Wall Jump if (isWalled() && !isGrounded()) { isWallSliding = true; } } private void StopWallJumping() { isWallJumping = false; } void Jump() { if (buffetCounter > 0f && coyoteCounter > 0f) { rb.velocity = new Vector2(rb.velocity.x, jumpForce); buffetCounter = 0f; } if (Input.GetButtonDown("Jump") && rb.velocity.y > 0f) { rb.velocity = new Vector2(rb.velocity.x, rb.velocity.y * 0.5f); coyoteCounter = 0f; } } void BetterJump() { if (isGrounded()) { coyoteCounter = coyoteTime; } else { coyoteCounter -= Time.deltaTime; } if (Input.GetButtonDown("Jump")) { buffetCounter = bufferTime; } else { buffetCounter -= Time.deltaTime; } } void Flip() { if (isFacingRight && horizontal < 0f || !isFacingRight && horizontal > 0f) { isFacingRight = !isFacingRight; Vector3 localScale = transform.localScale; localScale.x *= 1f; transform.localScale = localScale; } } }
问题分析与修复
核心问题点
- WallJump方法末尾的错误赋值:代码最后强制设置
isWallSliding = true,完全忽略了WallSlide方法中「必须按住对应方向键(horizontal≠0)」的判断条件,导致Wall Jump后即使没有按住方向键,也会强制开启滑墙状态,干扰后续的状态判断逻辑。 - Flip方法的翻转逻辑错误:
localScale.x *= 1f等于没有修改缩放值,角色无法正确翻转,导致wallJumpingDirection计算错误,后续Wall Jump的方向会出问题。 - WallJump触发时的状态干扰:WallJump触发时直接设置
isWallSliding=false,但后续逻辑没有正确让状态回归到WallSlide的判断流程。
修复后的代码
public class PlayerMovement : MonoBehaviour { [Header("Movement Options")] public float speed; public float jumpForce; public float acceleration; private float currentSpeed; private float horizontal; private bool isFacingRight = true; [SerializeField] private bool isWallSliding; private float wallSlidingSpeed = 2f; private bool isWallJumping; private float wallJumpingDirection; private float wallJumpingTime = 0.2f; private float wallJumpingCounter; private float wallJumpingDuration = 0.4f; private Vector2 wallJumpingPower = new Vector2(8f, 16f); [SerializeField] private Transform wallCheck; [SerializeField] private LayerMask wallLayer; [Header("Coyote and Buffer")] public float coyoteTime; private float coyoteCounter; public float bufferTime; private float buffetCounter; [Header("Components")] public Rigidbody2D rb; public Transform groundCheck; public LayerMask groundLayer; void Start() { currentSpeed = 0; } void Update() { Debug.Log($"isWallJumping: {isWallJumping}, isWallSliding: {isWallSliding}, isWalled: {isWalled()}, isGrounded: {isGrounded()}"); horizontal = Input.GetAxisRaw("Horizontal"); Jump(); BetterJump(); // 调整执行顺序:先处理WallJump,再处理WallSlide,避免状态覆盖 WallJump(); WallSlide(); if (!isWallJumping && !isWallSliding) { Flip(); } } void FixedUpdate() { if (!isWallJumping) { if (horizontal != 0) { currentSpeed = Mathf.MoveTowards(currentSpeed, speed * horizontal, acceleration * Time.fixedDeltaTime); } else { currentSpeed = Mathf.MoveTowards(currentSpeed, 0, acceleration * Time.fixedDeltaTime); } rb.velocity = new Vector2(currentSpeed, rb.velocity.y); } } bool isGrounded() { return Physics2D.OverlapCircle(groundCheck.position, 0.2f, groundLayer); } private bool isWalled() { return Physics2D.OverlapCircle(wallCheck.position, 0.2f, wallLayer); } private void WallSlide() { // 仅当不在WallJump状态时,才判断滑墙条件 if (!isWallJumping && isWalled() && !isGrounded() && horizontal != 0) { isWallSliding = true; rb.velocity = new Vector2(rb.velocity.x, Mathf.Clamp(rb.velocity.y, -wallSlidingSpeed, float.MaxValue)); } else { isWallSliding = false; } } private void WallJump() { if (isWallSliding) { isWallJumping = false; wallJumpingDirection = -transform.localScale.x; wallJumpingCounter = wallJumpingTime; CancelInvoke(nameof(StopWallJumping)); } else { wallJumpingCounter -= Time.deltaTime; } if (Input.GetButtonDown("Jump") && (wallJumpingCounter > 0f || isWallSliding)) { isWallJumping = true; isWallSliding = false; rb.velocity = new Vector2(wallJumpingDirection * wallJumpingPower.x, wallJumpingPower.y); wallJumpingCounter = 0f; if (transform.localScale.x != wallJumpingDirection) { isFacingRight = !isFacingRight; Vector3 localScale = transform.localScale; localScale.x *= -1f; transform.localScale = localScale; } Invoke(nameof(StopWallJumping), wallJumpingDuration); } // 移除错误的强制滑墙赋值逻辑,交给WallSlide方法处理 } private void StopWallJumping() { isWallJumping = false; } void Jump() { if (buffetCounter > 0f && coyoteCounter > 0f) { rb.velocity = new Vector2(rb.velocity.x, jumpForce); buffetCounter = 0f; } if (Input.GetButtonDown("Jump") && rb.velocity.y > 0f) { rb.velocity = new Vector2(rb.velocity.x, rb.velocity.y * 0.5f); coyoteCounter = 0f; } } void BetterJump() { if (isGrounded()) { coyoteCounter = coyoteTime; } else { coyoteCounter -= Time.deltaTime; } if (Input.GetButtonDown("Jump")) { buffetCounter = bufferTime; } else { buffetCounter -= Time.deltaTime; } } void Flip() { if (isFacingRight && horizontal < 0f || !isFacingRight && horizontal > 0f) { isFacingRight = !isFacingRight; Vector3 localScale = transform.localScale; // 修复翻转逻辑:乘以-1实现左右翻转 localScale.x *= -1f; transform.localScale = localScale; } } }
关键修改说明
- 移除了
WallJump方法末尾强制设置isWallSliding = true的代码,让滑墙状态完全由WallSlide方法的条件判断来控制。 - 修复了
Flip方法中的缩放值修改逻辑,将localScale.x *= 1f改为localScale.x *= -1f,确保角色能正确翻转。 - 调整了
Update中WallJump和WallSlide的执行顺序,避免状态被意外覆盖。 - 在
WallSlide方法中增加了!isWallJumping的判断,确保WallJump过程中不会触发滑墙逻辑。
内容的提问来源于stack exchange,提问作者Al Simmons
相关产品推荐
相关产品推荐

