UniRxを勉強しよう5

はい。なんか前日に書いた内容が投稿できずに終わっていることが多い。多分眠くて公開するのを忘れていたのだろう…
今回は前回作成したOnNextで発されたメッセージを取得するクラスから、GUI上のディスプレイに数値を表示させてみたいと思う。

出来上がったものがこちらです。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniRx;
using UnityEngine.UI;

public class ShowDisplay : MonoBehaviour
{
    //メッセージのやりとり対象はInspector画面から設定する。
    public Text displayPanelText;
    [SerializeField] private PassPushedButton passPushedButton;

    // Start is called before the first frame update
    void Start()

    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    void Awake()
    {
        //監視対象スクリプトからOnNextが飛んで来たら下記Subscribe処理を実行
        passPushedButton.KeyClicked
            .Scan((pre, current) => pre + current)
            .Subscribe(KeyCode => ShowToDisPlay(KeyCode));
    }

    private void ShowToDisPlay(string value)
    {
        if(value.Substring(0,1) == "0")
        {
            value = value.Substring(1, value.Length - 1);
        }
        displayPanelText.text = value;
    }
}

画面は以下のような感じだ。

f:id:dkkng:20200720233132p:plain
入力値が画面に表示されている。これだけで大分それっぽいな

最初に0が入力されていた場合はそれを消した文字列を取得するようにしている。
今の状態だと「+」「÷」といった記号類もここに表示してしまうため、それが入力された場合の処理を別途記入する必要がある。

これについてもif文の中でやってもよいのだが、せっかくなので演算記号は別途Subjectでイベントを取得するようにしてみようと思う。まあ基本的に前回書いた処理の焼き直しなのでそんなに難しくない。

演算記号用に書いてみよう

まずボタンの押下を検知するクラス。
数値(小数点含む)を押した場合と演算記号を押した場合とで別のSubjectからOnNextが発される。

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);
    }
}

そしてそれを受けてディスプレイの表示を変更するクラスがこちら

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniRx;
using UnityEngine.UI;

public class ShowDisplay : MonoBehaviour
{
    //メッセージのやりとり対象はInspector画面から設定する。
    public Text displayPanelText;
    [SerializeField] private PassPushedButton passPushedButton;

    // Start is called before the first frame update
    void Start()

    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    void Awake()
    {
        //監視対象スクリプトからOnNextが飛んで来たら下記Subscribe処理を実行
        passPushedButton.KeyClicked
            //.Scan((pre, current) => pre + current)
            .Subscribe(KeyCode => ShowToDisPlay(KeyCode))
            .AddTo(gameObject);
        passPushedButton.OperaterKeyClicked
            .Subscribe(a => 
            {
                ShowToDisPlay("");
            })
            .AddTo(gameObject);
    }

    private void ShowToDisPlay(string value)
    {
        if(value == "")
        {
            displayPanelText.text = "";
        }
        else
        {
            displayPanelText.text += value;
        }
    }
}

この時点だとさっきまでできていた「一番最初の0は削除する」の機能が失われているし、小数点が入力された場合の動作にも対応していないが、一旦今日はここまでとしたい。
早いところ演算処理に移りたい...それはそれで別のクラスで作っていく予定だ。
それでは、今回はここまで。

UniRxを勉強しよう4

さてさて!
前回までで押されたボタンの値は取得できるようになったので、今日は4.を進めていく。

完成までの流れ

1. まずは簡単に見た目だけ作る
2. ボタンを押下した際にこれを検知する
3. 押下されたボタンから数値や記号を取得する
4. 引数に渡された数値がディスプレイに表示されるようにする
5. 検知した数値や記号から四則演算を実施できるようにする
6. 見てくれを整える
7. 書き出す

その前に練習で作った処理から要らんところを消す

ここではどこを消したか分かりやすいようコメントアウトで記しておく。

    void ButtonCheck(int i)
    {
        buttons[i].onClick.AsObservable()
            //.Select(_ => 1)
            //.Scan(0, (element, aba) => element + aba)
            .Subscribe(count =>
            {
                Debug.Log(texts[i].text);
            })
            .AddTo(gameObject);
    }

イベントを取得さえできればいいので、Selectによる変換とScanによる値の編集は不要だ。
今回はここから別のところにOnNextでメッセージを飛ばすように作り変えたいと思う。

PassPushedButtonからShowDisplayへ取得したキーをパスする

めっちゃ大変だったができた...途中WindowsUpdateが挟まったせいで死ぬかと思った…

