UniRxを勉強しよう7
は~~~~~~い
今日もやっていくぞ!
完成までの流れ
1. まずは簡単に見た目だけ作る
2. ボタンを押下した際にこれを検知する
3. 押下されたボタンから数値や記号を取得する
4. 引数に渡された数値がディスプレイに表示されるようにする
5. 検知した数値や記号から四則演算を実施できるようにする
6. 見てくれを整える
7. 書き出す
昨日は5を実現するためのフローチャートを作り、機能を考えるところで終わっていた。今日はその実装と微調整だ。
完成したものがこちらになります
まず概要だが、今回作成した電卓は大きく3つのスクリプト(クラス)で動作が決まっている。
1. PassPushedButton
電卓のボタンが押下されたことを検知する
2. ShowDisplayButton
電卓のディスプレイに値を表示する
3. Calcurater
計算の実処理を行う
まず一つ目!PassPushedButtonから
using System.Collections; using System.Collections.Generic; using UnityEngine; using UniRx; using System; using UnityEngine.UI; using System.Security.Cryptography.X509Certificates; using System.Threading; public class PassPushedButton : MonoBehaviour { [SerializeField] List<Button> buttons; [SerializeField] List<Button> operaterKeys; [SerializeField] List<Text> texts; //このクラスからOnNextで別クラスに処理を渡せるようSubjectを用意 private Subject<string> sendCalcSubject = new Subject<string>(); private Subject<int> sendOperaterSubject = new Subject<int>(); //なんだっけこれ…プロパティ?外部クラスからアクセス(getのみ)できるようにしておく public IObservable<string> KeyClicked { get { return sendCalcSubject; } } public IObservable<int> OperaterKeyClicked { get { return sendOperaterSubject; } } // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { } void Awake() { for (int i = 0; i < buttons.Count; i++) { ButtonCheck(i); } for(int i =0; i < operaterKeys.Count; i++) { OperatorKeyChecked(i); } } void ButtonCheck(int i) { buttons[i].onClick.AsObservable() .Subscribe(count => { //定義したSubjectからOnNextでメッセージを出す sendCalcSubject.OnNext(texts[i].text); }) .AddTo(gameObject); } void OperatorKeyChecked(int i) { operaterKeys[i].onClick.AsObservable() .Subscribe(count => { sendOperaterSubject.OnNext(i); }) .AddTo(gameObject); } }
次にShowDisplay。
using System.Collections; using System.Collections.Generic; using UnityEngine; using UniRx; using UnityEngine.UI; public class ShowDisplay : MonoBehaviour { //メッセージのやりとり対象はInspector画面から設定する。 public Text displayPanelText; private int operatorFlg = 0; [SerializeField] private PassPushedButton passPushedButton; [SerializeField] private Caculater calculater; // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { } void Awake() { //監視対象スクリプトからOnNextが飛んで来たら下記Subscribe処理を実行 passPushedButton.KeyClicked .Subscribe(KeyCode => ShowToDisPlay(KeyCode)) .AddTo(gameObject); calculater.CalculateResult .Subscribe(result => { displayPanelText.text = result; operatorFlg = 1; }) .AddTo(gameObject); } private void ShowToDisPlay(string value) { //演算記号が入力されたら一度ディスプレイをクリアする if (operatorFlg == 1) { displayPanelText.text = ""; operatorFlg = 0; } //入力値が少数点でなければ先頭の0は消す //else if (displayPanelText.text=="0" && value !=".") { displayPanelText.text = value; } else { displayPanelText.text += value; } } }
最後にCalcurater
using System.Collections; using System.Collections.Generic; using UnityEngine; using UniRx; using System; using UnityEngine.UI; public class Caculater : MonoBehaviour { //メッセージのやりとり対象はInspector画面から設定する。 public Text displayPanelText; [SerializeField] private PassPushedButton passPushedButton; private Nullable<double> calculatedValue; private Nullable<int> operationSymbol; private string displayText; private Subject<string> sendCalculateSubject = new Subject<string>(); public IObservable<string> CalculateResult { get { return sendCalculateSubject; } } // Start is called before the first frame update void Start() { } // Update is called once per frame void Update() { } void Awake() { //演算記号の入力を検知 passPushedButton.OperaterKeyClicked .Subscribe(operateKeyNum => Calculate(operateKeyNum)) .AddTo(gameObject); } private void Calculate(int newOperationSymbol) { displayText = displayPanelText.text; if (newOperationSymbol != 5) { //数値・演算記号が共に入力済みだったとき if (calculatedValue.HasValue && operationSymbol.HasValue) { //+ if (operationSymbol == 0) calculatedValue += double.Parse(displayText); //- if (operationSymbol == 1) calculatedValue -= double.Parse(displayText); //× if (operationSymbol == 2) calculatedValue *= double.Parse(displayText); //÷ if (operationSymbol == 3) calculatedValue /= double.Parse(displayText); //= if (operationSymbol == 4) calculatedValue = double.Parse(displayText); //今回入力された演算記号を格納 operationSymbol = newOperationSymbol; //AC(演算記号リセットのため、これだけ判定タイミングをずらす) if (operationSymbol == 6) { calculatedValue = 0; operationSymbol = null; } //showdisplayに計算結果を送信する sendCalculateSubject.OnNext(calculatedValue.ToString()); } else { calculatedValue = double.Parse(displayText); operationSymbol = newOperationSymbol; sendCalculateSubject.OnNext(calculatedValue.ToString()); } } //Cが入力されたとき、変数の値は書き換えずにディスプレイのみクリアする else sendCalculateSubject.OnNext("0"); } }
各コードについての解説をコメントで書いた。
今回はフローチャートを作成してからスクリプトを作成したのだが、これがとても楽しい…
先に色々考えておいて、コードを書いてみてカチッと動きがはまるとたまらん!(まあ適宜ロジック修正したけど)
期限は明日となっているのでコードをきれいに書きなおし、また見た目も整えていきたいと思う。