【问题标题】:Can't detect collisions in Unity在 Unity 中无法检测到碰撞
【发布时间】:2020-01-20 04:38:14
【问题描述】:

我是 Unity 新手,正在努力使用 OnCollisionEnter 函数。

我意识到这听起来与其他问题相似,但我仍然无法让它适用于我的案例。

我正在使用 Oculus 距离抓取示例场景。

我有一个障碍试图撞到一个足球;)

该块有一个盒子碰撞器(非触发器)和刚体(非重力,非运动学)。

足球有一个 Sphere Collider(非触发器)和一个刚体(是重力,非运动学)。

该块包含一个脚本组件,可以让它漂浮到球上并撞到球上。

球有一个带有 OnCollisionEnter 函数的脚本,该函数应该在接触时破坏块。

这是附在球上的Player 脚本。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour
{
    void OnCollisionEnter (Collision col) {
        FloatingItem item = col.collider.gameObject.GetComponent<FloatingItem>();
        Destroy(item);
    }
}

球在Player 层中,而块在Attacker 层中。我在 Player Settings 碰撞矩阵中仔细检查了这些层之间是否启用了碰撞。

此外,每个对象的碰撞器的大小似乎都应与网格匹配。

任何让碰撞工作的帮助都会很棒!

这也是设置的视觉效果:

更新:

这是浮动块的Update方法:

void FixedUpdate () {
      if(targetTransform != null) {
        this.transform.position = Vector3.MoveTowards(this.transform.position, targetTransform.transform.position, Time.deltaTime * moveSpeed);
      }
    }

我无法在控制台中显示任何调试日志,因此它们不可靠。但答案是碰撞实际上是有效的,但我破坏了错误的对象。

将其更改为 Destroy(col.collider.gameObject) 有效。在这里学到了一个重要的区别!谢谢!

更新 2:

我添加了一张OVRPlayerController 设置方式的图片。试图通读关于 character controller 组件的弱文档,但我的理解是它包含一个胶囊对撞机。

【问题讨论】:

  • 请特别显示The block contains a script component that makes it float over to the ball and run into it. 的代码 剧透:任何具有刚体的东西都只能通过MovePositionFixedUpdate 内移动,否则物理学无法正常工作。如果块被脚本移动,你可能还想启用isKinematic,除非它会对物理做出反应
  • 现在您只是在销毁 FloatingItem 脚本,而不是整个 GameObject。你检查过 Debug.Log("collision");是否触发了碰撞?
  • @derHugo 如果每帧都使用 MovePosition,isKinematic 一定要开启,或者相当于设置了刚体.position。如果你想要碰撞,你应该简单地在第一帧设置速度。
  • @LouisGarczynski 你不会使用它every frame 但在固定的时间间隔内(通常是 0.2 秒)
  • 正如@nka_Zz 指出的那样,我没有正确销毁游戏对象。现在,当积木与足球相撞时,它就可以工作了。但这最初是因为试图让块与 OVRPlayerController 发生碰撞。在这种情况下它仍然不起作用。有什么想法吗?

标签: unity3d oculus


【解决方案1】:

只要涉及到Rigidbody,您就应该设置

transform.position = Vector3.MoveTowards(...);

而是通过 Rigidbody 组件,例如使用MovePosition

Rigidbody.MovePosition 移动 Rigidbody 并符合插值设置。启用Rigidbody 插值后,Rigidbody.MovePosition 会在帧之间创建平滑过渡。

这样可以在通过transform.position 移动时保持物理不变,从而创建一个不会对碰撞做出反应的硬跳跃!

// If possible already reference this via the Inspector
[SerializeField] private Rigidbody _rigidbody;

public Rigidbody target;

private void Awake()
{
    if(!_rigidbody) _rigidbody = GetComponent<Rigidbody>();

    // Always when controlling your position by script the Rigidbody 
    // should be kinematic
    _rigidbody.isKinematic = true;
}

private void FixedUpdate ()
{
    _rigidbody.MovePosition(Vector3.MoveTowards(_rigidbody.position, target.position, Time.deltaTime * movespeed));
}

【讨论】:

  • 感谢您的回答。但是OVRPlayerController 在技术上没有Rigidbody,所以我不确定要添加什么作为目标。当我将目标设置为 OVRPlayerController 本身时,该块会与玩家“碰撞”,但会将玩家撞到太空中。并且OnCollisionEnter 仍然没有被调用。我的目标只是通过OnCollisionEnter 检测碰撞。
  • 我不希望它们发生物理碰撞,您可能更愿意使用OnTriggerEnter 并将另一个对撞机转为isTrigger
  • 呃,是的,使它成为触发器有效。我想我现在明白了。另外,我在OVRPlayerController 中添加了一个胶囊对撞机,并且让碰撞也能正常工作。我以前从未这样做过,因为这里的文档说它的字符控制器组件可能会受到开箱即用的碰撞的影响:developer.oculus.com/documentation/unity/unity-sf-distancegrab
  • @Frankie 它可能使用某种 Raycast 来确定您是否可以抓取与实际碰撞不同的东西
  • 您是正确的,它使用单独的球体碰撞器(在 ovrplayercontroller 的子对象上)作为触发器来检测项目是否在抓取范围内。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多