勉強のためにWindows Form Applicationで,以下のように電卓を作成したとき。
このとき、その手順がそのままUnityに使えるのではないか?と思いたちUnityでも電卓を作成してみた。
確かに、UnityもWindows Form Applicationも、画面のButtonやLabel(TextField)を部品のように作成し、さらにC#でそのButtonをクリックしたときの挙動をひもづける(計算などして、Labelに表示する)という点で似通っていた。
ただ、いずれの二つも、以前Python(モジュールがtkinker、PysimpleGUI, pygameのいずれも)やJavascriptでつくったとき
https://qiita.com/tkoji3744/items/08b71054dfba4f93f2c4
にくらべて、スクリプトの行数がとても長かった。これは、C#には、pythonやJavaScriptで使った関数eval()が用意されていないということが原因と思われた。
すなわちPython の eval() 関数を使用すると、C# のように switch 文を使わずに 直接数式を評価できる ため、コードの簡潔さに大きく影響する。
eval() の動作
print(eval("5 + 3")) # 8
print(eval("10 * 2")) # 20
print(eval("50 / 5")) # 10.0
このように、eval() を使うと 文字列の計算式をそのまま評価して、結果を取得できる ため、C# のように switch 文や if を使わずに済む。
C#(Windows Forms)の計算処理
C# では eval() に相当する組み込み関数がなく、数式の処理を switch 文や if を使って実装する必要がある。
switch (operation)
{
case "+":
result = firstNumber + secondNumber;
break;
case "-":
result = firstNumber - secondNumber;
break;
case "×":
result = firstNumber * secondNumber;
break;
case "÷":
if (secondNumber != 0)
result = firstNumber / secondNumber;
else
lblResult.Text = "Error";
return;
}
C# では 演算子ごとに処理を分岐 させなければならないため、どうしてもコードが長くなる。
(参考) Python(Tkinter)の実装例
Python (Tkinter) を使った場合、eval() を活用することで 極めて短いコードで電卓を作成 できる。
import tkinter as tk
def on_click(event):
text = event.widget.cget("text")
if text == "=":
try:
result.set(eval(result.get()))
except:
result.set("Error")
elif text == "C":
result.set("")
else:
result.set(result.get() + text)
root = tk.Tk()
root.geometry("300x400")
result = tk.StringVar()
entry = tk.Entry(root, textvar=result, font="Arial 20")
entry.pack(fill="both")
buttons = [
"7", "8", "9", "+",
"4", "5", "6", "-",
"1", "2", "3", "*",
"C", "0", "=", "/"
]
for i in range(0, len(buttons), 4):
frame = tk.Frame(root)
frame.pack()
for text in buttons[i:i+4]:
btn = tk.Button(frame, text=text, font="Arial 20", height=2, width=5)
btn.pack(side="left")
btn.bind("<Button-1>", on_click)
root.mainloop()
eval() の強力さ
result.set(eval(result.get()))
この1行で 全ての計算を実行 できるため、C# の switch 文のような処理が不要になる。
「これだけ」のpythonに比べて、これから以下に書いていくUnityでの電卓つくりは、むなしくなるほど圧倒的に大変である、といえる。
その手順を要約する。
-
プロジェクトの準備
(1) Unityのインストール
Unity Hubを使用して最新のLTSバージョンのUnityをインストール。
(2) 新しいプロジェクトの作成
Unity Hubを開き、「新しいプロジェクト」。テンプレート: 2D を選択。
プロジェクト名: 「Calculator」。保存場所を選び、「作成」。 -
UIの作成
各UIの役割
Button 19個:計算機のボタン(0〜9、演算子4つ:+-*/、クリア、イコール、正負逆転、%、小数点)
Input Field 1個目 ユーザーの入力を表示
Input Field 2個目 計算結果を表示
(1) Canvasの作成
Hierarchyウィンドウで Right Click → UI → Canvas を作成。
Canvasの Render Mode を Screen Space - Overlay に設定
(2) 入力表示用のテキストボックス
Input Field (TMP)(2個) を配置
Hierarchyで Right Click → UI → Panel
(その子として)そのPnelの上で、Right Click → UI → Input Field (TMP) を作成(TextMeshProのバージョン推奨)Rect Transform を調整して画面上部に配置。Text を 0 等にして、Font Size を適切に調整。
複製して、2つ作成。
(3) ボタンの作成
まず画面上に、Button(19個)を配置
HierarchyでRight Click → UI → Button を作成し、名前を Button_1 に変更。
Text コンポーネントを 1 等に変更。Rect Transform でサイズと位置を調整。
作成した Button を Ctrl+D(Duplicate)で複製し、19個用意
他の数字 (0~9), 記号 (+, -, *, /, =, C) も同様に作成していく。
3.スクリプトの作成
Assets フォルダ内で Right Click → Create → C# Script
スクリプト名を CalculatorScript に変更し、以下のコードを記述。
ボタンに共通のスクリプトを適用すると効率がよい。
共通スクリプト(Calculator.cs)を作成した後、
OnClick() のイベントに同じ OnButtonClick() メソッドを登録
それぞれのボタンで、引数(ボタンの値) を渡す、等、このあとでおこなっていく予定
(1)スクリプトを1つ作成
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class Calculator : MonoBehaviour
{
public TMP_InputField inputField;
public TMP_InputField resultField;
private string currentInput = ""; // 数式を保持
private bool isResultDisplayed = false;
// ボタンを押したときの処理
public void OnButtonClick(string value)
{
Debug.Log($"Button Pressed: {value}");
// 直前に計算結果が表示されていた場合
if (isResultDisplayed)
{
// 数字が押された場合は currentInput をリセット
if (char.IsDigit(value[0]) || value == ".")
{
currentInput = value;
}
// 演算子が押された場合は、計算結果を継続
else
{
currentInput += value;
}
isResultDisplayed = false;
}
else
{
currentInput += value;
}
inputField.text = currentInput;
Debug.Log($"Updated Input: {currentInput}");
}
// クリアボタンの処理
public void OnClearClick()
{
Debug.Log("Clear Pressed");
currentInput = "";
inputField.text = "";
resultField.text = "";
isResultDisplayed = false;
}
// 計算結果を表示
public void OnEqualClick()
{
Debug.Log($"Evaluating: {currentInput}");
try
{
float result = EvaluateExpression(currentInput);
Debug.Log($"Final Result: {result}");
// 計算結果を currentInput に保存(次の計算に使えるようにする)
currentInput = result.ToString();
inputField.text = currentInput; // 入力フィールドに結果を表示
resultField.text = currentInput; // 結果フィールドにも表示
isResultDisplayed = true; // 計算完了フラグをセット
}
catch
{
resultField.text = "Error";
Debug.LogError("Calculation Error");
}
}
// 数式の評価
private float EvaluateExpression(string expression)
{
Debug.Log($"Computing: {expression}");
try
{
expression = expression.Replace("\"", "");
object result = new System.Data.DataTable().Compute(expression, "");
Debug.Log($"Computed Result: {result}");
return float.Parse(result.ToString());
}
catch (System.Exception ex)
{
Debug.LogError($"Error in computation: {ex.Message}");
return 0;
}
}
// +/- ボタンの処理
private void ToggleSign()
{
if (!string.IsNullOrEmpty(currentInput))
{
if (currentInput[0] == '-')
currentInput = currentInput.Substring(1);
else
currentInput = "-" + currentInput;
inputField.text = currentInput;
}
}
// % ボタンの処理
private void ApplyPercentage()
{
if (!string.IsNullOrEmpty(currentInput))
{
try
{
float value = float.Parse(currentInput) / 100f;
currentInput = value.ToString();
inputField.text = currentInput;
}
catch
{
resultField.text = "Error";
}
}
}
}
(2)ボタンにスクリプトを適用
スクリプトのアタッチ先について
スクリプト(Calculator.cs)は、Canvas や Button、Text にはアタッチせず。
代わりに、空の GameObject(例: CalculatorManager) を作成し、そこにアタッチする。
① 空のオブジェクトを作成
Unityの Hierarchy で右クリック、あるいはGameObject → Create Empty を選択。名前を CalculatorManager に変更。
② CalculatorManagerのInspector で
Add Component をクリック
Calculator スクリプトを追加。スクリプトに UI 要素を紐づける。
Calculator スクリプトの inputField に、Input Field (TMP) を設定
Calculator スクリプトの resultField に、結果表示用 Input Field (TMP) を設定
③各ボタンの OnClick() にスクリプトのメソッドを登録
次に、ボタンの OnClick() に Calculator スクリプトの OnButtonClick() を設定。
Hierarchy で Button 1 などを選択
Inspector の Button コンポーネントを確認
Inspector内に表示されているOnClick() のリストを開く
+ボタンを押して、新しいイベントを追加
イベントの対象を CalculatorManager に設定 (AssetsでなくSceneにある)
None (Object) の部分をクリック
CalculatorManager を選択
(メソッドを Calculator.OnButtonClick(string) に設定、すなわち)
No Function → Calculator → OnButtonClick(string) と選んでいく
引数にボタンの値を設定(下記表)
各ボタンに設定する引数の対応表
ボタン | 設定するメソッド | OnClick() の引数(“”をつけること) |
---|---|---|
0 | OnButtonClick(string) | "0" |
1 | OnButtonClick(string) | "1" |
2 | OnButtonClick(string) | "2" |
3 | OnButtonClick(string) | "3" |
4 | OnButtonClick(string) | "4" |
5 | OnButtonClick(string) | "5" |
6 | OnButtonClick(string) | "6" |
7 | OnButtonClick(string) | "7" |
8 | OnButtonClick(string) | "8" |
9 | OnButtonClick(string) | "9" |
. | OnButtonClick(string) | "." |
+ | OnButtonClick(string) | "+" |
- | OnButtonClick(string) | "-" |
* | OnButtonClick(string) | "*" |
/ | OnButtonClick(string) | "/" |
% | OnButtonClick(string) | "%" |
+/- | OnButtonClick(string) | "+/-" |
特別なボタンの設定
ボタン | 設定するメソッド | OnClick() の引数 |
---|---|---|
= | OnEqualClick() | (不要) |
C | OnClearClick() | (不要) |
4.動作確認 |