From 4d4466e8018adb3f52efcc43bf78ee839afe6414 Mon Sep 17 00:00:00 2001 From: neuecc Date: Mon, 8 Jun 2020 02:22:10 +0900 Subject: [PATCH] Add UniTask.WaitForFixedUpdate --- README.md | 18 ++++++---- .../Plugins/UniTask/Runtime/UniTask.Delay.cs | 16 +++++++++ src/UniTask/Assets/Scenes/SandboxMain.cs | 36 ++++++++++++++++--- 3 files changed, 60 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 9933bb1..a78c89c 100644 --- a/README.md +++ b/README.md @@ -72,13 +72,14 @@ async UniTask DemoAsync() await UniTask.Yield(PlayerLoopTiming.PreLateUpdate); // replacement of yield return null + await UniTask.Yield(); await UniTask.NextFrame(); // replacement of WaitForEndOfFrame(same as UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate)) await UniTask.WaitForEndOfFrame(); - // replacement of yield return new WaitForFixedUpdate - await UniTask.Yield(PlayerLoopTiming.FixedUpdate); + // replacement of yield return new WaitForFixedUpdate(same as UniTask.Yield(PlayerLoopTiming.FixedUpdate)) + await UniTask.WaitForFixedUpdate(); // replacement of yield return WaitUntil await UniTask.WaitUntil(() => isActive == false); @@ -92,9 +93,14 @@ async UniTask DemoAsync() // You can await standard task await Task.Run(() => 100); - // Multithreading, run on ThreadPool under this code(use SwitchToMainThread, same as `ObserveOnMainThreadDispatcher`) + // Multithreading, run on ThreadPool under this code await UniTask.SwitchToThreadPool(); + /* work on ThreadPool */ + + // return to MainThread(same as `ObserveOnMainThread` in UniRx) + await UniTask.SwitchToMainThread(); + // get async webrequest async UniTask GetTextAsync(UnityWebRequest req) { @@ -334,12 +340,12 @@ public enum PlayerLoopTiming It indicates when to run, you can check [PlayerLoopList.md](https://gist.github.com/neuecc/bc3a1cfd4d74501ad057e49efcd7bdae) to Unity's default playerloop and injected UniTask's custom loop. -`PlayerLoopTiming.Update` is similar as `yield return null` in 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 as `WaitForFixedUpdate`, `PlayerLoopTiming.LastPostLateUpdate` is similar as `WaitForEndOfFrame` in coroutine. +`PlayerLoopTiming.Update` is similar as `yield return null` in 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 as `WaitForFixedUpdate`, `PlayerLoopTiming.LastPostLateUpdate` is similar as `WaitForEndOfFrame` in coroutine. `yield return null` and `UniTask.Yield` is similar but different. `yield return null` always return next frame but `UniTask.Yield` return next called, that is, call `UniTask.Yield(PlayerLoopTiming.Update)` on `PreUpdate`, it returns same frame. `UniTask.NextFrame()` gurantees return next frame, this would be expected to behave exactly the same as `yield return null`. +> UniTask.Yield(without CancellationToken) is a special type, returns `YieldAwaitable` and run on YieldRunner. It is most lightweight and faster. + AsyncOperation is returned from native timing. For example, await `SceneManager.LoadSceneAsync` is returned from `EarlyUpdate.UpdatePreloading` and after called, loaded scene called from `EarlyUpdate.ScriptRunDelayedStartupFrame`. Also `await UnityWebRequest` is returned from `EarlyUpdate.ExecuteMainThreadJobs`. In UniTask, await directly and `WithCancellation` use native timing, `ToUniTask` use specified timing. This is usually not a particular problem, but with `LoadSceneAsync`, causes different order of Start and continuation after await. so recommend not to use `LoadSceneAsync.ToUniTask`. diff --git a/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.Delay.cs b/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.Delay.cs index 30fe4bb..bbdff39 100644 --- a/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.Delay.cs +++ b/src/UniTask/Assets/Plugins/UniTask/Runtime/UniTask.Delay.cs @@ -44,6 +44,22 @@ namespace Cysharp.Threading.Tasks return UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate, cancellationToken); } + /// + /// Same as UniTask.Yield(PlayerLoopTiming.FixedUpdate). + /// + public static YieldAwaitable WaitForFixedUpdate() + { + return UniTask.Yield(PlayerLoopTiming.FixedUpdate); + } + + /// + /// Same as UniTask.Yield(PlayerLoopTiming.FixedUpdate, cancellationToken). + /// + public static UniTask WaitForFixedUpdate(CancellationToken cancellationToken) + { + return UniTask.Yield(PlayerLoopTiming.FixedUpdate, cancellationToken); + } + public static UniTask DelayFrame(int delayFrameCount, PlayerLoopTiming delayTiming = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken)) { if (delayFrameCount < 0) diff --git a/src/UniTask/Assets/Scenes/SandboxMain.cs b/src/UniTask/Assets/Scenes/SandboxMain.cs index 8c2abe6..5de9373 100644 --- a/src/UniTask/Assets/Scenes/SandboxMain.cs +++ b/src/UniTask/Assets/Scenes/SandboxMain.cs @@ -267,11 +267,11 @@ public class SandboxMain : MonoBehaviour //cts.Cancel(); //await r; Debug.Log("SendWebRequestDone:" + PlayerLoopInfo.CurrentLoopType); - - // var foo = await UnityWebRequest.Get("https://bing.com/").SendWebRequest(); - // foo.downloadHandler.text; -// + + // var foo = await UnityWebRequest.Get("https://bing.com/").SendWebRequest(); + // foo.downloadHandler.text; + // _ = await UnityWebRequest.Get("https://bing.com/").SendWebRequest().WithCancellation(CancellationToken.None); Debug.Log("SendWebRequestWithCancellationDone:" + PlayerLoopInfo.CurrentLoopType); } @@ -358,11 +358,39 @@ public class SandboxMain : MonoBehaviour StartCoroutine(CoroutineRun()); } + async UniTaskVoid AsyncFixedUpdate() + { + while (true) + { + await UniTask.WaitForFixedUpdate(); + Debug.Log("Async:" + Time.frameCount + ", " + PlayerLoopInfo.CurrentLoopType); + } + } + + IEnumerator CoroutineFixedUpdate() + { + while (true) + { + yield return new WaitForFixedUpdate(); + Debug.Log("Coroutine:" + Time.frameCount + ", " + PlayerLoopInfo.CurrentLoopType); + } + } + + private void FixedUpdate() + { + Debug.Log("FixedUpdate:" + Time.frameCount + ", " + PlayerLoopInfo.CurrentLoopType); + } + void Start() { PlayerLoopInfo.Inject(); + _ = AsyncFixedUpdate(); + StartCoroutine(CoroutineFixedUpdate()); + + + okButton.onClick.AddListener(UniTask.UnityAction(async () => { /*