Unity 在没有 IsTrigger 的情况下使用 OnCollisionEnter2D 检测碰撞

Posted

技术标签:

【中文标题】Unity 在没有 IsTrigger 的情况下使用 OnCollisionEnter2D 检测碰撞【英文标题】:Unity Detecting Collisions With OnCollisionEnter2D Without IsTrigger 【发布时间】:2018-11-06 04:45:51 【问题描述】:

我正在尝试创建一个可以将玩家从一端带到另一端的门户。因此,如果玩家从一端进入传送门的 50%,他的另外 50% 将从另一端伸出。

我正在使用具有完全相同组件的完全相同精灵的两个预制角色。门户将仅使用这两个预制角色,而不是证实新的克隆。

下图描述了我试图用碰撞盒来移动它们:

澄清一下,我正在使用 OnCollisionEnter2D 检测接触点,以确定玩家从门户的哪一侧进入。如上图右侧所示,“进来的人”应该可以随时转身不被撤走,而从另一边离开时仍然可以被撤走。

但是,我的代码面临的问题是 OnCollisionEnter2D 函数仅在 IsTrigger 为 false 时才有效。但是当 IsTrigger 为 false 时,我的角色无法通过传送门并被推入地面并从地图上掉下来。

我尝试使用 Physics2D.IgnoreCollision,但似乎没有效果。

第二个被移动到出口传送门的角色被推出而不是平滑过渡。

public Transform PortalExit;
public CharacterController2D Player;

private GameObject Player1;
private CharacterController2D Player1Controller;
private Vector2 Player1Position;
private GameObject Player2;
private CharacterController2D Player2Controller;
private Vector2 Player2Position;

// Use this for initialization
void Start () 
    Player1 = GameObject.FindWithTag("Player1");
    Player1Controller = GameObject.FindWithTag("Player1").GetComponent<CharacterController2D>();
    Player1Position = Player1.transform.position;
    Player2 = GameObject.FindWithTag("Player2");
    Player2Controller = GameObject.FindWithTag("Player2").GetComponent<CharacterController2D>();
    Player2Position = Player2.transform.position;


// Update is called once per frame
void Update () 



void OnCollisionEnter2D (Collision2D collision) 

    Collider2D collider = collision.collider;

    if (collider.gameObject.tag == "Player1") 

        Vector3 contactPoint = collision.contacts[0].point;
        Vector3 center = collider.bounds.center;

        bool right = contactPoint.x > center.x;
        bool top = contactPoint.y > center.y;

        if (right) 
            // Physics2D.IgnoreCollision(GameObject.FindWithTag("Player1").GetComponent<Collider2D>(), GetComponent<Collider2D>());

            // change Player2's position into the other portal
            print("Hello!");
            Player2Position.x = 1.6f;
            Player2Position.y = PortalExit.position.y;
            Player2.transform.position = Player2Position;
        

        if (!right) 
            print("Goodbye!");
            // puts Player1 into the detention center
            Player1Position.x = -5.55f;
            Player1Position.y = -6f;

            Player1.transform.position = Player1Position;
        

    

    if (collider.gameObject.tag == "Player2") 

        Vector3 contactPoint = collision.contacts[0].point;
        Vector3 center = collider.bounds.center;

        bool right = contactPoint.x > center.x;
        bool top = contactPoint.y > center.y;

        if (!right) 
            // change Player2's position into the other portal
            Player1Position.x = -3.6f;
            Player1Position.y = PortalExit.position.y;
            Player1.transform.position = Player1Position;
        

        if (right) 
            // puts Player1 into the detention center
            Player2Position.x = -5.55f;
            Player2Position.y = -6f;

            Player2.transform.position = Player2Position;
        

    

【问题讨论】:

我最近在我的赛车游戏的检查站和部分终点试验了用于高速计时器的 2D 边缘对撞机。它们非常准确。比我预期的要多得多。我认为他们会遇到隧道问题和缺少高速交互。他们没有。它们可以完全像无限厚的 2D 形状一样使用。这意味着您可以在角色的最边缘使用它们来确定他相对于门户的位置,并在他完全通过时发出信号,在任一方向。垂直使用它们,连接到角色的边缘。有意义吗? @Confusde 对不起,我不明白你的建议...... 我需要画一些照片...你能等一下吗?我将在接下来的几天内为我自己的项目做一些事情,这样我就可以画出非常具体的东西了。 我的是隐形传送,有些效果需要同时出现在两个地方。尽管有传送,粒子、轨迹效果、声音和其他东西仍需要继续,因为它是一圈末端传送,它应该是无缝的并且对玩家来说是不明显的。所以我们有相似的需求,原因却大相径庭。 好的!我很高兴看到你的照片。 【参考方案1】:

你有两个选择:

1。将 isTrigger 更改为 false,然后从编辑器或通过脚本将 Rigidbody2D Body Type 从 Dynamic 更改为 Kinematic:

rb2d.bodyType = RigidbodyType2D.Kinematic;

通过这样做,刚体将停止对重力或来自其他物体的力作出反应。然后,您可以使用您的OnCollisionEnter2D 来检测碰撞事件,而不会出现您问题中描述的问题。


2。将 isTrigger 更改为 true,将 Rigidbody2D Gravity Scale 设置为 0,这样它就不会穿过地面。现在,您可以使用OnTriggerEnter2D 检测触发点,使用Physics2D.Raycast 伪造检测点,因为OnTriggerEnter2D 无法提供碰撞点:

void OnTriggerEnter2D(Collider2D collision)

    //Calculate layermask that excludes this GameObject we are raycasting from
    int layerMask = ~(1 << gameObject.layer);

    float distance = 100f;

    // Cast a ray straight down.
    RaycastHit2D hit = Physics2D.Raycast(transform.position, transform.forward, distance, layerMask);

    if (hit.collider != null)
    
        Collider2D collider = hit.collider;

        Vector3 contactPoint = hit.point;
        Vector3 center = collider.bounds.center;


        //...........
    

我建议你两个都试试,看看你最喜欢哪一个。

【讨论】:

非常感谢您的帮助!我尝试使用选项 1。虽然检测点工作得很好,但我的角色无法通过对撞机。因为它是一个传送门,我需要一个平稳的过渡,所以我的角色需要能够通过它。我还尝试使用选项 2。由于我不确定它的作用,我将代码直接粘贴到我的脚本中,但 if 语句根本不执行。但至少这个选项可以让我的角色通过。

以上是关于Unity 在没有 IsTrigger 的情况下使用 OnCollisionEnter2D 检测碰撞的主要内容,如果未能解决你的问题,请参考以下文章

unity3d OncollisionEnter2d检测不到碰撞,而且勾了isTrigger也无法穿过

是否可以在没有 BackgroundWorker 的情况下使 WinForms 响应? [关闭]

如何在没有固定高度的情况下使动态div溢出

在没有更多上下文的情况下使表达式类型模棱两可

在没有更多上下文的情况下使表达式类型模棱两可

如何在没有单击事件的情况下使特定的 TabItem 获得对 TabControl 的关注?