ぐーるらいふ

しがないリーマンの記録。遊びのunityのメモ帳にしたい。

【Unity】C#初心者だけどUniRXを使えるようになりたい

github.com

uniRXいいですよね。
バリバリなUnity Developerって感じで。

とはいえ普段C#使わないレベルの初心者だと入りづらいのも事実で、
「そもそも使うメリットとかあるの?」
「余計わかりにくくなるだけじゃないの?」
なんて思ってたりもしました。

ちょっとググってみて、
「なんかチェーンでいい感じにスッキリ書けるみたい。」
「イベント駆動で処理を飛ばしたりと自由自在らしい。」
「MessageBrockerとかBufferとか便利みたいだけどどこで使えばいいのかよくわからん。」
なんて事も分かりました。

ちょっとお硬めなメリットとかはググった先の先人達の記事を参考にして頂くとして、
初心者の自分がどうやって使い始めたかだけメモとして書いてみようと思いました。

UpdateをUniRXで置き換えよう

void Update(){
}

unityでMonoBehaviorやってたら知ってますよね。
毎フレーム処理したい時に使うアレです。

これに処理を入れると

void Update(){
     if(_isFire){
          // 火を発生させる処理
          _isFire = false; // 終わったらフラグを下ろす
     }
     // その他処理
}

こんなん書くことがあると思います。

これを言葉で説明してみると
「ファイアフラグが立っている時だけUpdateで火の処理をしたい」
という感じになります。

おお。そうか。これをUniRXに置き換えてみると

using UniRX;
using UniRX.Triggers;

void Start(){
     this.UpdateAsObserbable().Where(_ => _isFire).Subscribe(_ => {
          // 火を発生させる処理
          _isFire = false; // 終わったらフラグを下ろす
     });
}

void Update(){
// もういらない
//     if(_isFire){
//         // 火を発生させる処理
//          _isFire = false; // 終わったらフラグを下ろす
//     }
     // その他処理
}

このように置き換えることが出来る。

とにかく void Update()は大きくなりやすい。
switchでstate切り分けたり、パラメータチェックしたり。
そのため、細かくメソッドに分けたり、処理を委譲させたりして
管理しやすくする涙ぐましい努力をしているのだけど、
その辺りを助けてくれるってわけだ。

開始アニメーション処理している時は…

     this.UpdateAsObserbable().Where(_ => _isStartAnimation).Subscribe(_ => {
          // アニメーションさせるとか
          _isStartAnimation = false; // 終わったらフラグを下ろす
     });

敵が残っている時は…

     this.UpdateAsObserbable().Where(_ => _enemies.Count > 0).Subscribe(_ => {
          // 敵が残っている時
     });

HPが0になった時は…

     this.UpdateAsObserbable().Where(_ => _player._hp < 1).Subscribe(_ => {
          // HPが0以下になったら
     });

とupdate処理をブロックごとに分けて書く事が出来る。

もちろん好き好きでは良いはずだ。
毎フレーム処理をしたいならvoid Update()に処理を書くのが最もシンプルで分かりやすい。
UniRXを使うとこう書けますよというだけだ。

ボタンイベントをUniRX化する

uGUI使ってたらButtonを使うこともあるはず。
普段なら

public void OnClickButton(){
     // ボタン押されたら
}

こんなん作って、Inspectorで紐付けるはずだ。
これもUniRXで置き換えて紐付けをやめてみよう。

[SerializableField]
private Button _joinButton:

_joinButton.OnClickAsObservable().Subscribe(_ =>{
     // ボタン押されたら
});

うーんスッキリ。だけどボタンだけは紐付けないとダメか。(GetComponent?)
Zenjectのidまで連携させればボタンの紐付けすらいらなくなるケド。

[Inject(id="join_button")]
private Button _joinButton:

これはちと微妙かも?
(Buttonみたいな汎用なクラスをInjectするのはやめておいたほうが良さそう)

勉強中

まだ使い始めたばかりなので、これから少しずつ使って慣れていきたい所。
次はイベントの送出を勉強したいな。
(GameManagerみたいな親がいて、EnemyControllerのような子クラスのイベントをフックする、的なやつ)

以下コードイメージ。イメージだよ!合ってませんよ!

// 敵が倒されたらその敵に紐付いているスコアを加算して表示する
_enemyController.EnemyDestroy(_ => enemy).Subscribe(e => {
          score += e.score;
          scoreText.text = "score : " + score;
});

こういうイメージ…今まではdelegateとか使ってたけどUniRXならこんな感じで書けるのでは…!?
ととりあえずここまで。出来たらまたメモしよう。