[Unity] EditorWindowで電卓を作ってみた


# Unity使用中に簡単な計算がしたい

Unityを使っていて座標やキャラクタのステータスなど，パッとしたいけど暗算はできないし，電卓を別で開きたくないし，どうにかならないかな．．．と思ってUnity上で使用できる簡易的な電卓を作ってみました．

作成したものはこちらになります．
![claculator.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1113136/0a2c77fb-eb60-9888-576d-01d0293f4edb.gif)


新しいWindowとしてUnity使用中に電卓が現れて，簡単な計算がすぐ行えるようになりました．またUnityのメイン画面の裏側に隠れることもないのでとても便利です．今回はこの電卓の作り方を紹介します．というよりはEditorWindowの作り方なので他の機能にも応用が効くと思います．電卓自体の実装はもっといい方法があると思うので，自分で考えてみるといいと思います．(綺麗な実装あったら教えてください．）

## EditorWindowとは？
一言で言うと「Unityを使いやすくするためのカスタムWindow」

https://docs.unity3d.com/ja/current/ScriptReference/EditorWindow.html

Unity使ってるとInspectorViewやGameVeiw，SceneViewなどをいじって開発しますが，これらと同じように一つの画面として操作できるようにするのがEditowWindowです．電卓の例で見せたようにUnity上のWindowを自分好みで作ることができます．

Windowのサイズを変えたり，画像の挿入，色つけなどかなり多くのことができるそうです．力を入れればかなり凝ったものも作れそうですが，今回は簡単な電卓を作りました．

# Windowを定義


Windowを作ったり，Inspectorをいじったりする，Editor拡張を行うc#のスクリプトファイルは任意の場所のEditorディレクトリの中に入れておきます．(`Assets/Editor/CalculatorWindow.cs`や`Assets/Scripts/Editor/CalculatorWindow.cs`など)

個人的には`Assets/Editor/`内にEditor拡張系のスクリプトをまとめた方がいいかと思います．
新たなWindowを定義するに`EditorWindow`クラスを継承します．

早速`Assets/Editor/CalculatorWindow.cs`を作っていきましょう．MonobehaviorからEditorWindowに変更し，自動生成されるStart関数やUpdate関数は消して置きます．

```csharp
using UnityEditor;
using UnityEngine;
public class CalculatorWindow : EditorWindow
{
}
```

# メニューバーからWindowを生成

PackageManagerやBuildSettingなど行う時に使う，上のメニューバーにボタンを追加して
Windowが現れるようにします．`CalculatorWindow`クラスに以下の関数を定義します．

```csharp
    // メニューバーに追加するための属性
    [MenuItem("Tool/Calculator")]
    public static void CreateWindow()
    {
        // EditorWindowを作成する
        EditorWindow window = EditorWindow.GetWindow(typeof(CalculatorWindow), true, "Calculator");
        window.Show();
    }
```

`MenuItem( "任意の名前" )`と関数の前に属性をつけることで，関数をメニューから呼び出すことができるようになります．
上のメニューに`Tool/Calculator`が現れました．
![スクリーンショット 2022-01-22 18.26.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1113136/f860ecfb-7cf3-a512-2098-0f04a7e776e3.png)
`EditorWindow.GetWindow(typeof(CalculatorWindow), true, "Calculator");`で指定したtypeのWindowを呼び出します．Windowが非表示になっている時は新しくWindowが作られます．
今回は第二引数で`true`としていて，他のGameViewやSceneViewなどのようにドッキングができず，Unityの全面に居続けるWindowにしています．(これでTransformの座標みながらでも電卓自体を見ることができます)．第三引数はWindowのタイトルを設定しています．
(他にも引数で色々設定できるようです．)


実際に`Tool/Calculator`を押してみるとUnityの前にCalculatorWindowが表示されます．人によって表示されるサイズが異なるかもしれません．

![スクリーンショット 2022-01-22 18.33.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1113136/46d1883a-f8b1-5d3c-cc97-60733dd097dc.png)

**簡単にWindowが作れました！！！！**

これからWindowの中身を書いていきます．

# Windowにボタンを追加

電卓の数字や演算子はボタンとして押したら反応するようにします．まずは現在のからっぽのWindowに対して描画を行う関数を導入します．先程の`CalculatorWindow`クラスに`OnGUI`関数を追加します．この関数はWindowの移動や入力，マウスが入ってきたなどイベントが起きた時に呼ばれます．Windowに表示される文字やボタンなどはこの中に記述していきます．

```csharp
    private void OnGUI()
    {
        // ここに表示するものを書いていく
    }
```

例としてボタンを一つ表示してみましょう．Rectでボタンの表示する座標と大きさ(x,y,w,h)を指定して`GUI.Button()`で作成します．GUI.Buttonはボタンが押された時のみ`true`を返してくる仕組みになっています．if文の中にボタンが押された時の処理を書いて置きます．

```csharp
    private void OnGUI()
    {
        Rect rect = new Rect(0, 0, 100, 50);
        if (GUI.Button(rect, "押さないでね!!!"))
        {
            Debug.LogWarning("押してはいけません!!!");
        }
    }
```

先程と同じようにWindowを立ち上げると押さないでね!!と書かれたボタンが追加され，ボタンを押すとConsoleにWarningが出るようになったと思います．

![スクリーンショット 2022-01-22 18.50.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1113136/8be82d00-80e7-77a3-4f8f-de1398c410f9.png)

**押して怒られた方おめでとうございます！！大成功です！！**
ボタンを配置して，そのボタンが押された時に行なって欲しい処理の書き方もわかりました．if文内に直接処理を書かなくて外で定義した関数を呼び出すことも可能です．


## 文字を表示する

次は電卓の一番上に表示されている入力した数字を表示する部分について考えます．先程のボタンは一度削除してしまいます.今回は例としてHello World!を文字列として表示してみましょう．`OnGUI()`の関数を以下のように書き換えます．ボタンと同じようにRectで描画位置と大きさを決めて描画します．

```csharp
    string text = "Hello World!";
    int _fontSize = 32;
    private void OnGUI()
    {
        Rect rect = new Rect(0, 0, 100, 50);
        GUIStyle style = new GUIStyle()
        {
            fontSize = _fontSize,
        };
        EditorGUI.LabelField(rect, text, style);
    }
```

GUIStyleはオプションで入れなくてもいいですが，電卓の完成系で使用したフォントサイズを入れています.定義した変数の`text`を変更することで表示される文字が更新していきます．fontStyleの変更など設定で色々変えられるので自分好みにするといいと思います．
記述したらもう一度Windowを開き直してみましょう．以下のようになるはずです．

![スクリーンショット 2022-01-22 19.07.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1113136/0235efea-039e-7f7f-d638-e1dd9ecfe6b4.png)

**Hello World!**が表示されていたら成功です．立派なEditorWindow使いです．
ここまで来れば，ボタンもテキストも使い方も理解したと思うのであとは**やるだけ**です．必要な機能追加を行なっていきます．


## 電卓に必要なボタンを追加
この画像を完成系として必要な機能を追加していきます．一番上の入力した数字を表示するテキストと，ボタンを16個作ってそれぞれのボタンに処理を書けば完成です．

![スクリーンショット 2022-01-22 19.10.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1113136/8cd3ed96-fbd9-1266-aac2-6d22fbb28a04.png)

ボタンのサイズや配置は**いい感じ**になるように定数を当てはめていきます．ボタンを押した時の処理は一つずつ書いていきましょう．電卓のお気持ちを寄り添って考えましょう．今回は入力が数字か，演算子かACかどうか，で分けて書きました．処理内容だけ書くこんな感じです．

```csharp
    public void OnClickedNumber(int number)
    {
        // 現在の数字を10倍して新たに数字を加える
    }
    public void OnClickedOperator(Operator operator)
    {
        // 一つ前の演算があれば行う． (1+1 `+` <=これが入力された時1+1を計算する
        // 直前も演算子だった場合演算子を入れ替える
    }
    public void OnClickedAC()
    {
        // 全部リセット
    }
```

これらを実装して行くことで電卓が完成します．
実際に書いたコードはこちらで公開しているで自由に使ってください！`CalculatorWindow.cs`のファイルだけ取り出して自身のプロジェクトに配置するだけで使えるようになります．これもEditorWindowのすごいところ．

https://github.com/topaz13/UnityCalculator

## おわりに
初めてのQiita投稿です．EditorWindow触れてみて面白かったので共有したいと思って書きました．間違え等あったら優しく教えて欲しいです．
電卓以外にも便利なWindowはたくさん作れると思います．今回作った電卓も，簡易版なのでint型しか扱っていませんが，少数や有効桁数を増やしたり，メモリ機能をつけたりまだまだ拡張ができそうです．
UnityのEditor拡張は本当に面白くて沼にハマりそうです．みんなも遊んでみようね！！

## 参考サイト
- https://zenn.dev/kumas/books/325ed71592f6f5/viewer/78e9eb
- https://docs.unity3d.com/ja/current/ScriptReference/EditorWindow.html