Share
Embed
Transcript
31 slides
-
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/ とか作ってます -
ゲーム以外の用途にも 映像の出力先としてのUnity VR(Oculus Rift)やNUI(Kinect, Leap Motion)などデバイスがあっ ても、何に表示するの?何を表現するの? そこの最有力候補としてのUnity 強力な開発環境、3D表現、AssetStore、そしてシェア 多くのデバイスがUnity用のSDKを用意している
メディアアート ProcessingやopenFrameworksなどのフィールドへ (期待) -
Unityの非同期 通信処理はyield returnで待機できる コールバック地獄にならない! すばら!すばら! と思ったことは一度もありません:) IEnumerator OnMouseDown() { var
www = new WWW("http://bing.com/"); yield return www; // これで待機 Debug.Log(www.text); } -
yieldの問題点 戻り値が返せない 例外処理ができない IEnumerator GetGoogle() { var www = new
WWW("http://google.com/"); yield return www; // 戻り値を返せない!!! www.text is どこ } void OnMouseDown() { // このコードはコンパイルエラー // yieldはtry-catchで囲めないので例外処理できない! try { yield return StartCoroutine(GetGoogle()); } catch { } } これにより処理が分離できないという問題が 発生する。一つのIEnumeratorにダラダラと書 き連ねるしかなくなってしまう -
あるいはコールバック 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で完了待機できるので多少マシだけどとはいえ酷い) -
C# 5.0(async/await)なら? 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; } } yield(await)が戻り値を返して受け取れる 例外がtry-catchできる 非同期メソッドが戻り値を返せる -
Unity 5.0 2014年秋ぐらいに多分リリース! Monoのバージョンは新しくなりません! つまりC#も古い(3.0)のままです! asyncは来ない!知ってた!この先も期待できない! Unity Feedback – Upgrade
to Mono 3.0 http://feedback.unity3d.com/suggestions/upgrade-to-mono-30 Mono 3.0でC# 5.0フィーチャー入る。Voteしよう。 Vote数的に、どーもUnityコミュニティ的にも中の人達的にも、言語 あんま重要視してない気配がする…… -
Reactive Programming #とは 近年注目のアーキテクチャスタイル 昔からあったといえばあったけど、原理原則やライブラリが充実し てきたので、最近一気に華開いた感ある The Rective Manifesto http://www.reactivemanifesto.org/
Reactive Streams http://www.reactive-streams.org/ Principles of Reactive Programming https://www.coursera.org/course/reactive Martin Odersky(Creator of Scala) Eric Meijer(Creator of Reactive Extensions) Roland Kuhn(Akka Tech Lead) -
Gartner’s Hype Cycle 2013 Application Architecture/Application Development On the Rise
- Reactive Programming -
Reactive Extensions .NETでのReactive Programmingライブラリ https://rx.codeplex.com Microsoftのプロジェクトだったけど現在はOSS化している LINQスタイルでイベントや非同期が処理できる 他言語への移植 RxJava(RxNetよりむしろ注目されてるぐらい) https://github.com/Netflix/RxJava
2070 Stars RxJS(Microsoft自身によるもの) https://github.com/Reactive-Extensions/RxJS 1021 Stars -
UnityRx - Reactive Extensions for Unity というのを作りました、本日公開! ほとんど(8割ぐらい)は自前で書いた 公式のRxはヘヴィすぎてUnityの古いC#で動かしきれない iOSはAOTの問題もあって回避頑張れる気がしない
ので自前で書くことに。 Available Now(?) GitHub - https://github.com/neuecc/UnityRx/ AssetStore – 準備中(数日中に出すので待ってて!) 無料! -
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()); -
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は、UnityRxに同梱しているRxの形式 にラップ済みのWWWクラスで通信可能なメソッドです -
UnityRx 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するだけでキャン セル可能、などなど、多種 のメソッドがマルチスレッ ド処理を支援する -
AsyncA AsyncB AsyncC Result AsyncA().SelectMany(a => AsyncB(a)) .Zip(AsyncC(), (b, c)
=> new { b, c }); SelectMany + Zip - 合成の例 -
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 -
Unity用の各支援メソッド // ObservableMonoBehaviour public class Hoge : ObservableMonoBehaviour { public
override void Awake() { // 全てのMessageEventがRxで扱う形式で取得できる var query = this.OnMouseDownAsObservable() .SelectMany(_ => this.OnMouseDragAsObservable()) .TakeUntil(this.OnMouseUpAsObservable()); } } // Observable.EveryFrame // 毎フレーム毎に値を発行する Observable.EveryFrame() .Subscribe(_ => Debug.Log(DateTime.Now.ToString())); -
Unity用の各支援メソッド // 入れ物を用意して public class LogCallback { public string Condition;
public string StackTrace; public UnityEngine.LogType LogType; } public static class LogHelper { public static IObservable<LogCallback> LogCallbackAsObservable() { var subject = new Subject<LogCallback>(); // callback内でSubjectに発行してあげるように作ることでRxにコンバート可能 UnityEngine.Application.RegisterLogCallback((condition, stackTrace, type) => { subject.OnNext(new LogCallback { Condition = condition, StackTrace = stackTrace, Log }); return subject; } } Unityに多くあるデリゲートによるコールバックを IObservable<T>に変換するとかなりイケテル! -
Unity用の各支援メソッド // 入れ物を用意して public class LogCallback { public string Condition;
public string StackTrace; public UnityEngine.LogType LogType; } public static class LogHelper { public static IObservable<LogCallback> LogCallbackAsObservable() { var subject = new Subject<LogCallback>(); // callback内でSubjectに発行してあげるように作ることでRxにコンバート可能 UnityEngine.Application.RegisterLogCallback((condition, stackTrace, type) => { subject.OnNext(new LogCallback { Condition = condition, StackTrace = stackTrace, Log }); return subject; } } // 各処理が分離して記述可能になる、また合成処理が可能、などのメリットあり LogHelper.LogCallbackAsObservable() .Where(x => x.LogType == LogType.Warning) .Subscribe(); LogHelper.LogCallbackAsObservable() .Where(x => x.LogType == LogType.Error) .Subscribe(); Unityに多くあるデリゲートによるコールバックを IObservable<T>に変換するとかなりイケテル! -
センサー is IObservable<T> IObservable<T>は時間軸上に並ぶシーケンス 詳しくはググッて私の適当な記事読んでください http://www.atmarkit.co.jp/fdotnet/introrx/index/ Kinect, Leap Motionなどなど は、イベントシーケンスとみなせてRxと相性が非常にいい!
というわけでUnityRxで扱ってみてください まだメソッド足りないかもなのでIssueに入れてもらうとうれすぃ -
まとめ IEnumeratorを非同期処理に使うのはいけてない そしてC# 5.0(async/await)は来ない! そこでUnityRx なぜTaskじゃなくてRxなのか? Taskはawaitがなければ機能的に弱くて使いやすくはない マルチスレッド処理やイベント処理など多数の機能も! Available Now(?)
GitHub - https://github.com/neuecc/UnityRx/ Assets/UnityRx下のコードが本体なのでそれを持って来れば動く AssetStore – 準備中(数日中に出すので待ってて!) 無料!