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

Unity中如何在无物理系统下实现带碰撞的3D立方体跳跃移动

无物理系统的3D平台跳跃实现方案

核心思路

完全摒弃Unity物理引擎(如Rigidbody),通过射线检测判断地面接触状态,手动计算跳跃位移,结合BoxCast实现移动碰撞检测,模拟3D平台游戏的跳跃与移动效果。

关键实现步骤

1. 地面检测(跳跃触发前提)

通过向立方体下方发射短射线,判断是否接触地面:

  • 射线起点:立方体Collider的中心偏下位置(避免边角误判)
  • 射线长度:略大于Collider半高+地面误差值(比如collider.bounds.extents.y + 0.1f)
  • 检测层:指定地面层,过滤其他碰撞体

2. 跳跃逻辑实现

采用固定跳跃高度+时间控制的方式,模拟跳跃的上升与下落:

  • 记录跳跃状态(isJumping),仅在地面时允许触发跳跃
  • 用计时器(jumpTimer)控制跳跃周期,根据时间计算Y轴位移(比如用二次曲线模拟平滑跳跃)
  • 跳跃结束后自动回到地面状态

3. 移动与碰撞检测

使用Physics.BoxCast检测移动方向上的障碍物,避免穿模:

  • 以立方体Collider为基准,向移动方向发射BoxCast
  • 若检测到障碍物,则取消该方向的移动
  • 移动时保持Y轴位置不变(除非跳跃中)

完整代码示例

using UnityEngine;

public class PlatformerController : MonoBehaviour
{
    [Header("移动设置")]
    public float moveSpeed = 5f;
    public LayerMask groundLayer;
    public LayerMask obstacleLayer;

    [Header("跳跃设置")]
    public float jumpHeight = 2f;
    public float jumpDuration = 0.5f;

    private BoxCollider boxCollider;
    private bool isGrounded;
    private bool isJumping;
    private float jumpTimer;
    private float startYPos;

    private void Awake()
    {
        boxCollider = GetComponent<BoxCollider>();
    }

    private void Update()
    {
        // 地面检测
        CheckGround();

        // 跳跃输入
        if (Input.GetKeyDown(KeyCode.Space) && isGrounded && !isJumping)
        {
            StartJump();
        }

        // 处理跳跃过程
        if (isJumping)
        {
            UpdateJump();
        }

        // 移动输入
        Vector3 input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
        if (input.magnitude > 0.1f)
        {
            input = input.normalized;
            Move(input);
        }
    }

    private void CheckGround()
    {
        // 计算射线起点和长度
        Vector3 rayOrigin = transform.position + Vector3.down * (boxCollider.bounds.extents.y - 0.05f);
        float rayLength = 0.15f;

        // 发射射线检测地面
        isGrounded = Physics.Raycast(rayOrigin, Vector3.down, rayLength, groundLayer);

        // 若落地则重置跳跃状态
        if (isGrounded && isJumping)
        {
            isJumping = false;
            transform.position = new Vector3(transform.position.x, startYPos, transform.position.z);
        }
    }

    private void StartJump()
    {
        isJumping = true;
        jumpTimer = 0f;
        startYPos = transform.position.y;
    }

    private void UpdateJump()
    {
        jumpTimer += Time.deltaTime;
        float progress = jumpTimer / jumpDuration;

        // 用二次曲线计算Y轴位移,实现平滑跳跃
        float yOffset = jumpHeight * 4 * progress * (1 - progress);
        transform.position = new Vector3(transform.position.x, startYPos + yOffset, transform.position.z);

        // 跳跃结束
        if (progress >= 1f)
        {
            isJumping = false;
            // 强制触发一次地面检测,避免悬空
            CheckGround();
        }
    }

    private void Move(Vector3 direction)
    {
        // 计算移动后的目标位置
        Vector3 targetPos = transform.position + direction * moveSpeed * Time.deltaTime;

        // 用BoxCast检测移动路径上的障碍物
        Vector3 castCenter = boxCollider.bounds.center;
        Vector3 castSize = boxCollider.bounds.extents;
        float castDistance = Vector3.Distance(transform.position, targetPos);

        if (!Physics.BoxCast(castCenter, castSize, direction, transform.rotation, castDistance, obstacleLayer))
        {
            // 无障碍物则移动
            transform.position = targetPos;
        }
    }
}

注意事项

  • 确保地面和障碍物分别设置对应Layer,避免检测混乱
  • 调整jumpHeight和jumpDuration可以改变跳跃的手感
  • 移动速度moveSpeed可根据需求调整,建议配合输入平滑处理(如用Mathf.Lerp)
  • 射线长度和BoxCast参数需根据立方体Collider大小微调,避免误判或漏判

内容的提问来源于stack exchange,提问作者Redis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 14:01:13