More Related Content Similar to UniRx - Reactive Extensions for Unity (20) More from Yoshifumi Kawai (15) UniRx - Reactive Extensions for Unity2. Self Introduction
@仕事
株式会社グラニ 取締役CTO
C# 5.0 + .NET Framework 4.5 + ASP.NET MVC 5
最先端C#によるハイパフォーマンスWebアプリケーション
@個人活動
Microsoft MVP for Visual C#
Web http://neue.cc/
Twitter @neuecc
linq.js - http://linqjs.codeplex.com/ とか作ってます
8. yieldの問題点
戻り値が返せない
例外処理ができない
IEnumerator GetGoogle()
{
var www = new WWW("http://google.com/");
yield return www;
// 戻り値を返せない!!! www.text is どこ
}
IEnumerator OnMouseDown()
{
// このコードはコンパイルエラー
// yieldはtry-catchで囲めないので例外処理できない!
try
{
yield return StartCoroutine(GetGoogle());
}
catch
{
}
}
これにより処理が分離できないという問題が
発生する。一つのIEnumeratorにダラダラと書
き連ねるしかなくなってしまう
9. あるいはコールバック
IEnumerator GetGoogle(Action<string> onCompleted, Action<Exception> onError)
{
var www = new WWW("http://google.com/");
yield return www;
if (!www.error) onError(new Exception(www.error));
else onCompleted(www.text);
}
IEnumerator OnMouseDown()
{
string result;
Exception error;
yield return StartCoroutine(GetGoogle(x => result = x, x => error = x));
string result2;
Exception error2;
yield return StartCoroutine(GetGoogle(x => result2 = x, x => error2 = x));
}
結局コールバック地獄かよ!
(yieldで完了待機できるので多少マシだけどとはいえ酷い)
10. async Task<string> RunAsync()
{
try
{
var v = await new HttpClient().GetStringAsync("http://google.co.jp/");
var v2 = await new HttpClient().GetStringAsync("http://google.co.jp/");
return v + v2;
}
catch (Exception ex)
{
Debug.WriteLine(ex);
throw;
}
}
C# 5.0(async/await)なら?
yield(await)が戻り値を返して受け取れる
例外がtry-catchできる
非同期メソッドが戻り値を返せる
16. UniRx - Reactive Extensions for Unity
というのを作りました、本日公開!
ほとんど(8割ぐらい)は自前で書いた
公式のRxはヘヴィすぎてUnityの古いC#で動かしきれない
iOSはAOTの問題もあって回避頑張れる気がしない
ので自前で書くことに。
Available Now(?)
GitHub - https://github.com/neuecc/UniRx/
AssetStore(無料)
http://u3d.as/content/neuecc/uni-rx-reactive-extensions-for-
unity/7tT
18. RxによるUnityの非同期通信
// xが完了したらそれでy、完了したらzのダウンロードの連鎖のフローをLINQクエリ式で
var query = from x in ObservableWWW.Get("http://google.co.jp/")
from y in ObservableWWW.Get(x)
from z in ObservableWWW.Get(y)
select new { x, y, z };
// Subscribe = "最後に全部まとまったあとの"コールバック(ネストしないから処理が楽)
query.Subscribe(x => Debug.Log(x), ex => Debug.LogException(ex));
// もしくはCoroutineに変換して待機も可能(ToCoroutine is yieldable!)
yield return StartCoroutine(query.Do(x => Debug.Log(x)).ToCoroutine());
19. etc, etc....
// AとBを同時並列に走らせて一個にまとめる
var query = Observable.Zip(
ObservableWWW.Get("http://google.co.jp/"),
ObservableWWW.Get("http://bing.com/"),
(google, bing) => new { google, bing });
// エラーが起きたらリトライ処理を入れる
var cancel = ObservableWWW.Get("http://hogehgoe")
.OnErrorRetry((Exception ex) => Debug.LogException(ex),
retryCount: 3, delay: TimeSpan.FromSeconds(1))
.Subscribe(Debug.Log);
// キャンセルしたい場合は戻り値のDisposeを呼ぶだけ
cancel.Dispose();
// などなど、100近くの演算子をメソッドチェーン形式で繋げることができる
// あらゆる実行フローを完全にコントロールできる
ところでObservableWWWは、
UniRxに同梱されている、Rxの
形式にラップ済みのWWWクラ
スで通信可能なメソッドです
21. UniRx solves MultiThreading problems
// なんか重たい処理を別スレッドで開始するStartメソッド
var heavyMethod1 = Observable.Start(() =>
{
Thread.Sleep(TimeSpan.FromSeconds(3));
return 1;
});
var heavyMethod2 = Observable.Start(() =>
{
Thread.Sleep(TimeSpan.FromSeconds(3));
return 1;
});
// Zipで両方並列に走らせながら連結して
heavyMethod1.Zip(heavyMethod2, (x, y) => new { x, y })
.ObserveOnMainThread() // MainThreadに戻す!
.Subscribe(x =>
{
(GameObject.Find("myGuiText")).guiText.text = x.ToString();
});
他スレッドと待ち合わせ
MainThreadに戻して、そ
れ以降のフローは
GameObjectにアクセス可
能にする
ObserveOnMainThread
Subscribe後の戻り値を
Disposeするだけでキャン
セル可能、などなど、多種
のメソッドがマルチスレッ
ド処理を支援する
24. var asyncQuery = from a in AsyncA()
from b in AsyncB(a)
from c in AsyncC(a, b)
select new { a, b, c };
多重from(SelectMany)
AsyncA AsyncB AsyncC Result
27. Unity用の各支援メソッド
// 入れ物を用意して
public class LogCallback
{
public string Condition;
public string StackTrace;
public UnityEngine.LogType LogType;
}
public static class LogHelper
{
static Subject<LogCallback> subject;
public static IObservable<LogCallback> LogCallbackAsObservable()
{
if (subject == null)
{
subject = new Subject<LogCallback>();
// callback内でSubjectに発行してあげるように作ることでRxにコンバート可能
UnityEngine.Application.RegisterLogCallback((condition, stackTrace, type) =>
{
subject.OnNext(new LogCallback { Condition = condition, StackTrace = stackTrace, LogType = ty
});
}
return subject.AsObservable();
}
}
Unityに多くあるデリゲートによるコールバックを
IObservable<T>に変換するとかなりイケテル!
28. Unity用の各支援メソッド
// 入れ物を用意して
public class LogCallback
{
public string Condition;
public string StackTrace;
public UnityEngine.LogType LogType;
}
public static class LogHelper
{
static Subject<LogCallback> subject;
public static IObservable<LogCallback> LogCallbackAsObservable()
{
if (subject == null)
{
subject = new Subject<LogCallback>();
// callback内でSubjectに発行してあげるように作ることでRxにコンバート可能
UnityEngine.Application.RegisterLogCallback((condition, stackTrace, type) =>
{
subject.OnNext(new LogCallback { Condition = condition, StackTrace = stackTrace, LogType = ty
});
}
return subject.AsObservable();
}
}
Unityに多くあるデリゲートによるコールバックを
IObservable<T>に変換するとかなりイケテル!
// 各処理が分離して記述可能になる、また合成処理が可能、などのメリットあり
LogHelper.LogCallbackAsObservable()
.Where(x => x.LogType == LogType.Warning)
.Subscribe();
LogHelper.LogCallbackAsObservable()
.Where(x => x.LogType == LogType.Error)
.Subscribe();