一つ目のPassPushedButtonは以下のように変更。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniRx;
using System;
using UnityEngine.UI;
using System.Security.Cryptography.X509Certificates;

public class PassPushedButton : MonoBehaviour
{
    [SerializeField] List<Button> buttons;
    [SerializeField] List<Text> texts;

    //このクラスからOnNextで別クラスに処理を渡せるようSubjectを用意
    private Subject<string> sendCalcSubject = new Subject<string>();
    
    //なんだっけこれ…プロパティ?外部クラスからアクセス(getのみ)できるようにしておく
    public IObservable<string> KeyClicked
    {
        get { return sendCalcSubject; }
    }

    // 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);
        }
    }

    void ButtonCheck(int i)
    {
        buttons[i].onClick.AsObservable()
            .Subscribe(count =>
            {
                Debug.Log(texts[i].text);
                //定義したSubjectからOnNextでメッセージを出す
                sendCalcSubject.OnNext(texts[i].text);
            })
            .AddTo(gameObject);
    }
}

そしてここから発されたメッセージを受けてディスプレイに表示させるためのクラスは下記のように作った。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniRx;

public class ShowDisplay : MonoBehaviour
{
    //メッセージのやりとり対象はInspector画面から設定する。
    [SerializeField] private PassPushedButton passPushedButton;

    // 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 => Debug.Log("SD" + KeyCode));
    }
}

一旦はOnNextで飛ばされてきたメッセージを取得するだけにした。

VisualStudio2019でスクリプトを書いているのだが、名前空間UniRx内のものをしようとすると全部赤い波線が出るのでデバッグが大変だった。勘弁してくれマジで。

以下記事のサンプルコードをパクり、今回自分がやりたいことに合わせて修正をした。
qiita.com

UniRxを勉強しよう3

UniRxを使って電卓を作る、三日目だ。
昨日でUniRxを使ってイベントを取得する方法が分かってきたので、今日はロードマップの3の部分を進めようと思う

1. まずは簡単に見た目だけ作る
2. ボタンを押下した際にこれを検知する
3. 押下されたボタンから数値や記号を取得する
4. 引数に渡された数値がディスプレイに表示されるようにする
5. 検知した数値や記号から四則演算を実施できるようにする
6. 見てくれを整える
7. 書き出す

なんとなく飛ばしていたSerializeFieldが問題になった

ボタンを押した際、押された値を取得する処理を実装するにあたってつまづいた…
僕としてはボタンを配列(正確にはList)にポコポコと放り込む形がコード上はきれいかなと思ったのだが、SerializeFieldがなんだか分からないため扱いに困ってしばらく悩んだ。
調べたところ、「Inspectorに変数(等)を表示させたいけど、publicで表示させると不都合が起こるので使う」的なものらしい。特に変数の定義自体に影響はない。
ので以下のように書いて解決した。

[SerializeField] List<Button> button = new List<Button>();

これでインスペクターから要素数も指定できるし、複数のボタンをリストで使えるようになった。

さて、ここでUnity側で通常のエディタとしてVisualStudio2019に設定するのを忘れていたことに気付いた。設定をしてみると、UniRxに関する予測変換が利いていないことが判明。なんなの?
しばらく色々試したが、最終的にこの記事が見つかった。
raspberly.hateblo.jp
「using UniRxがうまくいかないぞ」という人はぜひ見てほしい。

でもこの通りにやってもAsObservableで赤い波線が出てしまう。ほんとやだ。

f:id:dkkng:20200719003417p:plain
動くけど、AsObservableがエラー扱いになる

そのあと色々試したが、結局上手くいかないのでもう無視する。エディタークソ。

気を取り直して

ようやく本題に入れた…下記の通りに書き直して押されたボタンが何かを特定できるようになった。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniRx;
using System;
using UnityEngine.UI;

public class PassPushedButton : MonoBehaviour
{
    [SerializeField] List<Button> buttons;
    [SerializeField] List<Text> texts;

    // 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);
        }
    }

    void ButtonCheck(int i)
    {
        //Debug.Log(texts[i]);
        buttons[i].onClick.AsObservable()
            .Select(_ => 1)
            .Scan(0, (element, aba) => element + aba)
            .Subscribe(count =>
            {
                Debug.Log(texts[i].text);
            })
            .AddTo(gameObject);
    }
}
f:id:dkkng:20200719014609p:plain
押されたキーの値がログに出る

