Your SlideShare is downloading. ×
未来のプログラミング技術をUnityで -UniRx-
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Saving this for later?

Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime - even offline.

Text the download link to your phone

Standard text messaging rates apply

未来のプログラミング技術をUnityで -UniRx-

0
views

Published on

UniRxを使えば「非同期処理」「イベント処理」「判定が複数フレームにまたがる処理」といった時間が絡んだ処理全般をとても簡単に記述できるようになります。今回はUniRxの便利な利用例をいくつか紹介したいと思います。

UniRxを使えば「非同期処理」「イベント処理」「判定が複数フレームにまたがる処理」といった時間が絡んだ処理全般をとても簡単に記述できるようになります。今回はUniRxの便利な利用例をいくつか紹介したいと思います。

Published in: Technology

0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
0
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
0
Comments
0
Likes
1
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. 未来のプログラミング技術をUnityで ~UniRx~ @toRisouP 2015/03/20
  • 2. スライド中に登場するサンプル http://torisoup.net/unirx-examples/ WebPlayer版 / Windows版 / Mac版と用意してあります
  • 3. 自己紹介 • とりすーぷ(@toRisouP) • 26歳 • 本業はWebエンジニア • 趣味でUnityでゲーム作ってます
  • 4. 過去に作ったもの 交通事故・渋滞シミュレータ (sm16238908) みくみくまうす (ニコ生配信支援ツール) NITORI BOX (東方2次創作ゲーム)
  • 5. みくみくまうす • ニコ生の配信支援ツール • MMDモデルがコメントを読み上げる • Unity製 • フリーソフトとして公開中 http://mikumikumouth.net/
  • 6. 今作ってるゲーム みこバト~レ • 東方2次創作の同人ゲーム • Unity + PhotonCloud • 例大祭と夏コミあたりで体験版出したい…
  • 7. ところで
  • 8. 「マウスのダブルクリック判定」 実装できますか?
  • 9. マウスのダブルクリック判定 • どうやって実装する? – 最後にクリックされてから一定時間以内ならダブルクリック? – クリック回数の変数とタイマの変数をフィールドに定義? – Update内に判定処理を書く?
  • 10. めんどい
  • 11. これをUniRxを使うと たったの数行で済みます
  • 12. たったのこれだけ!
  • 13. すごくね?
  • 14. 今回の発表の目標 実際の使用例を通して UniRxの凄さ便利さを伝えたい!
  • 15. ターゲット LINQは使えるレベルの人 プログラミング始めたばかりの人には少々厳しいかも
  • 16. 端折った説明や 厳密ではない説明をします ご了承ください (わかりやすさ第一で行きます)
  • 17. もくじ 1. UniRxって何? 2. UniRxって何が便利なの? 3. ストリームを使うメリットと例 4. よく使うオペレータ解説 5. Unity上での実用例5つ 6. まとめ
  • 18. UniRxって何?
  • 19. UniRx • Reactive Extensions for Unity • 作者は@neueccさん • MITライセンスで公開 • AssetStoreまたはgithubからダウンロード可
  • 20. Reactive Extensionsとは • FanctionalReactivePrograming をC#で実現するためのライブラリ – LINQ to Events – 元はMicrosoftReserchが開発 • 決してオレオレライブラリでは無い! • 最近になって流行の兆しが来ている – いろんな言語に移植されている • RxJS、RxJava、ReactiveCocoa、RxPy、UniRx… – どんな言語でもRxの考え方は共通している! • 覚えておいて損は絶対にしない!
  • 21. UniRxは何が便利なの?
  • 22. UniRxを使うと 時間の取り扱いが とても簡単になります
  • 23. 時間が絡んだ処理の例 • イベントの待ち受け – マウスクリックやボタン入力のタイミングで処理をする • 非同期処理 – 別スレッドで通信したり、重いファイルをロードさせたり • 時間計測が判定に必要な処理 – 長押し、ダブルクリックの判定 • 時間変化する値の監視 – False→Trueになった瞬間に1回だけ処理したい
  • 24. こういった処理をRxを使うと とても簡潔に記述できます
  • 25. まずはRxの基本的な 考え方を実際のコードを見せつつ 説明します
  • 26. ボタンがクリックされたら画面に表示する Buttonをクリックした時にTextに”Clicked”と表示してみる
  • 27. クリックされたら画面に表示するスクリプト ←メイン処理
  • 28. クリックされたら画面に表示するスクリプト ←Unity側が用意しているクリックイベント
  • 29. クリックされたら画面に表示するスクリプト ←イベントをストリームに変換
  • 30. クリックされたら画面に表示するスクリプト ←ストリームの購読 (最終的に何をするか書く)
  • 31. ストリーム • 「イベントが流れる配管」みたいなイメージ – 難しく言えば「時間軸上に並んだイベントのシーケンス」 – 分岐させたり合流させたりできる • コード中では IObservable<T> として扱われる – LINQで言うIEnumerable<T>に相当 イベントメッセージ イベントの流れそのものが「ストリーム」
  • 32. ストリームに流すイベント「メッセージ」 メッセージは3種類ある • OnNext – 通常使用するメッセージ – 普通はこれを使う • OnError – エラー発生時の例外を通知するメッセージ • OnCompleted – ストリームが終了した事を通知するメッセージ
  • 33. ボタンは 「クリック時にイベントをストリームに流している」 と考えることができる ストリームとボタンクリック Button ボタンがクリックされたタイミングで ストリームにメッセージを送り込む(OnNext)
  • 34. • ストリームの末端でメッセージが来た時に何をするかを定義する • ストリームはSubscribeされた瞬間に生成される – 基本的にSubscribeしない限りストリームは動かない – Subscribeのタイミングによって結果が変わる可能性がある • OnError, OnCompleteが来るとSubscribeは終了する Subscribe(ストリームの購読) Subscribe ストリームを購読して メッセージが来た時に処理をする ストリーム
  • 35. (補足)Subscribeとメッセージ Subscribeはオーバーロードで複数定義されているので用途に合わせて使う と良い • OnNextのみ • OnNext & OnCompleted • OnNext & OnError & OnCompleted
  • 36. 全体の流れ ← ボタンクリックイベントを ストリームに変換し メッセージが到着した時に テキストに”Clicked”を表示する
  • 37. Subscribeのタイミング Awake()/Start()でSubscribeするべき Update()に書くと無数のストリームが生成される
  • 38. ちなみに UniRxには、 uGUI用のObservableやSubscribeが準備されている ↑さっきの奴はこれくらい簡略化して書ける
  • 39. 「ストリーム」という考え方 のメリット
  • 40. イベントの 射影、フィルタリング、合成 などができる
  • 41.
  • 42. Buttonが3回押されたらTextに表示する • ボタンがクリックされた回数をカウントする? – カウンタ用の変数をフィールドに定義する?
  • 43. Buttonが3回押されたらTextに表示する • Buffer(3)を加えるだけ! – 余計なフィールド変数不要!
  • 44. Buffer • メッセージを蓄えて特定のタイミングで流す – 放出する条件はいろいろ指定できる • n個溜まったら流す • 別のストリームにメッセージが流れてきたら流す 画像はhttp://reactivex.io/documentation/operators/map.htmlより引用
  • 45. 例2
  • 46. Buttonが2つとも押されたらTextに表示する • 両方が交互に1回ずつ押された時にTextに表示する – 連打しても「1回押された」と判定させる
  • 47. Zip • 複数本のストリームのメッセージが全て揃うまで待つ – メッセージが揃った時に1個ずつ取り出して後続に流す – 揃ったメッセージは任意に加工して出力できる 画像はhttp://reactivex.io/documentation/operators/zip.htmlより引用
  • 48. Buttonが2つとも押されたらTextに表示する
  • 49. Buttonが2つとも押されたらTextに表示する ←1度動作した後にZip内のバッファをクリアする (後で説明します)
  • 50. Rxを使わない従来のやり方では、 イベントを受け取った後に どうするかを書いていた
  • 51. Rxでは イベントを受け取る前に 何をしたいかが書ける
  • 52. 「ストリームを加工して 自分が欲しいイベントだけ 通知させればいいじゃん!」
  • 53. まとめると、 Rxは 1.ストリームを用意して 2.ストリームをオペレータで加工して 3.最後にSubscribeする という考え方で使われる
  • 54. オペレータ ストリームをこねこねするもの
  • 55. オペレータ • ストリームに操作を加える関数のこと • メチャクチャたくさんある Select, Where, Skip, SkipUntil, SkipWhile, Take, TakeUntil, TakeWhile, Throttle, Zip, Merge, CombineLatest, Distinct, DistinctUntilChanged, Delay, DelayFrame, First, FirstOfDefault, Last, LastOfDefault, StartWith, Concat, Buffer, Cast, Catch, CatchIgnore, ObserveOn, Do, Sample, Scan, Single, SingleOrDefault, Retry, Repeat, Time, TimeStamp, TimeInterval…
  • 56. よく使うオペレータ紹介
  • 57. Where • 条件を満たすメッセージのみ通過させるオペレータ – 他の言語では「filter」とも呼ばれる 画像はhttp://reactivex.io/documentation/operators/filter.htmlより引用
  • 58. Select • 要素の値を射影(変換)する – 他の言語では「map」とも呼ばれる 画像はhttp://reactivex.io/documentation/operators/map.htmlより引用
  • 59. SelectMany • 新たなストリームを生成して、そのストリームが流すメッセージを本流のス トリームのメッセージとして扱う – ストリームを別ストリームで差し替えるイメージ(厳密に言うと違う) – 他の言語では「flatMap」とも呼ばれる 画像はhttp://reactivex.io/documentation/operators/flatmap.htmlより引用
  • 60. Throttle/ThrottleFrame • 落ち着いた時に最後のメッセージを流す – メッセージが集中して流れてきたら最後以外を無視する – 他の言語では「debounce」とも呼ばれる – よく使う 画像はhttp://reactivex.io/documentation/operators/debounce.htmlより引用
  • 61. Delay/DelayFrame • メッセージの伝達を遅延させる 画像はhttp://reactivex.io/documentation/operators/delay.htmlより引用
  • 62. DistinctUntilChanged • メッセージが変化した時のみ通知する – 同じ値が連続している場合は無視する 画像はhttp://rxmarbles.com/#distinctUntilChangedより引用
  • 63. SkipUntil • 指定したストリームにメッセージが来るまで メッセージをSkipする 画像はhttp://rxmarbles.com/#skipUntilより引用
  • 64. TakeUntil • 指定したストリームにメッセージが来たら、 自身のストリームにOnCompletedを流して終了させる 画像はhttp://rxmarbles.com/#takeUntilより引用
  • 65. TakeUntil • 指定したストリームにメッセージが来たら、 自身のストリームにOnCompletedを流して終了させる
  • 66. Repeat • ストリームがOnCompletedで終了した時にもう一度Subscribe を行う
  • 67. SkipUntil+TakeUntil+Repeat • よく使う組み合わせ – イベントAが来てからイベントBが来るまでの間だけ処理したいような 時に使う
  • 68. SkipUntil+TakeUntil+Repeatの例 例)ドラッグでオブジェクトを回転させる – MouseDownが来てからMouseUpが来るまで処理したい
  • 69. First • ストリームに最初に来たメッセージのみを流す – OnNextの直後にOnCompleteも流れる 画像はhttp://reactivex.io/documentation/operators/first.htmlより引用
  • 70. さっきのZipの例でFirst+Repeatを使った意図 First+Repeatで1回動作する度にストリームを作り直している (Zip内のメッセージキューをリセットするため)
  • 71. ここまでが基礎 基礎の説明だけでスライド70枚突破してる
  • 72. ここから実例を紹介
  • 73. 実際の使用例5つ 1. ダブルクリック判定 2. 値の変動を監視する 3. 値の変動を丸める 4. WWWを使いやすくする 5. PhotonCloudと組み合わせる
  • 74. 1.ダブルクリック判定
  • 75. ダブルクリック検知のコード
  • 76. クリックストリームの定義 クリックのストリームを定義(≠生成)
  • 77. クリックストリーム UpdateAsObservable() Updateのタイミングを通知 Where() クリックがあったフレームのみ通過 clickStream クリックイベントのストリーム
  • 78. よくみると2つのストリームがある
  • 79. よくみると2つのストリームがある
  • 80. 意味 クリックストリームを塞き止めてまとめる。 開放条件は「最後にクリックされてから200ミリ秒経過した時」である。
  • 81. クリックストリーム clickStream マウスクリックのストリーム Throttle(200ms) 200ms間イベントが 起きなかったら通知 200ms Buffer イベントをまとめる 終了条件はThrottle イベントが来るまで 3 1 2
  • 82. 2.値の変動を監視する
  • 83. プレイヤが着地した瞬間にエフェクトを再生する
  • 84. 着地した瞬間の検知方法 1. CharacterController.isGroundedを毎フレーム監視 2. 現フレームにおける値をフィールド変数に保存 3. 次フレームでFalse → Trueに変わった時にエフェクトを再生する
  • 85. UniRxを使わずに着地した瞬間の検知をしてみる
  • 86. UniRxを使わずに着地した瞬間の検知をしてみる パッと見で何やってるか判断できない! ←一時保存用のためだけのフィールド変数!!
  • 87. UniRxで着地した瞬間の検知をしてみる
  • 88. UniRxで着地した瞬間の検知をしてみる ここだけ! フィールド変数なんぞいらん!
  • 89. 着地判定のイメージ図 F F F T T T T F F F T F T UpdateAsObservable() Updateのタイミングを通知 Select() IsGroundedの値に差し替え DistinctUntilChanged() 値に変化があった時のみ通過 Where() 値がTrueの時のみ通過 Subscribe() isGroundedがFalse→Trueになった瞬間が通知される
  • 90. 3.値の変動を丸める
  • 91. isGroundedの変動を丸める • isGroundedの精度の改善 – 斜面を移動するとTrue/Falseが激しく変動する – この値の変動をUniRxで抑えこんでみる
  • 92. 方針 • isGroundedの変動をThrottleで無視させる – DistinctUntilChangedと併用すればOK
  • 93. UniRxでisGroundedの変動を丸める
  • 94. isGroundedの丸め込みイメージ図 T F T T T T T T T T T UpdateAsObservable() Updateのタイミングを通知 Select() IsGroundedの値に差し替え DistinctUntilChanged() 値に変化があった時のみ通過 ThrottleFrame(5) 値が5フレームの間 来なかったら最後の値を放流 Subscribe() isGroundedが6フレーム以上 安定していた時に最後の値が通知される F T 1 2 3 4 5
  • 95. 4.WWWを使いやすくする
  • 96. UnityのWWW • Unityの標準のHTTP通信用モジュール – コルーチンとして使う必要があり – そこまで使い勝手は良くない(HttpWebRequestよりはだいぶマシだけどさ…)
  • 97. ObservableWWW • WWWをObservableとして扱えるようにしたもの – Subscribeされた瞬間に通信が行われる – 後は勝手に裏で通信して結果がストリームに流れてくる – コルーチンとか考えなくて良い
  • 98. 例)ボタンが押されたらテクスチャを読み込む • ボタンが押されたら指定URLのテクスチャ画像をダウンロード してImageに表示する
  • 99. WWWでテクスチャ読み込み
  • 100. WWWでテクスチャ読み込み クリックストリームをObservableWWWの ストリームで上書きする ←ボタンを連打されても通信は1回しかさせないためにFirstを入れる
  • 101. WWWでテクスチャ読み込み 複雑なことも上から読めば何やってるかすぐわかる 1. ボタンがクリックされたら 2. HTTPでテクスチャ画像をダウンロードして 3. その結果をSpriteに変換し 4. Imageとして表示する
  • 102. タイムアウトを付け加える タイムアウトが欲しいならここにオペレータを挟むだけ
  • 103. ObservableWWWでいろいろ • 同時に通信して全てデータが揃ったら処理を進める
  • 104. ObservableWWWでいろいろ • 前の通信の結果を使って次の通信を行う – サーバに「リソースへのURL」を問い合わせて、サーバに教えてもらっ たURLからデータをダウンロードする resourcepath.txtの中に書かれたURLへアクセスするコード
  • 105. 5.Photon Cloudと組み合わせる
  • 106. PhotonCloud • Unityで簡単にネットワーク対戦が実装できるライブラリ • 通知が全てコールバックで微妙に使い勝手が悪い – UniRxでなんとかしたい
  • 107. • PhotonCloudのコールバックがストリームに変換される – ごちゃごちゃしたコールバックは隠蔽される UniRxと組み合わせると? PhotonCloud コールバックで ごちゃごちゃした世界 最新の部屋情報の通知ストリーム ロビー参加に成功した通知 ストリーム 部屋に参加成功した通知 ストリーム UniRxでコールバックを隠蔽
  • 108. コールバックからストリームに変換するメリット • IDEの補完が効くようになる – PhotonのコールバックはSendMessageで呼び出される – Observableとしてちゃんと定義してあげれば補完が効く • 多様なオペレータによる柔軟な制御ができるようになる – ログインに失敗したら3秒後にリトライ試すとか – 全員からレスポンスがあった時に処理をするとか – 部屋情報リストが更新されたことを通知するとか
  • 109. コールバックからストリームに変換するメリット • IDEの補完が効くようになる – PhotonのコールバックはSendMessageで呼び出される – Observableとしてちゃんと定義してあげれば補完が効く • 多様なオペレータによる柔軟な制御ができるようになる – ログインに失敗したら3秒後にリトライ試すとか – 全員からレスポンスがあった時に処理をするとか – 部屋情報リストが更新されたことを通知するとか
  • 110. 例)最新の部屋情報を通知するストリームを作る • OnRevicedRoomListUpdateコールバック – PhotonNetwork.GetRoomList()が更新された時に実行される – これをストリームにしてしまう
  • 111. つまりこういう形にしたい 最新のRoomInfo[]が流れるストリーム これをSubscribeしておけば、 部屋リストに更新があったことがすぐわかる
  • 112. ストリームの根源の作り方 • Observableのファクトリメソッドを使う • 既存のイベント等から変換する • Subject<T>系を使う • ReactiveProperty<T>を使う
  • 113. ReactiveProperty • Subscribeすることができる変数 • ObservableとしてSubscribeができる • 値を書き込んだ時にOnNextメッセージが飛ぶ
  • 114. ReactivePropertyで部屋情報を通知する
  • 115. ReactivePropertyで部屋情報を通知する OnRecivedRoomListUpdateのタイミングで _reactiveRoomsの値を書き換え、同時にストリームに通知が飛ぶ
  • 116. ReactivePropertyで部屋情報を通知する Observableとしてクラスの外に公開
  • 117. 受信側(さっきと同じスライド) コールバック地獄からの開放!
  • 118. 紹介したい機能は まだまだたくさんある
  • 119. これ以上話すと さすがに詰め込み過ぎなので ココらへんで終わります (というか既に詰め込み過ぎ)
  • 120. 補足スライドも用意してあるので そちらも見てね
  • 121. まとめ • UniRxは便利なので使ってみよう!!!!!!!! – 「時間」をすごい簡単に扱えるようになる – GUI周りの実装もスッキリ書ける – ゲームロジックに適用することもできる • UniRxは便利だが難しい面もある – 学習コストが高くて概念的にも難しい – 導入する場合はプログラムの設計から考え直す必要が出てくる • 真価を発揮させるには設計の根幹にUniRxがガッツリ食い込む • 「便利ライブラリ」ではなく「言語拡張」だと思う必要がある
  • 122. ちなみに • 歌舞伎座Tech #7 「Reactive Extensions」 – Rxに興味を持った方は参加されてみては? – http://kbkz.connpass.com/event/12597/
  • 123. ありがとうございました @toRisouP
  • 124. 以下補足とか
  • 125. 参考にするとよいサイト • ReactiveX – http://reactivex.io/ – Rxについて細かく解説されているサイト(ただし英語) • Reactive extensions入門v0.1 – http://www.slideshare.net/okazuki0130/reactive-extensionsv01 – @okazukiさんがまとめてくれたRxについての日本語資料 – すごいよくまとまっているので1度目を通すべし
  • 126. 補足)Subject<T> • ストリームの根源を作るもの – Subject,ReplySubject,BehaviorSubject,AsyncSubjectと複数種類あり – 外に公開するときは必ずAsObservableを挟んで公開する • 外から直接OnNextが叩ける状態にしない
  • 127. • Disposeを呼び出すとSubscribeが中止される – ストリームの根源が削除されると自動的にDisposeされる – ストリームが終了状態になってもDisposeされる – staticなストリームを作った場合は手動Disposeが必要 補足)Subscribeの止め方 button.onClickで作ったストリームは Buttonがシーンから削除されたタイミングでDisposeされる
  • 128. 補足)UpdateAsObservableとObservable.EveryUpdate どちらもUpdate()のタイミングを通知してくれるObservable • UpdateAsObservable – ObservableMonoBehaviour を継承すると使える – IObservable<Unit> – コンポーネントのDestory時に自動Disposeされる • Observable.EveryUpdate – どのスクリプトからでも使える – IObservable<long> (Subscribeした時からのフレーム数) – 使い終わったら明示的にDisposeする必要がある • またはOnCompleteがちゃんと発火するストリームにする
  • 129. おまけ
  • 130. おまけ)コルーチンをObservableに変換する • Observable.FromCoroutineを使うと変換できる – コルーチンの実行順序や実行条件をストリームで定義できる コルーチンAが終わったらコルーチンBを実行する例
  • 131. おまけ)UniRx+コルーチン • FromCoroutine<T>を使うと自由なストリームが作れる カウントダウンタイマの例
  • 132. 続き)カウントダウンタイマを作るのなら… • ただしFromCoroutine<T>でカウントダウンタイマを作るよりも Observable.Timerで作った方がスマート
  • 133. おまけ)HttpWebRequest を使ってPUT/DELETE • WWW/ObservableWWWはGETとPOSTのみサポート – PUT/DELETEを使いたい場合HttpWebRequestを使う必要がある • HttpWebRequestをそのまま使うとそこそこツライ – 同期処理で書くとスレッドを分離する必要がある – 非同期処理で書くのも結構めんどくさい
  • 134. おまけ)UniRxでHttpWebRequest • HttpWebReqeustでDELETEを叩く – Observable.Startを使えば別スレッドで実行できる – それをObserveOnでメインスレッドに戻す
  • 135. おまけ)ObserveOn • 処理を行うスレッドを切り替えるオペレータ – ObserveOnを使えばスレッド間でのデータのやり取りを考慮する必要 は無い
  • 136. 応用例)テキスト入力された時に検索サジェストを出す 1. InputFiledにテキストが入力された時に 2. 最後に入力されてから200m秒以上間隔が開いたら 3. GoogleSuggestAPIを叩いて 4. その時のサジェスト結果をTextに表示する
  • 137. 応用例)テキスト入力された時に検索サジェストを出す