CrossRoad

XRを中心とした技術ブログ。 Check also "English" category.

非同期処理中にUnityAPIを使えるSpicyPixel Concurrency Kitのご紹介

<2017/4/28 追記:シンプルな使い方を追加しました>

これは、Unity2 Advent Calendar 2015の4日目の記事です。

3日目は、geekdrumsさんの「Unityで音楽同期したアニメーションを作る」でした。

本日は非同期処理向けのアセットを紹介します。

1. 前提:Unityのスレッドに関する考え方

Unityはシングルスレッドで動作します。非同期っぽい処理を作るには、コルーチンと呼ばれる方法を使います。これはUnityがフレーム毎に処理を行うときに、そこに混ぜることで擬似的にマルチスレッドのような概念を実現しています。

しかし、別スレッドで実行する処理が重いと、メインの処理速度にも影響が出てしまいます。

(実際、WWWクラスを使って待ち時間のかかる処理をさせたら、コルーチンを使っていても画面が固まったことがありました)

以上がUnityのスレッドに対する私の理解ですが、間違っていたらご指摘くださいm(_ _)m

このような問題を解決してくれるのが、Spicy Pixel Concurrency Kitというアセットです。

詳しい原理については理解できてませんが、この仕組みを使うと、マルチスレッドのような非同期処理が実現できます。

2. Spicy Pixel Concurrency Kitの使い方

まずはAssetStoreより入手し、Importします。代表的な処理例をc#で書いてみます。ここではdelegateを使って非同期処理を実現しています。

using SpicyPixel.Threading;
using SpicyPixel.Threading.Tasks;

public class TestClass : ConcurrentBehaviour {   /*(1)*/

delegate void ThreadFunction();/*(2)*/
static ThreadFunction threadFunction;/*(2)*/

public void asyncFunction(){
	threadFunction = new ThreadFunction(testFunction); /*(2)*/
	threadFunction.BeginInvoke(new AsyncCallback(functionOnAsync),DateTime.Now); /*(3)*/
}

private void functionOnAsync(){
/*非同期で実行したい処理を書く*/

/*Debug.Logなど、UnityAPIを含んだ関数を呼び出す*/
taskFactory.StartNew(functionWithUnityAPI()); /*(4)*/

}

private void CallbackAndShowContents(IAsyncResult ar){  /*(5)*/
/*コールバックを受けて実行したい処理を書く*/
}

(1) ConcurrentBehaviourクラスを継承

多くの場合は、MonoBehaviourですが、このアセットを使うとき、非同期処理したいクラスは、これをくっつけて宣言します。

(2) delegete宣言

SpicyPixel Concurrency Kitにとって必須ではありませんが、非同期処理実行のために使いました。
Threadクラスを呼ぶ方法でも大丈夫です。

(3) 非同期処理の開始

delegateを使うと、BeginInvokeメソッドの引数で宣言した関数が非同期で実行されます。

(4) 非同期処理中のUnityAPIの実行

本稿のメインはこれですね。非同期処理の中でUnityAPIを含んだ関数を呼ぶとき、taskFactory.Startnewメソッドの引数とします。

(5) コールバック関数

非同期処理が終わった時に呼ばれる関数です。この中に処理を書いておけば非同期処理の終了をきっかけに処理を続けることができます。

3. シンプルな使い方の例

(2017/4/28 追記しました)

シンプルな使い方を書けていなかったので、参考までに記載しました。例えば、WWWクラスを複数回呼び出したい、とします。


gistd830337b1932c5d3860b755065533119

ここのgetImage()ではyieldで戻り値を得るまで処理が止まります(同期のような挙動を示す)。

そのため、getImage()を複数回呼び出す、すなわちWWWクラスを複数回呼ばれるとUnityのシーン実行が著しく遅くなります。SpicyPixel Concurrency Kitを使うと、非同期的に処理を実行することができます。

このように、taskFactory.StartNewというメソッドの中に非同期にしたいメソッドを書くだけです。


gist800f9f784121e48fb11dc690e9b3bf11

4. 終わりに

ここで紹介したのは使い方の一例です。他にも色々ありますので、ご興味ある方は本家サイトのLearnをご参照ください。

明日はYOSHIOKA-Koさんによる、「uGUIのAnchorを使ったアニメーションの演出」です。