terminalCode Example
Async tasks in s&box — coroutines, parallel tasks, and frame-by-frame animation
Async Tasks in s&box Components
s&box async tasks run on the main thread — they behave like coroutines. Use Task.Frame() to yield one frame, Task.DelaySeconds() to wait, and Task.WhenAll() to run tasks in parallel.
Basic Async Method
CSHARP
async Task PrintAfterDelay( float seconds, string message )
{
await Task.DelaySeconds( seconds );
Log.Info( message );
}Frame-by-Frame Animation (Coroutine Pattern)
CSHARP
async Task LerpScale( float duration, Vector3 target, Easing.Function ease )
{
TimeSince elapsed = 0;
var from = WorldScale;
while ( elapsed < duration )
{
WorldScale = Vector3.Lerp( from, target, ease( elapsed / duration ) );
await Task.Frame();
}
WorldScale = target;
}
// Chain animations
await LerpScale( 0.3f, Vector3.One * 1.5f, Easing.EaseOut );
await LerpScale( 0.2f, Vector3.One, Easing.EaseIn );Parallel Tasks
CSHARP
async Task DoMultiple()
{
// Start both — no await yet
var taskA = PrintAfterDelay( 1f, "One" );
var taskB = PrintAfterDelay( 2f, "Two" );
// Wait for both to finish
await Task.WhenAll( taskA, taskB );
Log.Info( "Both done" );
}Returning Values
CSHARP
async Task<string> FetchData( string url )
{
return await Http.RequestStringAsync( url );
}
// From synchronous code — fire and forget
_ = FetchData( "https://example.com" );
// From synchronous code — use result when ready
FetchData( "https://example.com" )
.ContinueWith( t => Log.Info( t.Result ) );Calling Async from Synchronous Code
CSHARP
protected override void OnEnabled()
{
// Fire and forget — _ discards the Task
_ = DoMultiple();
}Checking Completion in OnUpdate
CSHARP
Task<string> _fetchTask;
protected override void OnStart()
{
_fetchTask = FetchData( "https://example.com" );
}
protected override void OnUpdate()
{
if ( _fetchTask?.IsCompletedSuccessfully == true )
{
Log.Info( _fetchTask.Result );
_fetchTask = null;
}
}Safety — Destroyed Components
Component.Task helpers (e.g. Task.Frame() called via the component) auto-cancel when the GameObject becomes invalid. For manually created tasks, check validity yourself:CSHARP
async Task SpawnWave()
{
await Task.DelaySeconds( 3f );
if ( !this.IsValid() ) return; // component was destroyed while waiting
SpawnEnemies();
}Common Pitfall — Stacking Tasks
If a player can trigger the same async task multiple times, guard against stacking:
CSHARP
bool _isFiring;
async Task Fire()
{
if ( _isFiring ) return;
_isFiring = true;
await Task.DelaySeconds( 0.5f );
ShootBullet();
_isFiring = false;
}
Was this helpful?