Unity 2021.3.25f1中玩家设为触发器对象子对象后位置异常
问题:玩家设置为堆垛机子对象后出现浮空/被推出触发器现象
环境
Unity 2021.3.25f1
现象描述
堆垛机左右两侧设有触发器,玩家进入触发器前处于地面,状态正常:
执行设置父对象操作后,玩家浮空:
俯视图可见,无任何移动操作的情况下,玩家已脱离触发器范围:
现有代码
设置父对象函数
public void AttachPlayerToSelf() { Debug.Log("position before attach : " + FirstPersonMovement.S.transform.position); FirstPersonMovement.S.rigidbody.isKinematic = true; joueurPCGO.GetComponent<FirstPersonMovement>().enabled = false; joueurPCGO.transform.SetParent(transform); Debug.Log("position after attach : " + FirstPersonMovement.S.transform.position); }
注:joueurPCGO为包含玩家的GameObject
调用逻辑
if (gerbeur.isPlayerOnSide) { if (!isPlayerAttachedToSelf) { AttachPlayerToSelf(); isPlayerAttachedToSelf = true; } }
注:Gerbeur即堆垛机对应的GameObject
触发器检测函数
private void OnTriggerStay(Collider other) { isPlayerOnSide = true; }
已尝试的无效方案
- 将玩家Rigidbody设为运动学,无变化
- 缩小玩家碰撞体范围,无效果
- 设置父对象时不修改Rigidbody运动学状态,问题依旧
解决方案
核心原因
- 父对象变换时的坐标计算异常,导致玩家位置偏移
- 触发器状态未及时重置,存在逻辑误判风险
- 玩家与堆垛机的碰撞体产生物理分离力,导致被推出
具体修复步骤
1. 修正父对象设置时的坐标保持
强制保持玩家世界坐标不变,避免局部坐标系转换导致的偏移:
public void AttachPlayerToSelf() { // 记录玩家当前世界坐标和旋转 Vector3 playerWorldPos = FirstPersonMovement.S.transform.position; Quaternion playerWorldRot = FirstPersonMovement.S.transform.rotation; // 先禁用玩家移动组件 joueurPCGO.GetComponent<FirstPersonMovement>().enabled = false; // 清空刚体速度,避免残留物理力影响 Rigidbody playerRb = FirstPersonMovement.S.rigidbody; playerRb.isKinematic = true; playerRb.velocity = Vector3.zero; playerRb.angularVelocity = Vector3.zero; // 设置父对象,保持世界坐标不变 joueurPCGO.transform.SetParent(transform, worldPositionStays: true); // 手动同步位置(防止自动计算出错) joueurPCGO.transform.SetPositionAndRotation(playerWorldPos, playerWorldRot); Debug.Log("position after attach : " + FirstPersonMovement.S.transform.position); }
2. 完善触发器状态逻辑
添加OnTriggerExit重置状态,避免状态一直为true:
private void OnTriggerStay(Collider other) { // 增加标签判断,确保仅玩家触发 if (other.CompareTag("Player")) isPlayerOnSide = true; } private void OnTriggerExit(Collider other) { if (other.CompareTag("Player")) isPlayerOnSide = false; }
3. 避免碰撞体物理分离
设置父对象前临时关闭玩家碰撞体,防止物理引擎强制分离重叠碰撞体:
public void AttachPlayerToSelf() { Vector3 playerWorldPos = FirstPersonMovement.S.transform.position; Quaternion playerWorldRot = FirstPersonMovement.S.transform.rotation; joueurPCGO.GetComponent<FirstPersonMovement>().enabled = false; // 临时关闭玩家碰撞体 Collider playerCol = joueurPCGO.GetComponent<Collider>(); playerCol.enabled = false; Rigidbody playerRb = FirstPersonMovement.S.rigidbody; playerRb.isKinematic = true; playerRb.velocity = Vector3.zero; joueurPCGO.transform.SetParent(transform, true); joueurPCGO.transform.SetPositionAndRotation(playerWorldPos, playerWorldRot); // 延迟一帧开启碰撞体,避开当前帧物理计算 Invoke(nameof(EnablePlayerCollider), 0.01f); } private void EnablePlayerCollider() { joueurPCGO.GetComponent<Collider>().enabled = true; }
4. 检查堆垛机物理设置
- 确认堆垛机的非触发碰撞体(如机身)与玩家碰撞体无重叠
- 若堆垛机带有刚体,设置其为运动学,避免父对象物理状态影响玩家
内容的提问来源于stack exchange,提问作者Aikkyo
相关产品推荐
相关产品推荐

