[英]Unity Coroutine Wait Until true for x seconds
我想實現類似於yield return new WaitUntil(() => Check());
的東西。 , 但有一個額外的補充。 在滿足Check()
條件后,如果條件仍然為真,它應該等待 x 秒檢查每一幀。
這是我的實現:
private IEnumerator CheckCor(float waitTime)
{
bool checkFlag = true;
bool checkFlag2;
float whileTime;
while (checkFlag)
{
yield return new WaitUntil(() => Check());
checkFlag2 = true;
whileTime = waitTime;
while (whileTime > 0)
{
if (!Check())
{
checkFlag2 = false;
}
whileTime -= Time.deltaTime;
yield return null;
}
if (checkFlag2)
{
checkFlag = false;
}
}
}
Check()
在哪里
private bool Check();
我的實現工作得很好,但似乎有點長。
有沒有更短的方法來實現相同的行為?
(也使其通用將是一個加號,例如yield return WaitUntilForSeconds(Check(), 3f);
,其中 Check() 是條件,而 3f 是檢查每一幀條件的時間。我猜它可以使用CustomYieldInstruction
,但我不確定它是如何工作的。)
將其實現為CustomYieldInstruction
並不算太糟糕。 將檢查器作為Func<bool>
傳入,保留一個標志以記住您是否已啟動計時器,並在檢查 function 在任何時候返回 false 時重置該標志。 您甚至可以接受Func<float>
在計時器重置時調用剩余時間:
using UnityEngine;
public class WaitUntilForSeconds: CustomYieldInstruction
{
float pauseTime;
float timer;
bool waitingForFirst;
Func<bool> myChecker;
Action<float> onInterrupt;
bool alwaysTrue;
public WaitUntilForSeconds(Func<bool> myChecker, float pauseTime,
Action<float> onInterrupt = null)
{
this.myChecker = myChecker;
this.pauseTime = pauseTime;
this.onInterrupt = onInterrupt;
waitingForFirst = true;
}
public override bool keepWaiting
{
get
{
bool checkThisTurn = myChecker();
if (waitingForFirst)
{
if (checkThisTurn)
{
waitingForFirst = false;
timer = pauseTime;
alwaysTrue = true;
}
}
else
{
timer -= Time.deltaTime;
if (onInterrupt != null && !checkThisTurn && alwaysTrue)
{
onInterrupt(timer);
}
alwaysTrue &= checkThisTurn;
// Alternate version: Interrupt the timer on false,
// and restart the wait
// if (!alwaysTrue || timer <= 0)
if (timer <= 0)
{
if (alwaysTrue)
{
return false;
}
else
{
waitingForFirst = true;
}
}
}
return true;
}
}
}
然后,您可以使用
yield return new WaitUntilForSeconds(Check, 3f);
// or
yield return new WaitUntilForSeconds(Check, 3f, (float t) => {Debug.Log($"Interrupted with {t:F3} seconds left!");});
如果您需要檢查器的參數,您可以使用無參數 lambda:
yield return new WaitUntilForSeconds(() => Check(Vector3.up), 3f);
而且,與 lambda 一樣,請注意您所做的任何變量捕獲。
如果您不想要整個CustomYieldInstruction
,我會使用另一個WaitUntil
來暫停:
private IEnumerator CheckCor(float waitTime)
{
bool stillWaiting = true;
while (stillWaiting)
{
yield return new WaitUntil(() => Check());
float pauseTime = waitTime;
yield return new WaitUntil(() =>
{
pauseTime -= Time.deltaTime;
stillWaiting = !Check();
return stillWaiting || pauseTime <= 0;
});
if (stillWaiting)
{
// Stuff when pause is interrupted goes here
}
}
// Stuff after pause goes here
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.