とりあえずどのボタンが押されたか検知させることはできるようになった。
頭の中の設計では、このPassPushedButtonは「Pass」と言っている通り、別に作成する計算用のクラスに押されたボタンとその値を通知する仕組みにする。なんかその方がすっきりしません?

そっちのクラスに四則演算の処理を書いておく。
一旦ここまでにしよう…本分じゃない部分でずいぶん時間を食わされた…

【参考にしたサイト】
qiita.com

UniRxを勉強しよう2

全然関係ないんだけど、今日届いたこのイヤホンがめちゃくちゃいいので音楽聞きながら作業するタイプの人はぜひ買ってほしい。
AIRaftershokz.jp
耳の穴を塞がない骨伝導方式かつワイヤレスなので着けててもうっとうしくないし、適度に環境音が入ってきて集中しやすい。また、僕は趣味でベースを弾くのだが、これを使うと原曲を聞きながら自分の楽器の音も聞こえるのでめちゃくちゃ捗る。
これはたぶん本来の使い方ではないが、耳の穴に直接別のイヤホンをぶっさせばスプリッターなしで二つの音声を聞くことができる。最高。マジ最高。

続きから行くぞ!!

さて、昨日の続きからいきます。

昨日は書いた(コピペした)コードの一行目の解説すらできていなかったけど、おかげでUniRxについての理解が進んだ気がする。引き続き昨日のコードを掘り下げていこう。

void Awake()
{
    button.onClick.AsObservable()
        .Select(_ => 1)
        .Scan(0, (element, acc) => element + acc)
        .Subscribe(count => text.text = count.ToString())
        .AddTo(gameObject);
}

昨日は一行目のAsObservableで、ButtonオブジェクトのonClickイベントをIObservableという型にキャストアップしているということが分かった。
IObservableはSubscribeメソッドによってイベントを受けて実行する処理を定義することができ、IObserver型によって発されたメッセージを受けとることができる。

で、昨日の疑問だが、IObservableとIObserverはいずれもSubjectを基軸に動いているのだが、IObservableに変換されたonClickはどこのSubjectからメッセージを受け取っているんだ?そもそもIObserverはいないように見えるんだけど?

この点は調べたけどいまいちわからんかった…どっかにいるSubjectが仕事してるんだろう。

Select以降のところを考える

二行目以降を考えてみよう。LinQで見たような気がする文言が並んでいる。
この.Selectや.Scanは「オペレータ」と分類されるものだ。オペレータの理屈についてもちゃんと解説記事はあったのだが、なんかよく分からん。
とりあえずオペレータはIObserveが送ってくれたメッセージに対してフィルタリングやメッセージの変換などを行うことができるものらしい。種類はたくさんあるので、今回使用しているものについてだけ調べながら処理内容を見てみる。

Selectオペレータ

値を変換したり、値に関数を適用することができる。
今回は下記のように使われているが…

.Select(_ => 1)

なんこれ。ラムダ式ってのはなんか分かるけど…
多分だけど、受け取るメッセージにあたる部分が「_」なのかな?で、ラムダ式の中で「何を受け取ろうが『1』を返す」というメソッドを定義したのだと思う。
つまり、メッセージを受け取ったときに値を「1」に変換しているのだと思われる。
ためしに1を2に変えたら2ずつ増分し始めたのでどうやらそうらしい。

Scanオペレータ

メッセージの値と前回の結果との両方を使い関数を適用する。ふうん。
コードは以下のようになっている。

.Scan(0, (element, acc) => element + acc)

これ試してみてわかったんですが、「element」と「acc」は仮の名前というか…なのでどんな名前にしてもちゃんと動きます。
scanの第一引数「0」は初期値。
elementには「前回の処理の結果」が格納される。
accには「今回受け取ったメッセージ」が格納される。この場合は「1」がaccに入る。
いくつかscanの活用事例を見たが、初期値は格納していない場合も多かったので、これは無きゃ無いでも動くようだ。

ここでSubscribe

これわかったぞこれ…
つまり
メッセージ(イベント通知)が来る
→selectで値を変換する(1に)
→scanで前回の処理結果+1してこれをメッセージとする
→Subscribeでscanの計算結果をメッセージとして受け取る
って流れなんやろコレ!!!ハイハイハイ!!!

.Subscribe(count => text.text = count.ToString())

渡されたメッセージ(計算結果)はcountに入っている。
ラムダ式でtextオブジェクトのtextプロパティにcountの値を代入していると。

AddToはオペレータじゃなかったです

