You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);后,跳跃恢复正常抛物线,但角色下坡时会出现非预期小跳,无法保持贴地。

问题根源

  1. 原代码混用transform.Translate(直接修改位置,绕过物理引擎)和Rigidbody2D velocity,导致跳跃时物理状态被干扰,出现笔直起跳
  2. 修改后仅使用velocity,但未处理斜坡移动时的垂直速度,下坡时角色因重力与斜坡角度的关系,无法主动贴合地面,产生悬空小跳
  3. 原跳跃逻辑错误地将水平速度乘以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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 03:54:54