Saturday, January 28, 2012

Porting Unity3d's coroutines to Android/iOS

I have been quite away from Android development.
I have been coding a game for iOS: Shaman Doctor and now I am testing Unity3d.
This blog describes my wish to port that coroutines to other platforms.

Introduction

In Unity3d I am coding in C# and I learned about coroutines.
To give you an idea of how they work, check this blog posts:

Unity3d implementation for coroutines is somehow different.
To understand what I am saying, read the first link.
It gives an explanation of how it should be working inside Unity3d.

Usage
In the code where I use Unity3d coroutines is where I need to do a state machine code.
A super simple example would be:

Imagine you need to add a button but you can only click it once every two seconds.
I can imagine two possible implementations. Bare in mind that I didn't test this code.

Using time. objective-c code:

#define SECONDS_TO_ENABLE 2
@synthesize lastTimeUsed;

@implementation PotionController

- (id)init {
self = [super init];
if (self) {
self.lastTimeUsed = 0;
}

return self;
}

- (void)click {

NSTimeInterval now = [[NSDate date] timeIntervalSince1970];
NSTimeInterval difference = fabs(self.lastTimeUsed - now);

// if two seconds haven't pass, return.
if ( difference < SECONDS_TO_ENABLE ) {
return;
}

self.lastTimeUsed = now;

// Click logic here.
}

Disabling and sending an enable msg to be run after 2 seconds. Android code.

In this case it's a done with the View's postDelayed() method. It could be done
with a Handler as well.

public void click(final View view) {
view.setEnabled(false);

// Send a postDelayed to turn it on again.
view.postDelayed(new Runnable() {

@Override
public void run() {
view.setEnabled(True);
}

}, 2000L);

// Click logic here.
}

The same thing done with C# inside Unity3d would be:

void OnMouseDown() {
StartCoroutine(this.ClickLogic());
}

private IEnumerator ClickLogic() {
// Click Logic
yield return new WaitForSeconds(2.0f);
}

What happens when you click more than once in a two seconds time frame?
Honestly, I am not sure what happens when you call StartCoroutine() when
a previous coroutine was started, but it works.
I hope that someone can clarify this.

Now try to port this code from Unity3d to android or iOS.

IEnumerator TellMeASecret()
{
PlayAnimation("LeanInConspiratorially");
while(playingAnimation)
yield return null;

Say("I stole the cookie from the cookie jar!");
while(speaking)
yield return null;

PlayAnimation("LeanOutRelieved");
while(playingAnimation)
yield return null;
}

How can this be used in Android/iOS

Ordinary coroutines
Although Unity3d's coroutines are different from the ordinary, I wanted to know if it was possible to implement them in Android/iOS.

Android
My first google search about this was "java coroutines" and I learned that ordinary coroutines would need one of this options:
  • Modified JVMs (Can't be used in Android)
  • Modified Bytecode (Can't be used in Android)
  • Platform-specific JNI mechanisms (Not sure if it would work in Android)
  • Thread abstractions (Not sure how performant would work inside Android)
I feel this is a dead end for Android.

iOS

I didn't research a lot about iOS.
Here is a list of links that look interesting:

Unity3d implementation alike

After reading Richard Fine's blog post I thought it would be interesting to achieve something similar to that in the different platforms.
My big doubt is finding a way to implement something similar to an IEnumerator.

Using scala

Inside cocos2d-iphone
I am not sure if cocos2d's internal would support something like this.

Inside cocos2d-x
This is the real challenge.
Finding a way to implement Unity3d's coroutines but keeping it multiplatform.
Perhaps finding a way of doing it in C++.

What do you guys think?

2 comments:

  1. This comment has been removed by a blog administrator.

    ReplyDelete
  2. This comment has been removed by a blog administrator.

    ReplyDelete