Constructs allowed in an async method
The body of work that spans frames can contain loops, branches, calls to other methods, and event sends, combined with await. Local variables keep their values across a suspension.
Forms that compile (12)
Section titled “Forms that compile (12)”| Syntax | Description | Note |
|---|---|---|
while (running) { ...; await Async.Frames(60); } | while loops | |
foreach (GameObject lamp in lamps) | foreach loops | In this example, the elements of lamps are enabled one at a time, every 5 frames. |
for (y ...) { for (x ...) { ... } await Async.Frame(); } | Nested loops | |
if (items[i] < 0) continue; | break and continue | An iteration skipped by continue never reaches the await, so it consumes no frame. |
if (slow) { await Async.Frames(120); } else { await Async.Frame(); } | Branching with if | The statement after the branch runs once the wait has finished, whichever branch was taken. |
case 0: await Async.Frame(); done = 1; break; | Branching with switch | A default that contains no await does not suspend and finishes within the same frame. |
if (skip) return; | Return partway through | |
int[] work = new int[8]; await Async.Frame(); | Local arrays | |
level = Step(level); | Calling a method | The callee does not suspend; it runs to completion at the point of the call. |
SendCustomEvent(nameof(Bump)); | Sending events | |
SendCustomNetworkEvent(NetworkEventTarget.All, nameof(Chime)); | Network events | Only the sender counts the wait; the receiver runs after the network latency on top of that. |
phase = 1; RequestSerialization(); | Updating a synced field | Only the owner sends the value with RequestSerialization() (Sync). |
while loops
Section titled “while loops”A while loop can contain await.
using UnityEngine;using Tsukimi;
public class ParFlowWhile : TsukimiBehaviour{ public bool running; public int ticks;
private async FrameTask Pulse() { while (running) { ticks = ticks + 1; await Async.Frames(60); } }
void Start() { running = true; Pulse(); }}foreach loops
Section titled “foreach loops”A foreach over an array can contain await.
using UnityEngine;using Tsukimi;
public class ParFlowForeach : TsukimiBehaviour{ public GameObject[] lamps;
private async FrameTask LightUp() { foreach (GameObject lamp in lamps) { lamp.SetActive(true); await Async.Frames(5); } }
public override void Interact() { LightUp(); }}Nested loops
Section titled “Nested loops”In nested loops, the whole inner loop can run in one frame, with a suspension on each iteration of the outer loop.
using UnityEngine;using Tsukimi;
public class ParFlowNested : TsukimiBehaviour{ public int[,] grid; public int sum;
private async FrameTask Total() { for (int y = 0; y < grid.GetLength(0); y++) { for (int x = 0; x < grid.GetLength(1); x++) { sum += grid[y, x]; } await Async.Frame(); } }
public override void Interact() { Total(); }}break and continue
Section titled “break and continue”break and continue work in a loop that contains await.
using UnityEngine;using Tsukimi;
public class ParFlowBreakContinue : TsukimiBehaviour{ public int[] items; public int sum;
private async FrameTask Scan() { for (int i = 0; i < items.Length; i++) { if (items[i] < 0) continue; if (items[i] > 100) break; sum += items[i]; await Async.Frame(); } }
public override void Interact() { Scan(); }}Branches
Section titled “Branches”Branching with if
Section titled “Branching with if”if and else can each contain an await with a different frame count.
using UnityEngine;using Tsukimi;
public class ParFlowBranch : TsukimiBehaviour{ public bool slow; public int done;
private async FrameTask Run() { if (slow) { await Async.Frames(120); } else { await Async.Frame(); } done = done + 1; }
public override void Interact() { Run(); }}Branching with switch
Section titled “Branching with switch”A case in a switch can contain await.
using UnityEngine;using Tsukimi;
public class ParFlowSwitch : TsukimiBehaviour{ public int mode; public int done;
private async FrameTask Run() { switch (mode) { case 0: await Async.Frame(); done = 1; break; case 1: await Async.Frames(30); done = 2; break; default: done = 3; break; } }
public override void Interact() { Run(); }}Return partway through
Section titled “Return partway through”A return before the await finishes in that frame without suspending.
using UnityEngine;using Tsukimi;
public class ParFlowEarlyReturn : TsukimiBehaviour{ public bool skip; public int done;
private async FrameTask Run() { if (skip) return; await Async.Frames(10); done = done + 1; }
public override void Interact() { Run(); }}Carrying values across
Section titled “Carrying values across”Local arrays
Section titled “Local arrays”An array created locally with new keeps its contents across a suspension.
using UnityEngine;using Tsukimi;
public class ParFlowArrayAcross : TsukimiBehaviour{ public int total;
private async FrameTask Fold() { int[] work = new int[8]; for (int i = 0; i < work.Length; i++) { work[i] = i * i; } await Async.Frame(); for (int i = 0; i < work.Length; i++) { total += work[i]; } }
public override void Interact() { Fold(); }}Calling a method
Section titled “Calling a method”A method without [MaxTasks] can be called both before and after a suspension.
using UnityEngine;using Tsukimi;
public class ParFlowCallMethod : TsukimiBehaviour{ public int level;
private int Step(int v) { return v + 1; }
private async FrameTask Climb() { level = Step(level); await Async.Frame(); level = Step(level); }
public override void Interact() { Climb(); }}Notifying the outside
Section titled “Notifying the outside”Sending events
Section titled “Sending events”SendCustomEvent can be called both before and after a suspension.
using UnityEngine;using Tsukimi;
public class ParFlowSendEvent : TsukimiBehaviour{ public int hits;
public void Bump() { hits = hits + 1; }
private async FrameTask Knock() { SendCustomEvent(nameof(Bump)); await Async.Frames(30); SendCustomEvent(nameof(Bump)); }
public override void Interact() { Knock(); }}Network events
Section titled “Network events”SendCustomNetworkEvent can be sent after an await.
using UnityEngine;using VRC.Udon.Common.Interfaces;using Tsukimi;
public class ParFlowNetworkEvent : TsukimiBehaviour{ public int chimes;
public void Chime() { chimes = chimes + 1; }
private async FrameTask Delay() { await Async.Frames(90); SendCustomNetworkEvent(NetworkEventTarget.All, nameof(Chime)); }
public override void Interact() { Delay(); }}Updating a synced field
Section titled “Updating a synced field”Assigning to a [UdonSynced] field and calling RequestSerialization() can be repeated with a suspension in between.
using UnityEngine;using Tsukimi;
public class ParFlowSynced : TsukimiBehaviour{ [UdonSynced] public int phase;
private async FrameTask Advance() { phase = 1; RequestSerialization(); await Async.Frames(60); phase = 2; RequestSerialization(); }
public override void Interact() { Advance(); }}