Unity球面上运动物体朝向移动方向的实现问题求助
问题核心原因
- 旋转逻辑冲突:两处代码同时修改
transform.rotation,移动脚本里的朝向移动逻辑和引力脚本里的球面朝上对齐逻辑互相覆盖,没有做旋转合并。 - 移动方向计算错误:每60帧采样一次位置差计算
moveDirection的方式间隔过长,很容易拿到零向量或者错误方向,且Quaternion.LookRotation默认使用世界Y轴作为朝上方向,和球面场景需要的法线朝上逻辑不匹配。 - 刚体参数异常:给刚体开启了
RigidbodyConstraints.FreezeRotation锁死了物理旋转,同时原引力代码里的引力方向写反,实际是给物体施加了远离球心的斥力。 - 移动方向赋值错误:
Wander方法里生成新移动方向时,错误把mDirection.z写成了mDirection.y,会导致移动方向计算完全偏离预期。
修复方案
1. 调整引力吸引方法
将球面法线参数向外传递,不在引力方法内直接修改物体旋转,避免和朝向逻辑冲突,同时修正引力方向:
public void gravityAttractor(Transform body, out Vector3 surfaceNormal) { // 球面法线为球心指向物体的方向,作为物体的朝上基准 surfaceNormal = (body.position - transform.position).normalized; // 加负号把力的方向改为指向球心,实现引力效果 body.GetComponent<Rigidbody>().AddForce(-surfaceNormal * gravity); }
2. 重写物体移动与旋转逻辑
删除原有60帧采样位置的逻辑,直接用刚体速度计算移动方向,合并球面朝上与朝向移动的两个旋转需求:
private Rigidbody rb; private GravityAttractor Level; private void Awake() { rb = GetComponent<Rigidbody>(); Level = GameObject.FindGameObjectWithTag("Level").GetComponent<GravityAttractor>(); rb.useGravity = false; // 移除旋转冻结约束 rb.constraints = RigidbodyConstraints.None; } void Wander() { int rDirChange = Random.Range(0, 10); if (rDirChange > dChange) { // 修正之前错误的y轴赋值,改为z轴 mDirection = new Vector3((mDirection.x + Random.Range(-30, 30)), 0, (mDirection.z + Random.Range(-30, 30))).normalized; Vector3 tMovement = mDirection * moveSpeed; Movement = Vector3.SmoothDamp(Movement, tMovement, ref smoothMovement, 0.5f); } } private void FixedUpdate() { // 先执行引力逻辑,拿到当前位置的球面法线 Vector3 surfaceNormal; Level.gravityAttractor(transform, out surfaceNormal); // 原有移动逻辑保持不变 rb.MovePosition(rb.position + (transform.TransformDirection(Movement) * Time.fixedDeltaTime)); // 速度大于阈值时才更新移动朝向,避免静止时物体乱转 if (rb.velocity.magnitude > 0.1f) { // 核心:LookRotation第二个参数传入球面法线,保证物体朝上对齐球面的同时前向对齐移动方向 Quaternion targetRot = Quaternion.LookRotation(rb.velocity.normalized, surfaceNormal); transform.rotation = Quaternion.Slerp(transform.rotation, targetRot, Time.deltaTime * 0.5f); } else { // 静止时仅保持物体朝上对齐球面法线 Quaternion targetRot = Quaternion.FromToRotation(transform.up, surfaceNormal) * transform.rotation; transform.rotation = Quaternion.Slerp(transform.rotation, targetRot, Time.deltaTime * 2f); } }
3. 删除冗余代码
原物体挂载的单独执行引力的脚本可以完全删掉,引力逻辑已经整合到移动脚本的FixedUpdate中,避免重复执行引力计算。
内容的提问来源于stack exchange,提问作者riji
相关产品推荐
相关产品推荐

