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

Unity中平移GameObject时对象倾倒问题求解

解决Unity中碰撞平移物体时倾倒/无法触发碰撞的问题

看起来你遇到的是物理引擎与直接Transform操作冲突的典型问题,我来给你几个可行的解决方案:

核心问题分析

  • 直接用transform.Translate()移动带非Kinematic Rigidbody的物体时,相当于强制篡改物体位置,物理引擎会认为物体受到了异常外力,导致倾倒、掉落的物理异常。
  • 设为Kinematic后,Rigidbody会完全脱离物理模拟,不仅不会被物理力影响,也不会触发OnCollisionEnter(因为碰撞检测需要至少一方是非Kinematic的Rigidbody),所以才会出现无法触发碰撞和移动的问题。

方案1:冻结旋转约束(最推荐)

不用修改Kinematic状态,只需给那四个Section物体的Rigidbody添加旋转冻结,就能阻止它们倾倒,同时保持碰撞检测和物理交互正常:

  1. 在Inspector面板中选中Section物体的Rigidbody组件
  2. 勾选Freeze Rotation下的X、Y、Z三个轴
  3. 调整移动代码,用物理引擎推荐的Rigidbody.MovePosition()代替transform.Translate()(对带Rigidbody的物体,物理方式移动更稳定)

修改后的代码:

void OnCollisionEnter(Collision collision) {
    Debug.Log("Collision");
    string targetName = collision.gameObject.name;
    // 简化判断逻辑,不用写多个else if
    if (targetName == "SectionOne" || targetName == "SectionTwo" || 
        targetName == "SectionThree" || targetName == "SectionFour") {
        Rigidbody rb = collision.gameObject.GetComponent<Rigidbody>();
        if (rb != null) {
            // 计算目标位置,按Z轴平移section_placement距离
            Vector3 newPosition = rb.transform.position + new Vector3(0, 0, section_placement);
            // 用MovePosition进行物理友好的移动
            rb.MovePosition(newPosition);
        }
    }
}

方案2:临时切换Kinematic状态

如果你的场景需要物体在移动后继续响应物理,可以临时切换Kinematic状态:

  • 碰撞触发时,先将Rigidbody设为Kinematic(避免移动时物理干扰)
  • 完成平移后,延迟恢复非Kinematic状态(给物理引擎一点时间稳定)

示例代码:

// 用来临时存储需要恢复状态的Rigidbody
private List<Rigidbody> _rigidbodiesToReset = new List<Rigidbody>();

void OnCollisionEnter(Collision collision) {
    Debug.Log("Collision");
    string targetName = collision.gameObject.name;
    if (targetName.StartsWith("Section")) {
        Rigidbody rb = collision.gameObject.GetComponent<Rigidbody>();
        if (rb != null) {
            // 保存原始状态并设为Kinematic
            _rigidbodiesToReset.Add(rb);
            rb.isKinematic = true;
            // 执行平移
            rb.transform.Translate(0, 0, section_placement);
            // 0.1秒后恢复物理状态
            Invoke(nameof(ResetRigidbodyStates), 0.1f);
        }
    }
}

void ResetRigidbodyStates() {
    foreach (var rb in _rigidbodiesToReset) {
        rb.isKinematic = false;
    }
    _rigidbodiesToReset.Clear();
}

额外优化建议

  • 可以给Section物体的Rigidbody调高Mass(质量),让它们更不容易被碰撞冲得移位
  • 如果不需要Section物体响应其他物理(比如被其他物体推动),可以在移动完成后永久设为Kinematic,这样后续也不会出现倾倒问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:00:02