[disclaimer]


This is a personal blog. The opinions expressed here represent my own and not those of any of my employers or customers.

Except if stated otherwise, all the code shared is reusable under a MIT/X11 licence. If a picture is missing a copyright notice, it's probably because I'm owning it.

Thursday, March 14, 2013

Await in the Land of iOS - Collisions in Chipmunk

Note: this blog post follows the ones of Frank Krueger about the alpha release of mono 3.x for Xamarin.iOS bringing .NET 4.5 features to the mobile world: Drag-n-drop and Scripting Users. Read that first, it's worth it.

The old way!

If you're using the Chipmunk bindings, the correct way to handle collisions between shapes is to register 4 (FOUR!) handlers for the different steps: begin, preSolve, postSolve and separate. Your collision handling logic is then spread in 4 different functions. All of that for the same collision.



bool Begin (Arbiter arb)
{
 Console.WriteLine ("began");
 return true;
}

bool PreSolve (Arbiter arb)
{
 Console.WriteLine ("presolved");
 return true;
}

void PostSolve (Arbiter arb)
{
 Console.WriteLine ("postsolved");
}

void Separate (Arbiter arb)
{
 Console.WriteLine ("separated");
}
It would be great, for the sake of simplicity, if we could group the logic altogether.

await to the rescue

C# 5 (in .NET 4.5) allows just that. Procedural code in the form of:

await began;
Console.WriteLine ("BEGAN");
await presolved;
Console.WriteLine ("PRESOLVE");
await postsolved;
Console.WriteLine ("POSTSOLVE");
await separated;
Console.WriteLine ("SEPARATED");

All this, ran into an infinite loop:

async void WaitForCollisions ()
{
 using (var waiter = new AsyncCollisionWaiter (space, WALL, CHARACTER)) {
  for(;;) {
   var began = waiter.GetBeginAsync ();
   var presolved = waiter.GetPreSolveAsync ();
   var postsolved = waiter.GetPostSolveAsync ();
   var separated = waiter.GetSeparateAsync ();

   await began;
   Console.WriteLine ("BEGAN");
   await presolved;
   Console.WriteLine ("PRESOLVE");
   await postsolved;
   Console.WriteLine ("POSTSOLVE");
   await separated;
   Console.WriteLine ("SEPARATED");
  }
 }
}

The magic lies in the AsyncCollisionWaiter. Here's a quick implementation for it

Caveats

There's a 5-10 ms delay between the moment the result for the Task is set and the moment the awaiting function is resumed. That means nothing in most cases, but means A LOT when you're simulating physics. That means the separated event happens before the process resumes after the await began. That's why we have to Get*Async() all the events we're interested into before waiting for the first one.

Due to that delay as well, we loose the ability to decide in a timely manner if we want this collision to happen or not. That's why I unconditionally return true from Begin and PreSolve in the AsyncCollisionWaiter.

So what ?

Frank got me excited with his series of post. I wanted to apply the same process to my own stuffs. Although the code looks nicer, you're paying a high price for that beauty, and all the value of having 4 events is kinda ruined by the delay. In this case, a single collisionHappened would have been enough.
Have fun experimenting with await in your own mobile application too.

No comments:

Post a Comment