AddToはIObservableに定義されているメソッドの一つ...なのかな?とにかくIObservableが使用するものらしいです。
これをつかうとSubScribeによるイベントメッセージの購読を終了する…らしい。
転職先の先輩曰く「メモリ開放のことやで、とりあえず今はあんまり気にせずおまじない的に書いておきなさい」とのことだったのでこれは深堀しないでおこう。

.AddTo(gameObject);

今回書いたものは理解できた!!

この「最初マジで意味わかんなかったものが理解できた時の快感」ってやばいよね。
ともかく、これでUpdateメソッドとかInspector内からイベント登録をしなくてもスクリプトだけで動作を取得する方法が分かった。
これを活用して次のステップに進んでいこうと思う。

今日はもう少しやるが、ブログ的には区切りがいいので一旦ここで止めておく。
【参考にしたサイト】
qiita.com
qiita.com

UniRxを勉強しよう

きれいなコードとか途中のものも多いけれど、今回転職先の先輩から「UniRxを使えるようになってほしい」ということでUniRxを活用した電卓を作るよう課題を出してもらった。

というわけで、unityを使って電卓を作ってみる。
以前C#のフォームアプリケーションで作ったことはあったが、UniRxを使うとどうなるのか試していく。


とりあえず画面だけは昨日のうちに作っておいた。

f:id:dkkng:20200715234410p:plain
Unityで作った電卓

見てくれは後々修正する。

さて、きちんと勉強するなら「UniRxについて理解する」ことから始めるべきだが、僕はこういうのがめちゃくちゃ苦手&課題の納期的にも「先人のやり方を要所要所で模倣しながら並行して理解する」という方式で行こうと思う。

電卓を作る際のロードマップとしては下記のようなイメージだ。
1. まずは簡単に見た目だけ作る
2. ボタンを押下した際にこれを検知する
3. 押下されたボタンから数値や記号を取得する
4. 引数に渡された数値がディスプレイに表示されるようにする
5. 検知した数値や記号から四則演算を実施できるようにする
6. 見てくれを整える
7. 書き出す

1. は昨日のうちにやったので、今日は2.を実施できるようにしたい。

というわけで、下記の記事をとりあえず丸パクリして動きを確認してみた。
qiita.com

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniRx;
using System;
using UnityEngine.UI;

public class PushedButton : MonoBehaviour
{
    [SerializeField] Button button;
    [SerializeField] Text text;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    void Awake()
    {
        button.onClick.AsObservable()
            .Select(_ => 1)
            .Scan(0, (element, acc) => element + acc)
            .Subscribe(count => text.text = count.ToString())
            .AddTo(gameObject);

    }
}

これにより、ボタンを押下した際にボタンの子オブジェクトであるテキストの値が1ずつ増分されることを確認した。

f:id:dkkng:20200715235358p:plain
0のボタンを押下すると値が0,1,2...と増えていく

引用元にも解説が載っているが、知識ゼロで読んでも意味が分からなかった。
では、このスクリプトについて調べていく。

なお、「初級者が新しい知識を習得する際の情報の流れ」を記録しておくため、以下は体系的にまとめる上ではガッタガタな(例えば[具体]から[抽象]に記述が進むなど)書き方をする。まあ僕しか見ないからいいんだけど。

void Awake()

startやupdateはなじみ深いが、こいつは初めて見た気がする。
awakeはstartよりも先に実行されるメソッドで、シーンの開始時点で読み込まれるらしい。
このサンプルコードでなぜawakeにこの処理が記載されているのかは分からないが、Unityの公式リファレンスを見ると「Startの中で使う関数等をawakeの中に書いておくと、Startでその関数を呼び出せたりするよ」という例が載っていた。
「初期化の内容はここに書いておくといいよ」的な意味合いなのかな?

button.onClick.AsObservable()

この行では、ボタンオブジェクトのonClickイベントをIObservableという型に『アップキャスト』しているらしい。

アップキャスト…派生クラスから基底クラスに型を変更(キャスト)すること。
"Observable"という通り、observerから観測可能にするということだ。
これによってイベントの検知ができるようになる…らしい。

ちょっと違いました

…と思って調べてたら、IObserverとIObservableの解説記事が出てきた。
「UniRxはイベントの上位互換」らしく、イベントよりいろいろ柔軟に使えるらしい。
UniRxでのイベント検知(厳密には違うが分かりやすいのでこう書いておく)は「Subject」というやつが中核をなして行われる。

  • Subscribe : メッセージの受け取り時に実行するを関数を登録する
  • OnNext : Subscribeで登録された関数にメッセージを渡して実行する

