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

Unity3D:如何让漫游车(立方体)贴合不规则月球表面移动并固定?

不规则月球地形漫游车贴合控制解决方案

问题背景

正在开发太空题材校园项目,以立方体模拟月球漫游车,需实现始终贴合不规则月球表面移动的控制逻辑,参考Sebastian Lague《Geographical Adventures》的地面载具模式(移除上下移动,底面固定贴地)。现有代码已实现引力吸引与底面朝向月球中心,但存在以下问题:

  • 无法稳定贴合不规则地形,出现浮空/穿模
  • 漫游车会自行漂移回赤道区域
  • 移动控制未适配球面地形的切线坐标系

现有代码问题分析

  • 直接修改rb.position会破坏刚体物理状态,导致地形贴合不稳定
  • 移动逻辑使用世界坐标系X/Z轴,未基于当前位置的地表切线方向,非赤道区域移动时会产生朝向偏差,最终漂移回赤道
  • 引力受力与强制位置修改冲突,刚体持续受引力作用后会脱离地表约束

修正后的代码

using UnityEngine;

public class RoverController : MonoBehaviour
{
    public Transform moonCenter;  
    public float moveSpeed = 8f;
    public float groundCheckDistance = 2f;
    public float rotationSmoothness = 12f;

    private Rigidbody rb;
    private Vector3 localUp;
    private Vector3 localForward;
    private Vector3 localRight;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
        rb.useGravity = false;
        rb.freezeRotation = true;
        rb.interpolation = RigidbodyInterpolation.Interpolate;
    }

    void FixedUpdate()
    {
        // 计算当前位置的引力方向(指向月球中心)
        localUp = (moonCenter.position - transform.position).normalized;
        // 计算地表切线坐标系的前/右方向
        localForward = Vector3.Cross(transform.right, localUp).normalized;
        localRight = Vector3.Cross(localUp, localForward).normalized;

        // 地表贴合逻辑:射线检测获取地表高度
        RaycastHit hit;
        if (Physics.Raycast(transform.position, localUp, out hit, groundCheckDistance))
        {
            // 计算目标位置:保持底面与地表接触
            float targetHeight = hit.distance - (transform.localScale.y * 0.5f);
            Vector3 targetPosition = transform.position + localUp * targetHeight;
            // 使用MovePosition平滑移动刚体,避免物理冲突
            rb.MovePosition(targetPosition);
            // 冻结垂直于地表方向的速度,防止浮空
            rb.velocity = Vector3.ProjectOnPlane(rb.velocity, localUp);
        }

        // 旋转逻辑:保持底面朝向月球中心,前向沿地表切线
        Quaternion targetRotation = Quaternion.LookRotation(localForward, localUp);
        rb.MoveRotation(Quaternion.Lerp(transform.rotation, targetRotation, Time.fixedDeltaTime * rotationSmoothness));
    }

    void Update()
    {
        // 获取输入
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");

        // 基于地表切线坐标系计算移动方向
        Vector3 moveDir = (localForward * vertical + localRight * horizontal).normalized;
        // 设置刚体速度,仅沿地表平面移动
        rb.velocity = moveDir * moveSpeed;
    }
}

关键改动说明

  • 地表贴合优化:使用rb.MovePosition替代直接修改位置,配合Vector3.ProjectOnPlane冻结垂直地表的速度,确保刚体始终贴地,同时保留物理稳定性
  • 球面坐标系适配:基于当前位置的引力方向(localUp)计算地表切线的前/右方向,移动输入完全适配球面地形,解决赤道漂移问题
  • 旋转逻辑简化:使用Quaternion.LookRotation直接计算目标旋转,配合rb.MoveRotation实现平滑且准确的贴地朝向
  • 移除冗余引力:取消主动添加引力的逻辑,通过地表贴合的位置约束替代,避免物理冲突

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 15:17:51