我正在学习C#和unity,我最近的一个问题是让我的OnTriggerEnter2D()函数工作。经过大量的测试,我设法解决了我的问题,但我不能百分之百地确定我是否理解。
所以基本上我是检查一个物体是否接触另一个物体,如果不是这样,我旋转这个物体:
for (var i = 0; i < 4; i++)
{
if (!door.connected)
{
go.transform.Rotate(0f, 0f, 90f, Space.Self);
}
}这个不起作用,经过大量的调试,我决定在go.transform.Rotate(0f, 0f, 90f, Space.Self);和这项工作之后立即使用一个延迟为0.5s的协程。
如果我是对的,这是因为延迟让我的OnTriggerEnter2D()函数有足够的时间来检测冲突,还是这与OnTriggerEnter2D()无关?如果是这种情况,那么每次我要检查碰撞时,我都需要使用协程?
编辑1:我在另一个脚本中有这段代码
public void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Door"))
{
this.connected = true;
}
}因此,前面的循环确实会让我的对象旋转,但永远不会将我的公共变量"connected“设置为true,就像碰撞永远不会发生一样,除非是在正确的位置产生的碰撞。但是,当我使用协程时,它确实可以工作,为什么?
发布于 2020-06-12 18:30:50
在OnTriggerEnter2D中旋转对象绝对不需要协程。
我想象一下,根据你展示的代码片段,它几乎立即将物体旋转了90度4次(这是一个完整的360度旋转),因此看起来它根本没有移动。
编辑(响应编辑1):
当你添加一个协程时,你的代码能够工作的原因是因为四个90度的旋转并不都发生在一个帧中。发生的情况是:
,
connected标志设置为true,从而防止在任何后续帧中调用go.transform.Rotate。将其与不带协程的序列进行比较,该序列将为:
它将门旋转90度,然后再旋转一次,然后,它移动到下一个frame.
connected标志仍为false。然而,问题的解决方案并不是使用协程。解决方案是删除您的for循环。在Update方法中,如果门未连接,则将其旋转一度。在下一次更新时,如果门仍然没有连接,请重新连接。最终,在4次更新中,它将连接在一起,并且不再旋转每一帧。
发布于 2020-06-12 18:43:47
如果我是对的,这项工作是因为延迟让我的OnTriggerEnter2D()函数有足够的时间来检测冲突,还是这与OnTriggerEnter2D()无关?
不,这和OnTriggerEnter2D没有任何关系。正如你所看到的,你的碰撞正在工作并被触发。
发生的是,你旋转4次,大约90°,在一帧内加起来是360°,=>,你会注意到没有区别。
Unity中的Coroutine基本上就是一个IEnumerator。在某些情况下,每个IEnumerator都使用yield关键字。所以Unity中的Coroutine基本上做的是:
每一帧调用给定IEnumerator上的MoveNext,直到它终止或到达下一条yield语句。(有一些特殊情况,例如WaitUntilEndOfFrame...)
所以翻译过来,你可以说yield的意思是
从这里开始,在下一帧中中断“routine
顺便说一句。你正在做什么,例如
yield return new WaitForseconds(3f);基本上等同于做像这样的事情
var timePassed = 0f;
while(timePassed < 3f)
{
yield return null;
timePassed += Time.deltaTime;
}所以:不,对于碰撞检测,你不需要使用,需要使用协程;而是,当你想要在多个帧上“扩展”一些代码执行时,你应该使用一个。
当您将OnTriggerEnter2D声明为IEnumerator时,Unity在内部所做的基本上等于以下内容
private void OnTriggerEnter2D(Collider2D other)
{
StartCoroutine(RotationAnimation());
}
private IEnumerator RotationAnimation()
{
// ...
}所以你还是要非常小心,不要得到并发的例程!
如果你想要的实际上是一个平滑的旋转,你可以使用
private bool alreadyRotating;
// adjust this via the Inspector
[SerializeField] float rotationAnglePerSecond = 90f;
private void OnTriggerEnter2D(Collider2D other)
{
// avoid concurrent routines
if(!alreadyRotating) StartCoroutine(RotationAnimation());
}
private IEnumerator RotationAnimation()
{
// block concurrent routine
if(alreadyRotating) yield break;
alreadyRotating = true;
var initialOrientation = go.transform.rotation;;
// rotate until you reach 360°
var rotated = 0f;
while(rotated < 360f)
{
// get amount of rotation within this frame
var rotate = Time.deltaTime * rotationAnglePerSecond;
go.transform.Rotate(0f, 0f, 90f);
rotated += rotate;
yield return null;
}
// reset to initial orientation
go.transform.rotation = initialOrientation;
// when done allow the next routine
alreadyRotating = false;
}https://stackoverflow.com/questions/62341901
复制相似问题