といった仕組みになっているらしい。
OnNextで送り出されたメッセージを、Subscribe側が受け取って実行する、この際の橋渡しというか楔になっているという話だと理解した。

OnNext、SubscribeはSubjectが持つ二つのインターフェースに含まれるメソッド

上記は理解しやすくするための簡略化された説明だった。
実際にはSubjectはIObserverとIObservableの二つのインターフェースを持っている。
このうち、OnNextを有するIObserverはイベントの発行者としてふるまうインターフェースで、Subjectを有するIObservableはイベントメッセージの購読(受け取り)者としてふるまうインターフェースになっている。

長くなったが、

button.onClick.AsObservable()

によって、onClickはIObservableにキャストアップされ、これによりイベント発生時(正確にはsubjectがイベントを検知した時)にどんなふるまいをするか決められるようになったということだ。

ん?じゃあこの場合のIObserverはどこにあるんだ…?そもそもOnClickってSubjectクラスなのか?

今日はもう遅いので一旦ここまでにしよう…

【参考にしたサイト/記事】
docs.unity3d.com

qiita.com

qiita.com

qiita.com

qiita.com

Unity祭りに参加しました

おっすおっす

金曜日の夜にconnpassという勉強会支援プラットフォーム(って書いてた)が主催の勉強会に参加しました。
connpass.com

Unity祭という名前の勉強会で、僕のように基本さえ知らない人間には敷居が高いものだったがとりあえずは参加してみた。
「何言ってるか分からん」という焦りが自分にとってのハッパになると思ったから。
csharp-tokyo.connpass.com

というわけで、今回はこの勉強会の内容についてちょこっと書いてみたい。
下記スライドの抜粋になるので、興味がある人は全部読んでみてほしい。そしてとりすーぷさんに「マジぱねえっす」とお声掛けしてほしい。
speakerdeck.com

「Unitask」がすごいらしい

この内容について話してくださったのはとりすーぷさん

ぶっちゃけ基本さえ分かってない僕にはハードルが高すぎた。が、かいつまんで分かったことと「知らない言葉」について書いてみる。

簡単に言うとUnityでめちゃすごい非同期処理ができるようになる拡張ライブラリ

Unitaskは要するに「非同期処理がやりやすくなる(?)最新のライブラリ」のことらしい。およびその記法。
Unitaskの仕組みなど子細に解説があったが、僕には100年早かったので概要だけでも咀嚼しておこう。

とりあえず頭を整理しながら書いてみる。

非同期処理?

まず、同期処理・非同期処理についての説明があった。これは現職でも使う用語なので知っていた。…と思ったら盛大に勘違いしていたのでちょこっと調べてみた。
同期処理は「処理Aが処理Bを呼び出したとき、処理Bの完了を待ってから処理Aを再開する」処理の種類で、非同期処理は「処理Aは処理Bを呼び出すけど、処理Bの進行状況に関わらず処理Aも普通に進んでいく」処理だ。(と理解している)
「スーパーでの買い物」で考えてみる。「レジで商品を出し、支払額を計算してもらい、金額を聞いてから支払いをする」みたいなのは同期処理。計算途中に「はい!2000円払います!釣りは取っとけ!バイバイ!」だったら非同期処理だ。

Unityはゲームを作るときによく用いられるが、ゲーム内の処理は何かしらのきっかけ(イベント)によってスタートし、大元の処理では呼び出したらそれで終わり、待機しないことが多い。ダッシュ中にジャンプしたら、ジャンプ処理が独自に動いてダッシュ処理はダッシュ処理で動くみたいな。つまり、Unityを扱う上で「非同期処理」は必須の記法だ。※紛らわしいようだが、イベントによって処理が開始するならそれは「非同期処理」に分類されるらしい。

Unityでは「コルーチン」というものがある*1のだが、これも非同期処理に分類されるらしい。

非同期処理のスタンダードはasync/await

非同期処理を実装する上でスタンダードなのはasync/awaitを用いた書き方らしい。
これはC#5.0から実装された機能で、メソッドの頭に「async」と書くことでそのメソッドが非同期メソッドに変身できる。
これができると、上述の「コルーチン」のところにも記載した「処理を少しだけ待つ」ということができるようになったりする。コルーチンによく似ているが、とりすーぷさん曰く「強いコルーチン」だと思ってくれということだった。
強調していたのは、asyncは「待つ」ための機能だということだった。マルチスレッド処理*2とは違うんやで、ということだった。

Unitaskはasync/awaitの強化パーツみたいなもん

