Unity角色斜坡跳跃异常求助:无法抛物线跳跃且下坡小跳
角色斜坡移动与跳跃异常问题解决
问题描述
跟随Unity斜坡移动教程开发时,角色出现两个问题:
- 跳跃异常:无法做出正常抛物线跳跃,而是笔直僵硬地起跳
- 修改代码解决跳跃问题后,角色下坡时会出现非预期小跳,无法保持贴地
原脚本代码
using System.Collections; using System.Collections.Generic; using Unity.VisualScripting; using UnityEngine; using UnityEngine.UIElements; public class Player_Prototipo : MonoBehaviour { [SerializeField] private float moveSpeed; [SerializeField] private float JumpForce; [SerializeField] private LayerMask groundMask; [SerializeField] private float groundCheckDistance; [SerializeField] private float slopeChekDistance; [SerializeField] private PhysicsMaterial2D noFrictionMaterial; [SerializeField] private PhysicsMaterial2D frictionMaterial; private Rigidbody2D playerRB; private Animator playerAnimator; private CapsuleCollider2D playerCollider; private SpriteRenderer playerSpriteRenderer; private float moveInput; private Vector2 perpendicularSpeed; private Vector2 colliderSize; private Vector2 position; private Vector2 forcedDirection = new Vector2(0,0); private bool facingRight = true; private bool isGrounded; // Start is called before the first frame update void Start() { LoadComponents(); } // Update is called once per frame void Update() { position = transform.position - new Vector3(0f, colliderSize.y / 2, 0f); HandleInput(); HandleAnimations(); } private void FixedUpdate() { MoveAndNormalizeSlopes(); } private void LoadComponents() { playerRB = GetComponent<Rigidbody2D>(); playerAnimator = GetComponent<Animator>(); playerCollider = GetComponent<CapsuleCollider2D>(); playerSpriteRenderer = GetComponent<SpriteRenderer>(); colliderSize = playerCollider.size; } private void DebugDraw(RaycastHit2D hitSlope) { Debug.DrawRay(position, Vector3.down * groundCheckDistance, Color.blue); Debug.DrawRay(position, forcedDirection, Color.red); Debug.DrawRay(position, perpendicularSpeed, Color.red); Debug.DrawRay(position, hitSlope.normal, Color.green); Debug.DrawRay(position, Vector2.down * slopeChekDistance, Color.white); } private void MoveAndNormalizeSlopes() { RaycastHit2D hitDirection = Physics2D.Raycast(transform.position, Vector2.down, slopeChekDistance, groundMask); if(hitDirection.collider != null) { isGrounded = true; if(isGrounded && moveInput >= 0) { forcedDirection = new Vector2(hitDirection.normal.y, -hitDirection.normal.x); } else { forcedDirection = new Vector2(-hitDirection.normal.y, hitDirection.normal.x); } transform.Translate(forcedDirection * Mathf.Abs(moveInput) * moveSpeed); } else { isGrounded = false; } playerRB.velocity = new Vector2(moveInput * moveSpeed, playerRB.velocity.y); Debug.Log(isGrounded); DebugDraw(hitDirection); } private void HandleInput() { moveInput = Input.GetAxisRaw("Horizontal"); if (Input.GetKeyDown(KeyCode.Space) && isGrounded) { HandleJump(); } if ((moveInput > 0 && !facingRight) || (moveInput < 0 && facingRight)) { Flip(); } } private void HandleAnimations() { playerAnimator.SetBool("IsGrounded", isGrounded); playerAnimator.SetBool("Walk", Mathf.Abs(moveInput) != 0 && isGrounded); playerAnimator.SetBool("Jump", !isGrounded); } private void HandleJump() { playerRB.velocity = new Vector2(playerRB.velocity.x * JumpForce, JumpForce); //playerRB.AddForce(new Vector2(0f, JumpForce)); } private void Flip() { facingRight = !facingRight; playerSpriteRenderer.flipX = !facingRight; } }
尝试过的修改及新问题
将transform.Translate(forcedDirection * Mathf.Abs(moveInput) * moveSpeed);修改为playerRB.velocity = new Vector2(forcedDirection.x * moveSpeed, playerRB.velocity.y);后,跳跃恢复正常抛物线,但角色下坡时会出现非预期小跳,无法保持贴地。
问题根源
- 原代码混用
transform.Translate(直接修改位置,绕过物理引擎)和Rigidbody2D velocity,导致跳跃时物理状态被干扰,出现笔直起跳 - 修改后仅使用velocity,但未处理斜坡移动时的垂直速度,下坡时角色因重力与斜坡角度的关系,无法主动贴合地面,产生悬空小跳
- 原跳跃逻辑错误地将水平速度乘以JumpForce,导致跳跃时水平速度突变
修复方案
1. 统一用Rigidbody2D控制移动
完全移除transform.Translate,所有移动通过Rigidbody2D的velocity处理,保证物理引擎的一致性。
2. 修正斜坡移动的速度计算
检测到斜坡时,计算沿斜坡切线方向的移动速度,并调整垂直速度让角色主动贴合地面,避免悬空。
3. 修复跳跃逻辑
仅修改垂直方向速度,保留当前水平速度,保证跳跃抛物线正常。
修改后的关键代码
修正MoveAndNormalizeSlopes方法
private void MoveAndNormalizeSlopes() { // 从胶囊体底部发射射线,提升地面检测准确性 RaycastHit2D hitDirection = Physics2D.Raycast(position, Vector2.down, slopeChekDistance, groundMask); isGrounded = hitDirection.collider != null; if (isGrounded) { // 计算沿斜坡切线的移动方向 Vector2 slopeMovementDir; if (moveInput >= 0) { slopeMovementDir = new Vector2(hitDirection.normal.y, -hitDirection.normal.x); } else { slopeMovementDir = new Vector2(-hitDirection.normal.y, hitDirection.normal.x); } slopeMovementDir.Normalize(); // 标准化方向向量,避免速度异常 // 计算目标速度:沿斜坡方向的移动速度 + 保留重力的垂直贴合 Vector2 targetVelocity = slopeMovementDir * moveSpeed * Mathf.Abs(moveInput); // 确保垂直方向速度不大于当前速度,让角色贴合斜坡地面 targetVelocity.y = Mathf.Min(targetVelocity.y, playerRB.velocity.y); playerRB.velocity = targetVelocity; } else { // 空中时使用普通水平移动逻辑 playerRB.velocity = new Vector2(moveInput * moveSpeed, playerRB.velocity.y); } DebugDraw(hitDirection); }
修正HandleJump方法
private void HandleJump() { // 仅重置垂直速度为跳跃力,保留当前水平速度,保证抛物线正常 playerRB.velocity = new Vector2(playerRB.velocity.x, JumpForce); }
额外优化建议
- 给Rigidbody2D设置合适的
Linear Drag和Gravity Scale,提升移动和跳跃的手感 - 地面检测改用
Physics2D.OverlapCircle或OverlapCapsule,比单射线检测更稳定,避免斜坡边缘检测错误
内容的提问来源于stack exchange,提问作者Aprendizzz
相关产品推荐
相关产品推荐

