どうもトミです。
先日、(2022年3月)人生始めて自作のゲームをApple Storeでリリースできました!(888888)本当に嬉しいですね。自力でどこまでやれるかを試したくて始めたゲーム制作ですが、何も目標なしでは途中で投げ出してしまうのではないかと思い、ゲームの品質はどうであれ絶対にリリースするぞと決めてやりました。正直最初のゲームですし、一人では能力にも限界があるのであれもこれもと拘りだしたら終わる気がしないので、「何が何でも絶対にリリースする」という明確な目標があるお陰であまり迷わず最後までやりきれたと思います。
さて今回のゲーム制作からリリースまで一通りやったことで自分には何ができるか、逆に何ができない(足りない)かは明確に分かったことが非常に良かったです。自分に足りないことを補うために新しいことをインプットして更に成長していくことが重要だと思います。プログラミングにおいてはまだまだスマートなコードが書けないと思って以前から気になっているUniRxを本気で勉強しようと思います。
早速ですがAmazonで「UniRx/UniTask完全理解」という本を購入しました。
ネット上で色々探してみましたが、UniRx関連の書籍はあまり出ていなくて、私が買った本以外にもう一冊「Unityゲーム プログラミング・バイブル」という本にUniRxの章が設けられていて、どちらがいいかは迷っていましたが、最終的な決め手となったのは「網羅的、且つ本格的にUniRxについて勉強できるか」という点です。
「Unityゲーム プログラミング・バイブル」はUniRxというよりはUnityでゲームを作る上で必要な知識を各章に分けて勉強できる本になっています。言ってしまえば広く浅く勉強できるようになっています。Unityでゲームを作る上でどんな知識が必要なのかを系統的に知りたい方には良書だと思います。非常に分厚い本になっていますし、値段も張ってますが気になる方は下のリンクから覗いてみてください。
ちなみに「UniRx/UniTask完全理解」も「Unityゲーム プログラミング・バイブル」のUniRxの章も、どちらも同じ作者になっています。
前置きが長くなりましたが私がこの本でインプットした内容を私の理解を基に軽く紹介したいと思います。
UniRxとはなにか
ゲーム上のあらゆるイベントを監視して、それらのイベントの発生したタイミングでやりたい処理を行う。その一連の流れ(監視から処理まで)を繋げてやることで簡潔でまとまったロジックを目指すことが可能です。
ここでいうイベントとは、例えばUpdateやFixedUpdate、OnCollisionEnterなどUnityのイベント関数であったり、Button.OnClick()やTrigger.OnValueChanged()などuGUIコンポーネントのイベントであったり、StateMachineBehaviourのイベントであったり、とあらゆるイベントを監視できます。
イベントを監視する以外にも、コルーチンとの連携で例えば、yield returnの値を受け取って処理できるなど、使い方を工夫すれば今まで難しかった処理をシンプルに書くことができるメリットがあります。
UniRxの使い方のイメージ(処理の流れ)
先に断っておきますが、UniRxには本当に沢山のObservableの生成方法とOperatorの種類が豊富ですべては同じような使い方ではないことに注意してほしいです。ここではあくまでUniRxに対して全く知識のない状態で、如何にイメージしやすいかに注力して説明したいと思います。
さて使い方(処理の流れ)は概ね
- Observableを生成し、イベントを監視する
- Operatorを挟んで発火したメッセージを操作する(フィルタリングなど)
- Subscribeで(Operatorによってフィルタリングや変換した)メッセージの内容を処理する
非常に非常にシンプルにまとめると以上のような流れになっています。
UniRxの便利な使い方
コルーチンのyield returnした値を受け取って処理する
using System.Collections;
using UniRx;
using UnityEngine;
public class FromCoroutineValueTest : MonoBehaviour
{
void Start()
{
Observable.FromCoroutineValue<int>(GetLevelCoroutine, false)
.Subscribe(
// yield returnで返したレベルを受け取って処理する、ここではDebug.Logで出力しています
level => Debug.Log(level)
// すべて正常に処理し終わった後に呼ばれます
, () => Debug.Log("OnCompleted")
);
}
private IEnumerator GetLevelCoroutine()
{
// レベルの配列
var levels = new[]
{
1,2,3,4,5
};
foreach (var level in levels)
{
yield return level;
}
}
}
ダブルクリックを検知する
using System;
using UniRx;
using UniRx.Triggers;
using UnityEngine;
public class DoubleClickUseBuffer : MonoBehaviour
{
private void Start()
{
// UpdateのObservableを生成し、クリックイベントを検知する
var mouseDown =
this.UpdateAsObservable().Where(_ => Input.GetMouseButtonDown(0));
mouseDown
// 最後にクリックされてから500msの間マウスクリックがなかったときに
// これまでクリックした回数が2回だったらダブルクリックしたと判定する
.Buffer(mouseDown.Throttle(TimeSpan.FromMilliseconds(500)))
.Where(x => x.Count == 2)
.Subscribe(_ => Debug.Log("ダブルクリックされました"));
}
}
ボタンクリックされるまで処理を待つ
using System.Collections;
using UniRx;
using UnityEngine;
using UnityEngine.UI;
public class ToYieldInstructionTest : MonoBehaviour
{
[SerializeField] Button _button;
// Start is called before the first frame update
void Start()
{
StartCoroutine(HogeCoroutine());
}
private IEnumerator HogeCoroutine()
{
while (true)
{
// Buttonが押されるまで待つ
yield return _button
.OnClickAsObservable()
.Take(1)
.ToYieldInstruction();
// 押されたらなにか処理を行う
Debug.Log("Do Someting");
}
}
}
最後に
以上で紹介した使い方はいずれもUniRxだからできる方法です。このように本来であれば、bool型のフラグなどを用意してそれぞれのイベントで監視しながらバラバラだった処理をひとまとめにしてより自然な流れで表現できるのはUniRxの大きなメリットだと思います。他にも沢山の便利な使い方があります。
「UniRx/UniTask完全理解」では、UniRxの導入方法から使い方まで、具体例を用いて詳細に説明しています。「どう使うか」、「使い所」のヒントを提供してくれる一冊だと思いますので、これからUniRxを本格的に勉強したい方は是非、手にとってほしい一冊です!UniRxを習得してより柔軟なコードが書けるように一緒に頑張りましょう!
初めて作ったゲーム「Poor Hero」
iOSの方はダウンロードしていただけると嬉しいです。
コメント