Unitaskはこのasync/awaitをUnity上で扱いやすく、より便利にするものらしい。アロケーションの削減によるパフォーマンス向上や、Unityに特化した機能の提供などが使用する上でのメリットらしい。
正直この後の話は一ミリも分からなかったので時間をかけて消化したいと思う。(これしないやつだな)

今更ながらここから入手できるので有識者の方はぜひチェックしてほしい。
github.com

学んだこと:「新しい技術をつかんで積極的に導入していいものを作ろう」

よく言われることだが、IT業界は新技術の新興とその衰退がものっすごい速い。集合知の恐るべきところである。こうしたものをしっかりキャッチアップしないと、古のツールを独自の技法で謎に使いこなしていくおじさんになってしまう。今回はエンジニアの友達に声をかけてもらってこれに参加したのだが、継続的にこうしたイベント(リモートのもの)には参加していきたいと思った。
なにより、いいものを作るために使えるものはしっかり使い、限られたリソースを有効に使って、表現に使えるバッファを増やしていきたいものだ。(なんも知らんけど)

以上、番外編でした。

*1:コルーチンについて軽く調べたら「関数の亜種」で処理の最中に中断、また中断したところから再開ができるような仕組みらしい。めっちゃ便利だね。 doruby.jp

*2:マルチスレッド処理というのは簡単に言うと「二つのものを同時に動かすぞ」みたいな処理。効率厨?e-words.jp

きれいなコードを書こう6

さーて、今日もやっていくぞ!
今回も「美しさ」についてだ。

www.oreilly.co.jp

前回までのまとめ

第四章 美しさ
・なぜ美しさが大切なのか
理解しやすくするために、中身の関連性に合わせてしっかりと見た目を整えていくことが大切だ。
・一貫性のある簡潔な改行位置
命名の規則の話はすでにやってきたが、改行する位置(引数を書くところで改行するなど、単純に文字数だけで改行をするとあとあと見にくくなってしまう)を揃えることで理解が進めやすくなる。
・メソッドを使った整列
プログラミングではしょっちゅう出てくることだが、同じ処理が何行も続くならそれはメソッドにまとめるべきだ。見た目ももちろんだが、テストの際や仕様追加で同じ処理をまた増やすときに効率化も図れる。
・縦の線をまっすぐにする
インデントもそうだが、引数の一文字目を揃えることでメソッドの引数の比較などが容易になる。
「似ているコードは似ているように見せる」をキーワードにしてコードを書いていこう。
・一貫性と意味のある並び
コードは並びを変えても、その正しさに影響を及ぼすことは少ない。
引数を並べるときも「重要なものから並べる」、「アルファベット順に並べる」などの工夫をしていくとよい。

ここからは新しい内容だ。

宣言をブロックにまとめる

たとえば、定数を書く段、ハンドラを書く段、メソッドを書く段、という具合に書き分けをしておくとよい。実際これは今もしているけれど…

class ConnectServer{
  public:
    ConnectServer();
    void CheckConnectSpeed();
    void OpenDatabase();
    void ExportSetting();
    ~ConnectServer();
}


class ConnectServer{
  public:
    ConnectServer();
    ~ConnectServer();

    //接続
    void CheckConnectSpeed();
    void OpenDatabase();

    //設定値書き出し
    void ExportSetting();
}

上より下の方がまとまりに意味があるので理解しやすい。
こういった具合で意味の持たせ方によって書き方もまとめていこう。

コードを「段落」に分割する

これも上の内容とほとんど同じだ。まとまりによって分け、各まとまりが持つ意味合いをコメントで説明してあげる。

個人的な好みと一貫性

大文字、小文字を使うタイミングや、クラス定義の際の{}の書き方などは、人によって書きかたの癖がでる。こういうのにポリシーを持つ人も多いが、「どちらが正しいかより、その現場でどちらが主流か」に合わせたほうがいい。改修の度に異なるルールでプログラミングをしてしまうと、あとあとメンテナンスをするときに他の人がものすごく困ることになる。

今日はここまでなんだけど…

も~~~~この書き方やめよう。全然身についてる感じがしないし、いちいち事例考えるのも不毛だし…
正直「どうまとめるか」に頭を使っているので入ってきている感じがしない。

ということで、明日からは先日自作したゲームのコードを、各章の内容に沿ってリファクタリングしてみようと思う。
機能追加するぞと息巻いていたがサボり続けて中身を自分でも忘れてしまった…これをきっかけにコードをきれいにして、今後のテコ入れをやりやすくしていこう。

個人的な好みと一貫性