Part2では複数のボタンの実装まで出来ました。
【1から】Godot Engineで簡易電卓を作る Part2
そして電卓の計算部分を実装するにあたり、まずは入力パターンを考えてみます。
◯:111+11=
×:111+=
×:111=
×:+11=
×:=
打ち込んで欲しいパターンとしては
数字1(0〜9)→演算子(+-×÷)→数字2(0~9)→等号(=)
ということで
場合1→場合2→場合3→場合4
といった感じに場合分けして実装していこうと思います。
場合1
まずは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
var phase = 1
と宣言して、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が”1”のとき(ボタン”1”が押されたとき)実行されるようにします。
そして、次は"+"が押されるまでmain.numに格納されていた値を一時的な変数(ここではbuff)に格納しようと思います。
その後、main.numを初期化して、数字2の部分として再利用していきます。
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に移行できるように条件分けします。
場合2
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(例:1、11、111)を代入し、numをゼロリセットします。
そして、phaseに2を代入して、firstFlagでは数字2でも使い回したいのでfalseを代入します。
場合3
phase2ではphase1と同じく数字を打ち込んでいきます。
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
そして先程と同じく、今度は”=”が押されたときに処理が挟まるようにします。
場合4
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で”=”が押された場合は
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
と先程の処理を繰り返すだけで良いと思います。
次は”+”の場合
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":』の条件を満たすように変数をセットします。
こうすることで再び「数字2→等号」と打って計算ができるようになります。
こうしてループをかけることで処理を使い回して実装することが可能に。
最後に0,2~9の数字ボタン、−×÷ボタンを実装して計算できるようにします。
完成まで
まずはボタンを複製して並べます。
そして、まず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行追加します。
var regex = RegEx.new()
regex.compile("\\d")
条件判定で一々「... and $Button.text == "2" and... 」といった感じで繋げていくと大変なので、正規表現で処理します。
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に
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
var operator = "0"
operator変数を宣言。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.正規表現
まずは変数宣言部にて宣言し
var regex = RegEx.new()
次に「func _ready():」にて
func _ready():
regex.compile("\\d")
pass # Replace with function body.
Godotでは新規インスタンスを宣言した後、正規表現はcompileメソッドを用いてインスタンスに登録します。
そしてボタン関数部において
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.条件設定
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():と関数定義して外に出します。
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)
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))
後の段階は変数を置き換えていくだけです。
↑においた全体図を実行すると
ですが「1÷0=」するとエラーになるので修正して、リセットボタン「CE」も実装して
完成コードは↓になります。
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
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
以上で簡易電卓は完成です。この他にも欲しい機能がある場合は各自で付け足してみましょう。