【１から】Godot Engineで簡易電卓を作る Part3

Part2では複数のボタンの実装まで出来ました。

[【１から】Godot Engineで簡易電卓を作る Part2](https://qiita.com/t170317/items/24a4024c212406423d1c)

そして電卓の計算部分を実装するにあたり、まずは入力パターンを考えてみます。

◯：111+11=
×：111+=
×：111=
×：+11=
×：=

打ち込んで欲しいパターンとしては

数字1(0〜9)→演算子(+-×÷)→数字2(0~9)→等号(=)

ということで

場合１→場合２→場合３→場合４

といった感じに場合分けして実装していこうと思います。

###場合１

まずはmain.gdに

```gd:main.gd
extends Node2D


# Declare member variables here. Examples:
# var a = 2
# var b = "text"
var num = "0"
var phase = 1 

# Called when the node enters the scene tree for the first time.
func _ready():
	pass # Replace with function body.


# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
#	pass
```

```gd
var phase = 1 
```

と宣言して、button.gdに読み込んでボタン関数にて場合分けしていきます。

```gd:button.gd
extends Node2D


# Declare member variables here. Examples:
# var a = 2
# var b = "text"
onready var main = get_node("/root/Node2D")

# Called when the node enters the scene tree for the first time.
func _ready():
	pass # Replace with function body.

# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
#	pass


func _on_Button_button_down():
    if main.phase == 1 and $Button.text == "1":
        main.num += $Button.text
        print(main.num)
    elif main.phase == 2:
    pass
    elif main.phase == 3:
    pass
    elif main.phase == 4:
    pass
```

ひとまずこう書いて、$Button.textが”１”のとき(ボタン”１”が押されたとき)実行されるようにします。

そして、次は"+"が押されるまでmain.numに格納されていた値を一時的な変数(ここではbuff)に格納しようと思います。

その後、main.numを初期化して、数字2の部分として再利用していきます。

```gd:main.gd
extends Node2D


# Declare member variables here. Examples:
# var a = 2
# var b = "text"
var num = "0"
var phase = 1 
var buff = "0"
var firstFlag = false

# Called when the node enters the scene tree for the first time.
func _ready():
	pass # Replace with function body.


# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
#	pass
```
その際、一度でも数字が入力されたことを確認するためfirstFlagという変数でフラグ管理します。

こうして、好きなだけ1を入力してから"+"を打って、そこからphase2に移行できるように条件分けします。

###場合２

```gd:button.gd
func _on_Button_button_down():
    if main.phase == 1 and $Button.text == "1":
        main.num += $Button.text
        print(main.num)
        main.firstFlag = true
    elif main.phase == 1 and main.firstFlag == true and $Button.text == "+":
        main.buff = main.num
        main.num = "0" 
        main.phase = 2 
        main.firstFlag = false
    elif main.phase == 2:
    pass
    elif main.phase == 3:
    pass
    elif main.phase == 4:
    pass
```

条件としては数字が一回でも押された状態で、”＋”が押された場合となります。

そうして、分岐下では先程用意したbuffに今までの連結した値num(例：１、１１、１１１)を代入し、numをゼロリセットします。

そして、phaseに２を代入して、firstFlagでは数字２でも使い回したいのでfalseを代入します。

###場合３

phase２ではphase１と同じく数字を打ち込んでいきます。

```gd:button.gd
func _on_Button_button_down():
    if main.phase == 1 and $Button.text == "1":
        main.num += $Button.text
        print(main.num)
        main.firstFlag = true
    elif main.phase == 1 and main.firstFlag == true and $Button.text == "+":
        main.buff = main.num
        main.num = "0" 
        main.phase = 2 
        main.firstFlag = false
    elif main.phase == 2 and $Button.text == "1":
        main.num += $Button.text
        print(main.num)
        main.firstFlag = true
    elif main.phase == 3:
    pass
    elif main.phase == 4:
    pass
```

そして先程と同じく、今度は”＝”が押されたときに処理が挟まるようにします。

###場合４

```gd:button.gd
func _on_Button_button_down():
    if main.phase == 1 and $Button.text == "1":
        main.num += $Button.text
        print(main.num)
        main.firstFlag = true
    elif main.phase == 1 and main.firstFlag == true and $Button.text == "+":
        main.buff = main.num
        main.num = "0" 
        main.phase = 2 
        main.firstFlag = false
    elif main.phase == 2 and $Button.text == "1":
        main.num += $Button.text
        print(main.num)
        main.firstFlag = true
    elif main.phase == 2 and main. firstFlag == true and $Button.text == "=":
        main.buff = str(int(main.buff) + int(main.num)) 
        print(main.buff) 
        main.phase = 3 
    elif main.phase == 3:
    pass
    elif main.phase == 4:
    pass
```

計算結果をmain.buffに代入し、printで表示します(手順としては一旦int・整数型に直し計算できるようにしてから演算し、結果を再びstr・文字列型に戻す)。

これで一応計算機としての機能は実装できました。

あと実装する必要があることとすれば、

・計算終了後にまた”=”ボタンが押されたら「計算結果+数字2」で再計算
・”+”が押されたらまた次の数字を入力して、”=”で結果表示
・他の数字ボタン(0,2~9)、-×÷ボタンの実装

となりますが、先に上2つを実装してみます。

まずはphase3で”=”が押された場合は

```gd:button.gd
func _on_Button_button_down():
    if main.phase == 1 and $Button.text == "1":
        main.num += $Button.text
        print(main.num)
        main.firstFlag = true
    elif main.phase == 1 and main.firstFlag == true and $Button.text == "+":
        main.buff = main.num
        main.num = "0" 
        main.phase = 2 
        main.firstFlag = false
    elif main.phase == 2 and $Button.text == "1":
        main.num += $Button.text
        print(main.num)
        main.firstFlag = true
    elif main.phase == 2 and main. firstFlag == true and $Button.text == "=":
        main.buff = str(int(main.buff) + int(main.num)) 
        print(main.buff) 
        main.phase = 3 
    elif main.phase == 3 and $Button.text == "=":
        main.buff = str(int(main.buff) + int(main.num)) 
        print(main.buff) 
    elif main.phase == 4:
    pass
```

と先程の処理を繰り返すだけで良いと思います。

次は”＋”の場合

```gd:button.gd
func _on_Button_button_down():
    if main.phase == 1 and $Button.text == "1":
        main.num += $Button.text
        print(main.num)
        main.firstFlag = true
    elif main.phase == 1 and main.firstFlag == true and $Button.text == "+":
        main.buff = main.num
        main.num = "0" 
        main.phase = 2 
        main.firstFlag = false
    elif main.phase == 2 and $Button.text == "1":
        main.num += $Button.text
        print(main.num)
        main.firstFlag = true
    elif main.phase == 2 and main. firstFlag == true and $Button.text == "=":
        main.buff = str(int(main.buff) + int(main.num)) 
        print(main.buff) 
        main.phase = 3 
    elif main.phase == 3 and $Button.text == "=":
        main.buff = str(int(main.buff) + int(main.num)) 
        print(main.buff) 
    elif main.phase == 3 and $Button.text == "+":
        main.num = "0"
        main.phase = 2
        main.firstFlag = false
    elif main.phase == 4:
        pass
```

と『elif main.phase == 2 and $Button.text == "1":』の条件を満たすように変数をセットします。

こうすることで再び「数字２→等号」と打って計算ができるようになります。

こうしてループをかけることで処理を使い回して実装することが可能に。

最後に0,2~9の数字ボタン、−×÷ボタンを実装して計算できるようにします。

###完成まで

まずはボタンを複製して並べます。

![スクリーンショット 2021-11-22 20.41.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2309073/c6846f27-9bf4-323f-7613-d29f7ea746dc.png)

そして、まずbutton.gdの宣言部分にて

```gd:button.gd
extends Node2D


# Declare member variables here. Examples:
# var a = 2
# var b = "text"
onready var main = get_node("/root/Node2D")
var regex = RegEx.new()
regex.compile("\\d")
# Called when the node enters the scene tree for the first time.
func _ready():
	pass # Replace with function body.

# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
#	pass
```
と2行追加します。

```gd
var regex = RegEx.new()
regex.compile("\\d")
```
条件判定で一々「... and $Button.text == "2" and... 」といった感じで繋げていくと大変なので、正規表現で処理します。

```gd:button.gd
func _on_Button_button_down():
	if main.phase == 1 and regex.is_valid($Button.text) == true:
		main.num += $Button.text
		print(main.num)
		main.firstFlag = true
	elif main.phase == 1 and main.firstFlag == true and regex.is_valid($Button.text) == true and $Button.text != "=":
		main.buff = main.num
		main.num = "0" 
		main.phase = 2 
		main.firstFlag = false
	elif main.phase == 2 and regex.is_valid($Button.text) == true:
		main.num += $Button.text
		print(main.num)
		main.firstFlag = true
	elif main.phase == 2 and main. firstFlag == true and $Button.text == "=":
		main.buff = str(int(main.buff) + int(main.num)) 
		print(main.buff) 
		main.phase = 3 
	elif main.phase == 3 and $Button.text == "=":
		main.buff = str(int(main.buff) + int(main.num)) 
		print(main.buff) 
	elif main.phase == 3 and regex.is_valid($Button.text) == true and $Button.text != "=":
		main.num = "0"
		main.phase = 2
		main.firstFlag = false
	elif main.phase == 4:
		pass

```

1段階目では数字1ケタ(0~9)にマッチするとtrueが返るようになっています。

2段階目では逆に「!=」でそれ以外の文字（残りのボタン+-×÷=）がマッチします。

ここでは”=”を省きたいので「and $Button.text != "="」も条件に付けておきます。

3段目は1段目と同じく数字部分を書き換え、4段目・5段目は書き換えない、6段目”＋”の場合は2段めと同じように記号部分の条件を書き換えます。

ただこのままでは＋しか計算出来ないので条件分けします。

そこでまずmain.gdに

```gd:main.gd
extends Node2D


# Declare member variables here. Examples:
# var a = 2
# var b = "text"
var num = "0"
var phase = 1 
var buff = "0"
var firstFlag = false
var operator = "0"

# Called when the node enters the scene tree for the first time.
func _ready():
	pass # Replace with function body.


# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
#	pass

```

```gd:main.gd
var operator = "0"
```

operator変数を宣言。button.gdを以下に書き換え


```gd:button.gd
extends Node2D


# Declare member variables here. Examples:
# var a = 2
# var b = "text"
onready var main = get_node("/root/Node2D")
var regex = RegEx.new()

# Called when the node enters the scene tree for the first time.
func _ready():
	regex.compile("\\d")
	pass # Replace with function body.

# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
#	pass
func cal():
	if main.operator == "+":
		main.buff = str(int(main.buff) + int(main.num))
	elif main.operator == "-":
		main.buff = str(int(main.buff) - int(main.num))
	elif main.operator == "×":
		main.buff = str(int(main.buff) * int(main.num))
	elif main.operator == "÷":
		main.buff = str(int(main.buff) / int(main.num))

func _on_Button_button_down():
	var result = regex.search($Button.text)
	if result == null:
		result = false
	else:
		result = true
	if main.phase == 1 and result == true:
		main.num += $Button.text
		print(main.num)
		main.firstFlag = true
	elif main.phase == 1 and main.firstFlag == true and result == false and $Button.text != "=":
		main.operator = $Button.text
		print(main.operator)
		main.buff = main.num
		main.num = "0" 
		main.phase = 2 
		main.firstFlag = false
	elif main.phase == 2 and result == true:
		main.num += $Button.text
		print(main.num)
		main.firstFlag = true
	elif main.phase == 2 and main.firstFlag == true and $Button.text == "=":
		cal()
		print(main.buff) 
		main.phase = 3 
	elif main.phase == 3 and $Button.text == "=":
		cal()
		print(main.buff) 
	elif main.phase == 3 and result == false and $Button.text != "=":
		main.operator = $Button.text
		print(main.operator)
		main.num = "0"
		main.phase = 2
		main.firstFlag = false
	elif main.phase == 4:
		pass


```

##変更点

###1.正規表現

まずは変数宣言部にて宣言し

```gd:button.gd
var regex = RegEx.new()
```

次に「func _ready():」にて

```gd:button.gd
func _ready():
    regex.compile("\\d")
    pass # Replace with function body.
```
Godotでは新規インスタンスを宣言した後、正規表現はcompileメソッドを用いてインスタンスに登録します。

そしてボタン関数部において

```gd:button.gd
func _on_Button_button_down():
    var result = regex.search($Button.text)
    if result == null:
        result = false
    else:
        result = true
```
regex.search($Button.text)　とsearchメソッドを使うことで先程登録した正規表現で検索をかけてくれます。

そして正規表現とマッチした場合はRegExMatchオブジェクトが返ってきます。

逆にマッチしなかった場合はnullオブジェクトが返ってきます。

ここでは正規パターンを"\\d"、つまり数字1文字(0~9)として定めていますので、それ以外の+-×÷=ボタンが入力された場合はnullが返ってきます。

まずは数字と記号を分けられたら良いので、nullが返ってくるときはすべてfalseを代入して、そうでない時（=数字ボタン）にtrueを代入して場合分けに繋げていきます。

###2.条件設定

```gd:button.gd
if main.phase == 1 and result == true:
		main.num += $Button.text
		print(main.num)
		main.firstFlag = true
	elif main.phase == 1 and main.firstFlag == true and result == false and $Button.text != "=":
		main.operator = $Button.text
		print(main.operator)
		main.buff = main.num
		main.num = "0" 
		main.phase = 2 
		main.firstFlag = false
```
1段目ではresult == true、2段目ではresult == false and $Button.text != "=":としています。

2段目は記号ボタンから”＝”を排除して四則演算に対応させています。

ボタンの値である四則演算の記号は次の計算パートで使用するために一旦「main.operator」変数に格納します。

###3.計算部分は関数定義する
”＝”が押される部分が2回出てくるので、func cal():と関数定義して外に出します。

```gd:button.gd

	elif main.phase == 2 and main.firstFlag == true and $Button.text == "=":
		cal()
		print(main.buff) 
		main.phase = 3 
	elif main.phase == 3 and $Button.text == "=":
		cal()
		print(main.buff) 
```

```gd:button.gd
func cal():
	if main.operator == "+":
		main.buff = str(int(main.buff) + int(main.num))
	elif main.operator == "-":
		main.buff = str(int(main.buff) - int(main.num))
	elif main.operator == "×":
		main.buff = str(int(main.buff) * int(main.num))
	elif main.operator == "÷":
		main.buff = str(int(main.buff) / int(main.num))

```

後の段階は変数を置き換えていくだけです。

↑においた全体図を実行すると

![スクリーンショット 2021-11-23 1.11.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2309073/300f2b3a-683b-dfc7-bbd8-a0f3374c99fd.png)

ですが「1÷0=」するとエラーになるので修正して、リセットボタン「CE」も実装して![スクリーンショット 2021-11-23 1.24.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2309073/e2d0717e-b2aa-f231-4b94-47dbfe221ab4.png)


完成コードは↓になります。

```gd:main.gd
extends Node2D


# Declare member variables here. Examples:
# var a = 2
# var b = "text"
var num = "0"
var phase = 1 
var buff = "0"
var firstFlag = false
var operator = "0"

# Called when the node enters the scene tree for the first time.
func _ready():
	pass # Replace with function body.


# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
#   pass

```

```gd:button.gd
extends Node2D


# Declare member variables here. Examples:
# var a = 2
# var b = "text"
onready var main = get_node("/root/Node2D")
var regex = RegEx.new()

# Called when the node enters the scene tree for the first time.
func _ready():
	regex.compile("\\d")
	pass # Replace with function body.

# Called every frame. 'delta' is the elapsed time since the previous frame.
#func _process(delta):
#	pass
func cal():
	if main.operator == "+":
		main.buff = str(int(main.buff) + int(main.num))
	elif main.operator == "-":
		main.buff = str(int(main.buff) - int(main.num))
	elif main.operator == "×":
		main.buff = str(int(main.buff) * int(main.num))
	elif main.operator == "÷":
		main.buff = str(int(main.buff) / int(main.num))

func _on_Button_button_down():
	if $Button.text == "CE":
		main.buff = "0"
		main.num = "0"
		main.phase = 1
		main.firstFlag = false
		main.operator = "0"
		print("CE")
	var result = regex.search($Button.text)
	if result == null:
		result = false
	else:
		result = true
	if main.phase == 1 and result == true:
		main.num += $Button.text
		print(main.num)
		main.firstFlag = true
	elif main.phase == 1 and main.firstFlag == true and result == false and $Button.text != "=":
		main.operator = $Button.text
		print(main.operator)
		main.buff = main.num
		main.num = "0" 
		main.phase = 2 
		main.firstFlag = false
	elif main.phase == 2 and result == true:
		main.num += $Button.text
		print(main.num)
		main.firstFlag = true
	elif main.phase == 2 and main.firstFlag == true and $Button.text == "=":
		if main.operator == "÷" and int(main.num) == 0:
			print('error buff / 0')
			pass
		else:
			cal()
			print(main.buff) 
			main.phase = 3 
	elif main.phase == 3 and $Button.text == "=":
		cal()
		print(main.buff) 
	elif main.phase == 3 and result == false and $Button.text != "=":
		main.operator = $Button.text
		print(main.operator)
		main.num = "0"
		main.phase = 2
		main.firstFlag = false
	elif main.phase == 4:
		pass

```

以上で簡易電卓は完成です。この他にも欲しい機能がある場合は各自で付け足してみましょう。