Skip to content

Commit

Permalink
Merge pull request #496 from Cysharp/hadashiA/awaitable
Browse files Browse the repository at this point in the history
Add EndOfFrame implementation using `UnityEngine.Awaitable`
  • Loading branch information
hadashiA committed Sep 14, 2023
2 parents 90c5e5a + ffbadbc commit acc7155
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 1 deletion.
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,13 @@ async UniTask<string> DemoAsync()
await UniTask.Yield();
await UniTask.NextFrame();

// replacement of WaitForEndOfFrame(requires MonoBehaviour(CoroutineRunner))
// replacement of WaitForEndOfFrame
#if UNITY_2023_1_OR_NEWER
await UniTask.WaitForEndOfFrame();
#else
// requires MonoBehaviour(CoroutineRunner))
await UniTask.WaitForEndOfFrame(this); // this is MonoBehaviour
#endif

// replacement of yield return new WaitForFixedUpdate(same as UniTask.Yield(PlayerLoopTiming.FixedUpdate))
await UniTask.WaitForFixedUpdate();
Expand Down Expand Up @@ -497,6 +502,8 @@ It indicates when to run, you can check [PlayerLoopList.md](https://gist.github.
`PlayerLoopTiming.Update` is similar to `yield return null` in a coroutine, but it is called before Update(Update and uGUI events(button.onClick, etc...) are called on `ScriptRunBehaviourUpdate`, yield return null is called on `ScriptRunDelayedDynamicFrameRate`). `PlayerLoopTiming.FixedUpdate` is similar to `WaitForFixedUpdate`.

> `PlayerLoopTiming.LastPostLateUpdate` is not equivalent to coroutine's `yield return new WaitForEndOfFrame()`. Coroutine's WaitForEndOfFrame seems to run after the PlayerLoop is done. Some methods that require coroutine's end of frame(`Texture2D.ReadPixels`, `ScreenCapture.CaptureScreenshotAsTexture`, `CommandBuffer`, etc) do not work correctly when replaced with async/await. In these cases, pass MonoBehaviour(coroutine runnner) to `UniTask.WaitForEndOfFrame`. For example, `await UniTask.WaitForEndOfFrame(this);` is lightweight allocation free alternative of `yield return new WaitForEndOfFrame()`.
>
> Note: In Unity 2023.1 or newer, `await UniTask.WaitForEndOfFrame();` no longer requires MonoBehaviour. It uses `UnityEngine.Awaitable.EndOfFrameAsync`.
`yield return null` and `UniTask.Yield` are similar but different. `yield return null` always returns next frame but `UniTask.Yield` returns next called. That is, call `UniTask.Yield(PlayerLoopTiming.Update)` on `PreUpdate`, it returns same frame. `UniTask.NextFrame()` guarantees return next frame, you can expect this to behave exactly the same as `yield return null`.

Expand Down
7 changes: 7 additions & 0 deletions src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.Delay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ public static UniTask NextFrame(PlayerLoopTiming timing, CancellationToken cance
return new UniTask(NextFramePromise.Create(timing, cancellationToken, out var token), token);
}

#if UNITY_2023_1_OR_NEWER
public static async UniTask WaitForEndOfFrame(CancellationToken cancellationToken = default)
{
await Awaitable.EndOfFrameAsync(cancellationToken);
}
#else
[Obsolete("Use WaitForEndOfFrame(MonoBehaviour) instead or UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate). Equivalent for coroutine's WaitForEndOfFrame requires MonoBehaviour(runner of Coroutine).")]
public static YieldAwaitable WaitForEndOfFrame()
{
Expand All @@ -86,6 +92,7 @@ public static UniTask WaitForEndOfFrame(CancellationToken cancellationToken)
{
return UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate, cancellationToken);
}
#endif

public static UniTask WaitForEndOfFrame(MonoBehaviour coroutineRunner, CancellationToken cancellationToken = default)
{
Expand Down

0 comments on commit acc7155

Please sign in to comment.