首页 > 解决方案 > 问题,OnCollisionStay 上的布尔冲突

问题描述

问题,当我按 E 来实例化 Hole 对象时,他们按 F 来实例化树,
即使玩家仍在与 Hole 碰撞,当我按 F 时,holeColliding 变为假。

公共类 CreateHole : MonoBehaviour {

public GameObject gameObject2;
public GameObject gameObject1;
public bool holeColliding;
public Transform playerPosition;
public bool facingRight1 = true;
public Vector3 holePosition;
public bool treeColliding;
void Update()
{
    facingRight1 = GetComponent<PlayerMovement>().facingRight;

    if (Input.GetKeyDown(KeyCode.E) && holeColliding == false && facingRight1 == true)
    {
        Instantiate(gameObject1, playerPosition.position + new Vector3(0.6f, -1f, 0f), Quaternion.identity);
    }
    else if (Input.GetKeyDown(KeyCode.E) && holeColliding == false && facingRight1 == false)
    {
        Instantiate(gameObject1, playerPosition.position + new Vector3(-0.6f, -1f, 0f), Quaternion.identity);
    }

    if (Input.GetKeyDown(KeyCode.F) && holeColliding == true && treeColliding == false)
    {
        Instantiate(gameObject2, holePosition + new Vector3(0f, 0.5f), Quaternion.identity);
    }
}

 void OnTriggerStay2D(Collider2D other)
 {
    if(other.tag == "Hole")
    {
        holePosition = other.transform.position;
        holeColliding = true;
        Debug.Log("true");
    }
    else
    {
        holeColliding = false;
        Debug.Log("false");
    }
    if(other.tag == "Tree")
    {
        treeColliding = true;
    }
    else
    {
        treeColliding = false;
    }
}

标签: c#unity3d

解决方案


gameObject2似乎没有被标记为“洞”,所以你elseOnTriggerStay套装holeColliding = false......

由于OnTriggerStay2D每帧都执行,但一次只针对一个 Collider,所以你的bools 总是一团糟! (不幸的是,API 并不清楚它是只为一个其他对象调用还是为每个对象调用,我假设/期待后者 - 但在这里并不重要)


我宁愿不使用重复OnTriggerStay2D,而是将其拆分为OnTriggerEnter2Dand OnTriggerExit2D。无论如何这是有道理的,否则你可以进入一个洞,离开它但holeCollidingtrue永远留下!

void OnTriggerEnter2D (Collider2D other)
{
    if(other.CompareTag("Hole"))
    {
        holePosition = other.transform.position;
        holeColliding = true;
        Debug.Log("true");
    }
    else if(other.CompareTag("Tree"))
    {
        treeColliding = true;
    }
}

void OnTriggerExit2D(Collider2D other)
{
    if(other.CompareTag("Hole"))
    {
        holeColliding = false;
    }
    else if(other.CompareTag("Tree"))
    {
        treeColliding = false;
    }
}

请注意,在上面的代码中,我建议宁愿使用CompareTag而不是直接将字符串与==. CompareTag如果提供的标签拼写错误或根本不存在,则抛出异常。一个“错误”会通过==简单地返回而默默地隐藏起来,这会false花费你的开发时间和精力;)


一般还有两点:

  • 永远不要使用或重复使用 - 这是一个非常昂贵的电话GetComponentUpdate而是存储一次引用并重用它!
  • 您检查了E两次输入,这也是多余的并且针头昂贵。因为在两个代码块中你做的几乎一样,你甚至可以使用?运算符来缩短它(这基本上是if - else当只以不同方式分配一个变量时的简写)

我会将您的代码修改为

// Best would be you already reference this via the Inspector
// Then you can skip the GetComponent completely
[SerializeField] private PlayerMovement playerMovement;

private void Awake ()
{
    // Otherwise get it at runtime and store it for later
    if(! playerMovement) playerMovement = GetComponent<PlayerMovement>();
}

void Update()
{
    // Now reuse the already stored reference
    facingRight1 = playerMovement.facingRight;

    if (Input.GetKeyDown(KeyCode.E) && !holeColliding)
    {
        // Since in both code blocks you do exactly the same
        // .. the only changing is a `-` you can shorten your code a lot
        var x = 0.6f * (facingRight1 ? 1 : -1);

        Instantiate(gameObject1, playerPosition.position + new Vector3(x, -1f, 0f), Quaternion.identity);
    }

    if (Input.GetKeyDown(KeyCode.F) && holeColliding && !treeColliding)
    {
        Instantiate(gameObject2, holePosition + Vector3.up * 0.5f, Quaternion.identity);
    }
}

推荐阅读