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

Unity 3D:除OnCollisionEnter外检测碰撞接触与合并脚本问题

解决持续接触下的物体合并问题

核心问题原因

OnCollisionEnter仅在碰撞开始的瞬间触发一次,当多个物体持续接触时,不会重复触发回调,导致升级后的物体无法和周围同类型物体继续合并。


方案1:使用OnCollisionStay替代OnCollisionEnter

OnCollisionStay会在物体持续接触的每一帧都调用,适合持续检测合并条件,但需要添加冷却机制避免重复触发合并逻辑。

修改后的碰撞检测代码

private float mergeCooldown = 0.5f; // 合并冷却时间,避免帧内重复触发
private float lastMergeTime;

private void OnCollisionStay(Collision collision)
{
    if (this.ObjectType == ObjectSize.Bigger || Time.time - lastMergeTime < mergeCooldown) 
        return;

    var collidedObj = collision.gameObject.GetComponent<MergeableObject>();
    if (collidedObj != null && collidedObj.ObjectType == this.ObjectType)
    {
        lastMergeTime = Time.time;
        CollisionCheck(collidedObj);
    }
}

优化合并逻辑

在CollisionCheck完成合并(升级物体类型)后,主动触发一次周围检测,确保升级后的物体能立即和其他同类型物体合并:

private void CollisionCheck(MergeableObject target)
{
    // 原有的合并逻辑:判断Y轴、禁用高位置物体、升级当前物体
    if (this.transform.position.y <= target.transform.position.y)
    {
        target.gameObject.SetActive(false);
        // 执行升级操作:放大、切换材质、更新ObjectType
        UpgradeObject();
        // 升级后立即检测周围是否有新的同类型物体
        CheckSurroundingObjects();
    }
}

private void CheckSurroundingObjects()
{
    // 用OverlapSphere检测周围一定范围内的物体
    Collider[] hitColliders = Physics.OverlapSphere(transform.position, 1.5f); // 半径根据物体大小调整
    foreach (var collider in hitColliders)
    {
        var mergeable = collider.GetComponent<MergeableObject>();
        if (mergeable != null && mergeable != this && mergeable.ObjectType == this.ObjectType && Time.time - lastMergeTime >= mergeCooldown)
        {
            lastMergeTime = Time.time;
            CollisionCheck(mergeable);
            break; // 每次升级后只处理一个,避免连锁反应导致逻辑混乱
        }
    }
}

方案2:主动帧检测(更稳定的持续检测)

如果碰撞回调仍有问题,可以完全放弃碰撞事件,改用Update中主动检测周围物体的方式,不受碰撞触发条件限制。

主动检测代码示例

private float checkInterval = 0.3f; // 检测间隔,降低性能消耗
private float lastCheckTime;

private void Update()
{
    if (this.ObjectType == ObjectSize.Bigger || Time.time - lastCheckTime < checkInterval)
        return;

    lastCheckTime = Time.time;
    CheckSurroundingObjects();
}

private void CheckSurroundingObjects()
{
    Collider[] hitColliders = Physics.OverlapSphere(transform.position, 1.5f);
    foreach (var collider in hitColliders)
    {
        var mergeable = collider.GetComponent<MergeableObject>();
        if (mergeable != null && mergeable != this && mergeable.ObjectType == this.ObjectType)
        {
            CollisionCheck(mergeable);
            return; // 处理一个后退出,避免同一帧多次合并
        }
    }
}

关键注意事项

  • 添加合并标记:可以给MergeableObject加一个isBeingMerged布尔值,在合并开始时设为true,完成后设为false,避免多个物体同时触发合并逻辑导致冲突。
  • 调整检测范围:OverlapSphere的半径要根据物体大小动态调整,确保能检测到相邻的同类型物体。
  • 性能优化:不要每一帧都执行检测,通过冷却时间/检测间隔降低性能消耗,避免大量物体同时检测导致卡顿。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 08:01:28