diff --git a/addons/block_code/block_code_plugin.gd b/addons/block_code/block_code_plugin.gd index 80991aa0..2140879b 100644 --- a/addons/block_code/block_code_plugin.gd +++ b/addons/block_code/block_code_plugin.gd @@ -44,7 +44,9 @@ const DISABLED_CLASSES := [ "TitleBar", "MainPanel", "BlockCodePlugin", - "BlockCategoryButton" + "BlockCategoryButton", + "CreateVariableButton", + "VariableCategoryDisplay" ] diff --git a/addons/block_code/block_script_data/block_script_data.gd b/addons/block_code/block_script_data/block_script_data.gd index 4e933c41..3502ca73 100644 --- a/addons/block_code/block_script_data/block_script_data.gd +++ b/addons/block_code/block_script_data/block_script_data.gd @@ -3,12 +3,14 @@ extends Resource @export var script_inherits: String @export var block_trees: SerializedBlockTreeNodeArray +@export var variables: Array[VariableResource] @export var generated_script: String @export var version: int -func _init(p_script_inherits: String = "", p_block_trees: SerializedBlockTreeNodeArray = null, p_generated_script: String = "", p_version = 0): +func _init(p_script_inherits: String = "", p_block_trees: SerializedBlockTreeNodeArray = null, p_variables: Array[VariableResource] = [], p_generated_script: String = "", p_version = 0): script_inherits = p_script_inherits block_trees = p_block_trees generated_script = p_generated_script + variables = p_variables version = p_version diff --git a/addons/block_code/examples/pong_game/pong_game.tscn b/addons/block_code/examples/pong_game/pong_game.tscn index 41c45314..02c6f96e 100644 --- a/addons/block_code/examples/pong_game/pong_game.tscn +++ b/addons/block_code/examples/pong_game/pong_game.tscn @@ -49,6 +49,7 @@ array = Array[ExtResource("4_qtggh")]([SubResource("Resource_uln40")]) script = ExtResource("7_uuuue") script_inherits = "SimpleCharacter" block_trees = SubResource("Resource_4j61k") +variables = Array[Resource("res://addons/block_code/ui/block_canvas/variable_resource.gd")]([]) generated_script = "extends SimpleCharacter var VAR_DICT := {} @@ -64,6 +65,7 @@ func _process(delta): move_and_slide() " +version = 0 [sub_resource type="Resource" id="Resource_d4hry"] script = ExtResource("5_wr38c") @@ -102,6 +104,7 @@ array = Array[ExtResource("4_qtggh")]([SubResource("Resource_75h61")]) script = ExtResource("7_uuuue") script_inherits = "SimpleCharacter" block_trees = SubResource("Resource_r5rk4") +variables = Array[Resource("res://addons/block_code/ui/block_canvas/variable_resource.gd")]([]) generated_script = "extends SimpleCharacter var VAR_DICT := {} @@ -117,66 +120,73 @@ func _process(delta): move_and_slide() " +version = 0 -[sub_resource type="Resource" id="Resource_lbd5h"] +[sub_resource type="Resource" id="Resource_80onm"] script = ExtResource("5_wr38c") block_class = &"StatementBlock" -serialized_props = [["block_name", "statement_block"], ["label", "StatementBlock"], ["color", Color(0.890196, 0.0588235, 0.752941, 1)], ["block_type", 2], ["position", Vector2(0, 0)], ["scope", ""], ["block_format", "Load file {file_path: STRING} as sound {name: STRING}"], ["statement", "VAR_DICT[{name}] = AudioStreamPlayer.new() -VAR_DICT[{name}].name = {name} -VAR_DICT[{name}].set_stream(load({file_path})) -add_child(VAR_DICT[{name}])"], ["defaults", {}], ["param_input_strings", { +serialized_props = [["block_name", "statement_block"], ["label", "StatementBlock"], ["color", Color(0.890196, 0.0588235, 0.752941, 1)], ["block_type", 2], ["position", Vector2(0, 0)], ["scope", ""], ["block_format", "Load file {file_path: STRING} as sound {name: STRING}"], ["statement", " +var __sound = AudioStreamPlayer.new() +__sound.name = {name} +__sound.set_stream(load({file_path})) +add_child(__sound) +"], ["defaults", {}], ["param_input_strings", { "file_path": "res://addons/block_code/examples/pong_game/assets/score.ogg", "name": "score_sound" }]] -[sub_resource type="Resource" id="Resource_6fxi6"] +[sub_resource type="Resource" id="Resource_jfgyp"] script = ExtResource("4_qtggh") -serialized_block = SubResource("Resource_lbd5h") +serialized_block = SubResource("Resource_80onm") path_child_pairs = [] -[sub_resource type="Resource" id="Resource_4ns0q"] +[sub_resource type="Resource" id="Resource_0qgyx"] script = ExtResource("5_wr38c") block_class = &"StatementBlock" -serialized_props = [["block_name", "statement_block"], ["label", "StatementBlock"], ["color", Color(0.890196, 0.0588235, 0.752941, 1)], ["block_type", 2], ["position", Vector2(0, 0)], ["scope", ""], ["block_format", "Load file {file_path: STRING} as sound {name: STRING}"], ["statement", "VAR_DICT[{name}] = AudioStreamPlayer.new() -VAR_DICT[{name}].name = {name} -VAR_DICT[{name}].set_stream(load({file_path})) -add_child(VAR_DICT[{name}])"], ["defaults", {}], ["param_input_strings", { +serialized_props = [["block_name", "statement_block"], ["label", "StatementBlock"], ["color", Color(0.890196, 0.0588235, 0.752941, 1)], ["block_type", 2], ["position", Vector2(0, 0)], ["scope", ""], ["block_format", "Load file {file_path: STRING} as sound {name: STRING}"], ["statement", " +var __sound = AudioStreamPlayer.new() +__sound.name = {name} +__sound.set_stream(load({file_path})) +add_child(__sound) +"], ["defaults", {}], ["param_input_strings", { "file_path": "res://addons/block_code/examples/pong_game/assets/wall_hit.ogg", "name": "wall_hit" }]] -[sub_resource type="Resource" id="Resource_bp15q"] +[sub_resource type="Resource" id="Resource_515lv"] script = ExtResource("4_qtggh") -serialized_block = SubResource("Resource_4ns0q") -path_child_pairs = [[NodePath("VBoxContainer/SnapPoint"), SubResource("Resource_6fxi6")]] +serialized_block = SubResource("Resource_0qgyx") +path_child_pairs = [[NodePath("VBoxContainer/SnapPoint"), SubResource("Resource_jfgyp")]] -[sub_resource type="Resource" id="Resource_qlhw3"] +[sub_resource type="Resource" id="Resource_na8wd"] script = ExtResource("5_wr38c") block_class = &"StatementBlock" -serialized_props = [["block_name", "statement_block"], ["label", "StatementBlock"], ["color", Color(0.890196, 0.0588235, 0.752941, 1)], ["block_type", 2], ["position", Vector2(0, 0)], ["scope", ""], ["block_format", "Load file {file_path: STRING} as sound {name: STRING}"], ["statement", "VAR_DICT[{name}] = AudioStreamPlayer.new() -VAR_DICT[{name}].name = {name} -VAR_DICT[{name}].set_stream(load({file_path})) -add_child(VAR_DICT[{name}])"], ["defaults", {}], ["param_input_strings", { +serialized_props = [["block_name", "statement_block"], ["label", "StatementBlock"], ["color", Color(0.890196, 0.0588235, 0.752941, 1)], ["block_type", 2], ["position", Vector2(0, 0)], ["scope", ""], ["block_format", "Load file {file_path: STRING} as sound {name: STRING}"], ["statement", " +var __sound = AudioStreamPlayer.new() +__sound.name = {name} +__sound.set_stream(load({file_path})) +add_child(__sound) +"], ["defaults", {}], ["param_input_strings", { "file_path": "res://addons/block_code/examples/pong_game/assets/paddle_hit.ogg", "name": "paddle_hit" }]] -[sub_resource type="Resource" id="Resource_4o4ck"] +[sub_resource type="Resource" id="Resource_bku44"] script = ExtResource("4_qtggh") -serialized_block = SubResource("Resource_qlhw3") -path_child_pairs = [[NodePath("VBoxContainer/SnapPoint"), SubResource("Resource_bp15q")]] +serialized_block = SubResource("Resource_na8wd") +path_child_pairs = [[NodePath("VBoxContainer/SnapPoint"), SubResource("Resource_515lv")]] -[sub_resource type="Resource" id="Resource_sltlk"] +[sub_resource type="Resource" id="Resource_2m4ct"] script = ExtResource("5_wr38c") block_class = &"EntryBlock" serialized_props = [["block_name", "ready_block"], ["label", "EntryBlock"], ["color", Color(0.980392, 0.34902, 0.337255, 1)], ["block_type", 1], ["position", Vector2(49, 42)], ["scope", ""], ["block_format", "On Ready"], ["statement", "func _ready():"], ["defaults", {}], ["param_input_strings", {}], ["signal_name", ""]] -[sub_resource type="Resource" id="Resource_wlbg2"] +[sub_resource type="Resource" id="Resource_lfbxc"] script = ExtResource("4_qtggh") -serialized_block = SubResource("Resource_sltlk") -path_child_pairs = [[NodePath("VBoxContainer/SnapPoint"), SubResource("Resource_4o4ck")]] +serialized_block = SubResource("Resource_2m4ct") +path_child_pairs = [[NodePath("VBoxContainer/SnapPoint"), SubResource("Resource_bku44")]] -[sub_resource type="Resource" id="Resource_5ftwo"] +[sub_resource type="Resource" id="Resource_0sepo"] script = ExtResource("5_wr38c") block_class = &"ParameterBlock" serialized_props = [["block_name", "parameter_block"], ["label", "Param"], ["color", Color(0.294118, 0.482353, 0.92549, 1)], ["block_type", 3], ["position", Vector2(0, 0)], ["scope", " @@ -184,12 +194,12 @@ func _on_body_entered(_body: Node): var body: NodePath = _body.get_path() "], ["block_format", "body"], ["statement", "body"], ["defaults", {}], ["variant_type", 22], ["param_input_strings", {}]] -[sub_resource type="Resource" id="Resource_2kdpe"] +[sub_resource type="Resource" id="Resource_k5cwt"] script = ExtResource("4_qtggh") -serialized_block = SubResource("Resource_5ftwo") +serialized_block = SubResource("Resource_0sepo") path_child_pairs = [] -[sub_resource type="Resource" id="Resource_282k5"] +[sub_resource type="Resource" id="Resource_uucid"] script = ExtResource("5_wr38c") block_class = &"ParameterBlock" serialized_props = [["block_name", "parameter_block"], ["label", "Param"], ["color", Color(0.294118, 0.482353, 0.92549, 1)], ["block_type", 3], ["position", Vector2(0, 0)], ["scope", " @@ -197,12 +207,12 @@ func _on_body_entered(_body: Node): var body: NodePath = _body.get_path() "], ["block_format", "body"], ["statement", "body"], ["defaults", {}], ["variant_type", 22], ["param_input_strings", {}]] -[sub_resource type="Resource" id="Resource_rofb0"] +[sub_resource type="Resource" id="Resource_64xkq"] script = ExtResource("4_qtggh") -serialized_block = SubResource("Resource_282k5") +serialized_block = SubResource("Resource_uucid") path_child_pairs = [] -[sub_resource type="Resource" id="Resource_7ldo3"] +[sub_resource type="Resource" id="Resource_76m34"] script = ExtResource("5_wr38c") block_class = &"ParameterBlock" serialized_props = [["block_name", "parameter_block"], ["label", "Param"], ["color", Color(0.294118, 0.482353, 0.92549, 1)], ["block_type", 3], ["position", Vector2(0, 0)], ["scope", ""], ["block_format", "Is {node: NODE_PATH} in group {group: STRING}"], ["statement", "get_node({node}).is_in_group({group})"], ["defaults", {}], ["variant_type", 1], ["param_input_strings", { @@ -210,17 +220,20 @@ serialized_props = [["block_name", "parameter_block"], ["label", "Param"], ["col "node": "" }]] -[sub_resource type="Resource" id="Resource_nqdjc"] +[sub_resource type="Resource" id="Resource_fmoex"] script = ExtResource("4_qtggh") -serialized_block = SubResource("Resource_7ldo3") -path_child_pairs = [[NodePath("MarginContainer/HBoxContainer/ParameterInput0/SnapPoint"), SubResource("Resource_rofb0")]] +serialized_block = SubResource("Resource_76m34") +path_child_pairs = [[NodePath("MarginContainer/HBoxContainer/ParameterInput0/SnapPoint"), SubResource("Resource_64xkq")]] -[sub_resource type="Resource" id="Resource_j6m6b"] +[sub_resource type="Resource" id="Resource_d7dfr"] script = ExtResource("5_wr38c") block_class = &"StatementBlock" -serialized_props = [["block_name", "statement_block"], ["label", "StatementBlock"], ["color", Color(0.890196, 0.0588235, 0.752941, 1)], ["block_type", 2], ["position", Vector2(0, 0)], ["scope", ""], ["block_format", "Play the sound {name: STRING} with Volume dB {db: FLOAT} and Pitch Scale {pitch: FLOAT}"], ["statement", "VAR_DICT[{name}].volume_db = {db} -VAR_DICT[{name}].pitch_scale = {pitch} -VAR_DICT[{name}].play()"], ["defaults", { +serialized_props = [["block_name", "statement_block"], ["label", "StatementBlock"], ["color", Color(0.890196, 0.0588235, 0.752941, 1)], ["block_type", 2], ["position", Vector2(0, 0)], ["scope", ""], ["block_format", "Play the sound {name: STRING} with Volume dB {db: FLOAT} and Pitch Scale {pitch: FLOAT}"], ["statement", " +var __sound_node = get_node({name}) +__sound_node.volume_db = {db} +__sound_node.pitch_scale = {pitch} +__sound_node.play() +"], ["defaults", { "db": "0.0", "pitch": "1.0" }], ["param_input_strings", { @@ -229,12 +242,12 @@ VAR_DICT[{name}].play()"], ["defaults", { "pitch": "1.0" }]] -[sub_resource type="Resource" id="Resource_scf28"] +[sub_resource type="Resource" id="Resource_oqnor"] script = ExtResource("4_qtggh") -serialized_block = SubResource("Resource_j6m6b") +serialized_block = SubResource("Resource_d7dfr") path_child_pairs = [] -[sub_resource type="Resource" id="Resource_2mpvd"] +[sub_resource type="Resource" id="Resource_uibbi"] script = ExtResource("5_wr38c") block_class = &"ParameterBlock" serialized_props = [["block_name", "parameter_block"], ["label", "Param"], ["color", Color(0.294118, 0.482353, 0.92549, 1)], ["block_type", 3], ["position", Vector2(0, 0)], ["scope", " @@ -242,12 +255,12 @@ func _on_body_entered(_body: Node): var body: NodePath = _body.get_path() "], ["block_format", "body"], ["statement", "body"], ["defaults", {}], ["variant_type", 22], ["param_input_strings", {}]] -[sub_resource type="Resource" id="Resource_1lxsg"] +[sub_resource type="Resource" id="Resource_7jqxw"] script = ExtResource("4_qtggh") -serialized_block = SubResource("Resource_2mpvd") +serialized_block = SubResource("Resource_uibbi") path_child_pairs = [] -[sub_resource type="Resource" id="Resource_jiood"] +[sub_resource type="Resource" id="Resource_nchna"] script = ExtResource("5_wr38c") block_class = &"ParameterBlock" serialized_props = [["block_name", "parameter_block"], ["label", "Param"], ["color", Color(0.294118, 0.482353, 0.92549, 1)], ["block_type", 3], ["position", Vector2(0, 0)], ["scope", ""], ["block_format", "Is {node: NODE_PATH} in group {group: STRING}"], ["statement", "get_node({node}).is_in_group({group})"], ["defaults", {}], ["variant_type", 1], ["param_input_strings", { @@ -255,17 +268,20 @@ serialized_props = [["block_name", "parameter_block"], ["label", "Param"], ["col "node": "" }]] -[sub_resource type="Resource" id="Resource_cxr6m"] +[sub_resource type="Resource" id="Resource_35nkf"] script = ExtResource("4_qtggh") -serialized_block = SubResource("Resource_jiood") -path_child_pairs = [[NodePath("MarginContainer/HBoxContainer/ParameterInput0/SnapPoint"), SubResource("Resource_1lxsg")]] +serialized_block = SubResource("Resource_nchna") +path_child_pairs = [[NodePath("MarginContainer/HBoxContainer/ParameterInput0/SnapPoint"), SubResource("Resource_7jqxw")]] -[sub_resource type="Resource" id="Resource_4luxm"] +[sub_resource type="Resource" id="Resource_fywef"] script = ExtResource("5_wr38c") block_class = &"StatementBlock" -serialized_props = [["block_name", "statement_block"], ["label", "StatementBlock"], ["color", Color(0.890196, 0.0588235, 0.752941, 1)], ["block_type", 2], ["position", Vector2(0, 0)], ["scope", ""], ["block_format", "Play the sound {name: STRING} with Volume dB {db: FLOAT} and Pitch Scale {pitch: FLOAT}"], ["statement", "VAR_DICT[{name}].volume_db = {db} -VAR_DICT[{name}].pitch_scale = {pitch} -VAR_DICT[{name}].play()"], ["defaults", { +serialized_props = [["block_name", "statement_block"], ["label", "StatementBlock"], ["color", Color(0.890196, 0.0588235, 0.752941, 1)], ["block_type", 2], ["position", Vector2(0, 0)], ["scope", ""], ["block_format", "Play the sound {name: STRING} with Volume dB {db: FLOAT} and Pitch Scale {pitch: FLOAT}"], ["statement", " +var __sound_node = get_node({name}) +__sound_node.volume_db = {db} +__sound_node.pitch_scale = {pitch} +__sound_node.play() +"], ["defaults", { "db": "0.0", "pitch": "1.0" }], ["param_input_strings", { @@ -274,36 +290,36 @@ VAR_DICT[{name}].play()"], ["defaults", { "pitch": "1.0" }]] -[sub_resource type="Resource" id="Resource_e1yr3"] +[sub_resource type="Resource" id="Resource_pucal"] script = ExtResource("4_qtggh") -serialized_block = SubResource("Resource_4luxm") +serialized_block = SubResource("Resource_fywef") path_child_pairs = [] -[sub_resource type="Resource" id="Resource_v4fm4"] +[sub_resource type="Resource" id="Resource_8nvnv"] script = ExtResource("5_wr38c") block_class = &"ControlBlock" serialized_props = [["block_name", "control_block"], ["label", "Control Block"], ["color", Color(0.270588, 0.666667, 0.94902, 1)], ["block_type", 2], ["position", Vector2(0, 0)], ["scope", ""], ["block_formats", ["if {condition: BOOL}"]], ["statements", ["if {condition}:"]], ["defaults", {}], ["param_input_strings_array", [{ "condition": false }]]] -[sub_resource type="Resource" id="Resource_2s53u"] +[sub_resource type="Resource" id="Resource_r8172"] script = ExtResource("4_qtggh") -serialized_block = SubResource("Resource_v4fm4") -path_child_pairs = [[NodePath("VBoxContainer/MarginContainer/Rows/Row0/RowHBoxContainer/RowHBox/ParameterInput0/SnapPoint"), SubResource("Resource_cxr6m")], [NodePath("VBoxContainer/MarginContainer/Rows/SnapContainer0/SnapPoint"), SubResource("Resource_e1yr3")]] +serialized_block = SubResource("Resource_8nvnv") +path_child_pairs = [[NodePath("VBoxContainer/MarginContainer/Rows/Row0/RowHBoxContainer/RowHBox/ParameterInput0/SnapPoint"), SubResource("Resource_35nkf")], [NodePath("VBoxContainer/MarginContainer/Rows/SnapContainer0/SnapPoint"), SubResource("Resource_pucal")]] -[sub_resource type="Resource" id="Resource_1st46"] +[sub_resource type="Resource" id="Resource_fl4h4"] script = ExtResource("5_wr38c") block_class = &"ControlBlock" serialized_props = [["block_name", "control_block"], ["label", "Control Block"], ["color", Color(0.270588, 0.666667, 0.94902, 1)], ["block_type", 2], ["position", Vector2(0, 0)], ["scope", ""], ["block_formats", ["if {condition: BOOL}"]], ["statements", ["if {condition}:"]], ["defaults", {}], ["param_input_strings_array", [{ "condition": false }]]] -[sub_resource type="Resource" id="Resource_ci12p"] +[sub_resource type="Resource" id="Resource_3xq0k"] script = ExtResource("4_qtggh") -serialized_block = SubResource("Resource_1st46") -path_child_pairs = [[NodePath("VBoxContainer/MarginContainer/Rows/Row0/RowHBoxContainer/RowHBox/ParameterInput0/SnapPoint"), SubResource("Resource_nqdjc")], [NodePath("VBoxContainer/MarginContainer/Rows/SnapContainer0/SnapPoint"), SubResource("Resource_scf28")], [NodePath("VBoxContainer/SnapPoint"), SubResource("Resource_2s53u")]] +serialized_block = SubResource("Resource_fl4h4") +path_child_pairs = [[NodePath("VBoxContainer/MarginContainer/Rows/Row0/RowHBoxContainer/RowHBox/ParameterInput0/SnapPoint"), SubResource("Resource_fmoex")], [NodePath("VBoxContainer/MarginContainer/Rows/SnapContainer0/SnapPoint"), SubResource("Resource_oqnor")], [NodePath("VBoxContainer/SnapPoint"), SubResource("Resource_r8172")]] -[sub_resource type="Resource" id="Resource_gpji8"] +[sub_resource type="Resource" id="Resource_eiexb"] script = ExtResource("5_wr38c") block_class = &"EntryBlock" serialized_props = [["block_name", "entry_block"], ["label", "EntryBlock"], ["color", Color(0.294118, 0.482353, 0.92549, 1)], ["block_type", 1], ["position", Vector2(50, 226)], ["scope", ""], ["block_format", "On [body: NODE_PATH] entered"], ["statement", " @@ -311,27 +327,30 @@ func _on_body_entered(_body: Node): var body: NodePath = _body.get_path() "], ["defaults", {}], ["param_input_strings", {}], ["signal_name", "body_entered"]] -[sub_resource type="Resource" id="Resource_kidbc"] +[sub_resource type="Resource" id="Resource_gg652"] script = ExtResource("4_qtggh") -serialized_block = SubResource("Resource_gpji8") -path_child_pairs = [[NodePath("VBoxContainer/TopMarginContainer/MarginContainer/HBoxContainer/ParameterOutput0/SnapPoint"), SubResource("Resource_2kdpe")], [NodePath("VBoxContainer/SnapPoint"), SubResource("Resource_ci12p")]] +serialized_block = SubResource("Resource_eiexb") +path_child_pairs = [[NodePath("VBoxContainer/TopMarginContainer/MarginContainer/HBoxContainer/ParameterOutput0/SnapPoint"), SubResource("Resource_k5cwt")], [NodePath("VBoxContainer/SnapPoint"), SubResource("Resource_3xq0k")]] -[sub_resource type="Resource" id="Resource_s53m4"] +[sub_resource type="Resource" id="Resource_py8f3"] script = ExtResource("5_wr38c") block_class = &"ParameterBlock" serialized_props = [["block_name", "parameter_block"], ["label", "Param"], ["color", Color(0.0117647, 0.666667, 0.454902, 1)], ["block_type", 3], ["position", Vector2(0, 0)], ["scope", ""], ["block_format", "Viewport Center"], ["statement", "(func (): var transform: Transform2D = get_viewport_transform(); var scale: Vector2 = transform.get_scale(); return -transform.origin / scale + get_viewport_rect().size / scale / 2).call()"], ["defaults", {}], ["variant_type", 5], ["param_input_strings", {}]] -[sub_resource type="Resource" id="Resource_l3fka"] +[sub_resource type="Resource" id="Resource_kck4x"] script = ExtResource("4_qtggh") -serialized_block = SubResource("Resource_s53m4") +serialized_block = SubResource("Resource_py8f3") path_child_pairs = [] -[sub_resource type="Resource" id="Resource_5id23"] +[sub_resource type="Resource" id="Resource_fyaul"] script = ExtResource("5_wr38c") block_class = &"StatementBlock" -serialized_props = [["block_name", "statement_block"], ["label", "StatementBlock"], ["color", Color(0.890196, 0.0588235, 0.752941, 1)], ["block_type", 2], ["position", Vector2(0, 0)], ["scope", ""], ["block_format", "Play the sound {name: STRING} with Volume dB {db: FLOAT} and Pitch Scale {pitch: FLOAT}"], ["statement", "VAR_DICT[{name}].volume_db = {db} -VAR_DICT[{name}].pitch_scale = {pitch} -VAR_DICT[{name}].play()"], ["defaults", { +serialized_props = [["block_name", "statement_block"], ["label", "StatementBlock"], ["color", Color(0.890196, 0.0588235, 0.752941, 1)], ["block_type", 2], ["position", Vector2(0, 0)], ["scope", ""], ["block_format", "Play the sound {name: STRING} with Volume dB {db: FLOAT} and Pitch Scale {pitch: FLOAT}"], ["statement", " +var __sound_node = get_node({name}) +__sound_node.volume_db = {db} +__sound_node.pitch_scale = {pitch} +__sound_node.play() +"], ["defaults", { "db": "0.0", "pitch": "1.0" }], ["param_input_strings", { @@ -340,83 +359,87 @@ VAR_DICT[{name}].play()"], ["defaults", { "pitch": "1.0" }]] -[sub_resource type="Resource" id="Resource_2xngh"] +[sub_resource type="Resource" id="Resource_1o8v3"] script = ExtResource("4_qtggh") -serialized_block = SubResource("Resource_5id23") +serialized_block = SubResource("Resource_fyaul") path_child_pairs = [] -[sub_resource type="Resource" id="Resource_4nxq2"] +[sub_resource type="Resource" id="Resource_5fsso"] script = ExtResource("5_wr38c") block_class = &"StatementBlock" serialized_props = [["block_name", "statement_block"], ["label", "StatementBlock"], ["color", Color(0.439216, 0.501961, 0.564706, 1)], ["block_type", 2], ["position", Vector2(0, 0)], ["scope", ""], ["block_format", "Set Physics Position {position: VECTOR2}"], ["statement", "PhysicsServer2D.body_set_state(get_rid(),PhysicsServer2D.BODY_STATE_TRANSFORM,Transform2D.IDENTITY.translated({position}))"], ["defaults", {}], ["param_input_strings", { "position": "960,544" }]] -[sub_resource type="Resource" id="Resource_jy6wp"] +[sub_resource type="Resource" id="Resource_uyy35"] script = ExtResource("4_qtggh") -serialized_block = SubResource("Resource_4nxq2") -path_child_pairs = [[NodePath("VBoxContainer/TopMarginContainer/MarginContainer/HBoxContainer/ParameterInput0/SnapPoint"), SubResource("Resource_l3fka")], [NodePath("VBoxContainer/SnapPoint"), SubResource("Resource_2xngh")]] +serialized_block = SubResource("Resource_5fsso") +path_child_pairs = [[NodePath("VBoxContainer/TopMarginContainer/MarginContainer/HBoxContainer/ParameterInput0/SnapPoint"), SubResource("Resource_kck4x")], [NodePath("VBoxContainer/SnapPoint"), SubResource("Resource_1o8v3")]] -[sub_resource type="Resource" id="Resource_ysjrw"] +[sub_resource type="Resource" id="Resource_f3xvu"] script = ExtResource("5_wr38c") block_class = &"EntryBlock" serialized_props = [["block_name", "entry_block"], ["label", "EntryBlock"], ["color", Color(0.941176, 0.764706, 0, 1)], ["block_type", 1], ["position", Vector2(51, 616)], ["scope", ""], ["block_format", "Define method {method_name: NIL}"], ["statement", "func {method_name}():"], ["defaults", {}], ["param_input_strings", { "method_name": "reset" }], ["signal_name", ""]] -[sub_resource type="Resource" id="Resource_y82yh"] +[sub_resource type="Resource" id="Resource_n4cap"] script = ExtResource("4_qtggh") -serialized_block = SubResource("Resource_ysjrw") -path_child_pairs = [[NodePath("VBoxContainer/SnapPoint"), SubResource("Resource_jy6wp")]] +serialized_block = SubResource("Resource_f3xvu") +path_child_pairs = [[NodePath("VBoxContainer/SnapPoint"), SubResource("Resource_uyy35")]] -[sub_resource type="Resource" id="Resource_vlu5s"] +[sub_resource type="Resource" id="Resource_gn6n3"] script = ExtResource("6_ppdc3") -array = Array[ExtResource("4_qtggh")]([SubResource("Resource_wlbg2"), SubResource("Resource_kidbc"), SubResource("Resource_y82yh")]) +array = Array[ExtResource("4_qtggh")]([SubResource("Resource_lfbxc"), SubResource("Resource_gg652"), SubResource("Resource_n4cap")]) [sub_resource type="Resource" id="Resource_hnwk2"] script = ExtResource("7_uuuue") script_inherits = "RigidBody2D" -block_trees = SubResource("Resource_vlu5s") +block_trees = SubResource("Resource_gn6n3") +variables = Array[Resource("res://addons/block_code/ui/block_canvas/variable_resource.gd")]([]) generated_script = "extends RigidBody2D -var VAR_DICT := {} func _ready(): - VAR_DICT['paddle_hit'] = AudioStreamPlayer.new() - VAR_DICT['paddle_hit'].name = 'paddle_hit' - VAR_DICT['paddle_hit'].set_stream(load('res://addons/block_code/examples/pong_game/assets/paddle_hit.ogg')) - add_child(VAR_DICT['paddle_hit']) - VAR_DICT['wall_hit'] = AudioStreamPlayer.new() - VAR_DICT['wall_hit'].name = 'wall_hit' - VAR_DICT['wall_hit'].set_stream(load('res://addons/block_code/examples/pong_game/assets/wall_hit.ogg')) - add_child(VAR_DICT['wall_hit']) - VAR_DICT['score_sound'] = AudioStreamPlayer.new() - VAR_DICT['score_sound'].name = 'score_sound' - VAR_DICT['score_sound'].set_stream(load('res://addons/block_code/examples/pong_game/assets/score.ogg')) - add_child(VAR_DICT['score_sound']) + var __sound_1 = AudioStreamPlayer.new() + __sound_1.name = 'paddle_hit' + __sound_1.set_stream(load('res://addons/block_code/examples/pong_game/assets/paddle_hit.ogg')) + add_child(__sound_1) + var __sound_2 = AudioStreamPlayer.new() + __sound_2.name = 'wall_hit' + __sound_2.set_stream(load('res://addons/block_code/examples/pong_game/assets/wall_hit.ogg')) + add_child(__sound_2) + var __sound_3 = AudioStreamPlayer.new() + __sound_3.name = 'score_sound' + __sound_3.set_stream(load('res://addons/block_code/examples/pong_game/assets/score.ogg')) + add_child(__sound_3) func _on_body_entered(_body: Node): var body: NodePath = _body.get_path() if get_node(body).is_in_group('paddles'): - VAR_DICT['paddle_hit'].volume_db = 0.0 - VAR_DICT['paddle_hit'].pitch_scale = 1.0 - VAR_DICT['paddle_hit'].play() + var __sound_node_1 = get_node('paddle_hit') + __sound_node_1.volume_db = 0.0 + __sound_node_1.pitch_scale = 1.0 + __sound_node_1.play() if get_node(body).is_in_group('walls'): - VAR_DICT['wall_hit'].volume_db = 0.0 - VAR_DICT['wall_hit'].pitch_scale = 1.0 - VAR_DICT['wall_hit'].play() + var __sound_node_2 = get_node('wall_hit') + __sound_node_2.volume_db = 0.0 + __sound_node_2.pitch_scale = 1.0 + __sound_node_2.play() func reset(): PhysicsServer2D.body_set_state(get_rid(),PhysicsServer2D.BODY_STATE_TRANSFORM,Transform2D.IDENTITY.translated((func (): var transform: Transform2D = get_viewport_transform(); var scale: Vector2 = transform.get_scale(); return -transform.origin / scale + get_viewport_rect().size / scale / 2).call())) - VAR_DICT['score_sound'].volume_db = 0.0 - VAR_DICT['score_sound'].pitch_scale = 1.0 - VAR_DICT['score_sound'].play() + var __sound_node_1 = get_node('score_sound') + __sound_node_1.volume_db = 0.0 + __sound_node_1.pitch_scale = 1.0 + __sound_node_1.play() func _init(): body_entered.connect(_on_body_entered) " +version = 0 [sub_resource type="Resource" id="Resource_tasas"] script = ExtResource("5_wr38c") @@ -516,6 +539,7 @@ array = Array[ExtResource("4_qtggh")]([SubResource("Resource_jwpt1")]) script = ExtResource("7_uuuue") script_inherits = "Area2D" block_trees = SubResource("Resource_7qerp") +variables = Array[Resource("res://addons/block_code/ui/block_canvas/variable_resource.gd")]([]) generated_script = "extends Area2D var VAR_DICT := {} @@ -531,6 +555,7 @@ func _on_body_entered(_body: Node2D): func _init(): body_entered.connect(_on_body_entered) " +version = 0 [sub_resource type="Resource" id="Resource_doveu"] script = ExtResource("5_wr38c") @@ -630,6 +655,7 @@ array = Array[ExtResource("4_qtggh")]([SubResource("Resource_uj1xx")]) script = ExtResource("7_uuuue") script_inherits = "Area2D" block_trees = SubResource("Resource_xphhp") +variables = Array[Resource("res://addons/block_code/ui/block_canvas/variable_resource.gd")]([]) generated_script = "extends Area2D var VAR_DICT := {} @@ -645,6 +671,7 @@ func _on_body_entered(_body: Node2D): func _init(): body_entered.connect(_on_body_entered) " +version = 0 [sub_resource type="Resource" id="Resource_nh5qb"] script = ExtResource("5_wr38c") @@ -748,6 +775,7 @@ array = Array[ExtResource("4_qtggh")]([SubResource("Resource_kt2b1"), SubResourc script = ExtResource("7_uuuue") script_inherits = "SimpleScoring" block_trees = SubResource("Resource_c8btv") +variables = Array[Resource("res://addons/block_code/ui/block_canvas/variable_resource.gd")]([]) generated_script = "extends SimpleScoring var VAR_DICT := {} @@ -764,6 +792,7 @@ func goal_left(): score_right += 1 " +version = 0 [node name="Pong" type="Node2D"] diff --git a/addons/block_code/instruction_tree/instruction_tree.gd b/addons/block_code/instruction_tree/instruction_tree.gd index 5122074e..f8781100 100644 --- a/addons/block_code/instruction_tree/instruction_tree.gd +++ b/addons/block_code/instruction_tree/instruction_tree.gd @@ -14,6 +14,34 @@ class TreeNode: children.append(node) +class IDHandler: + static var counts: Dictionary = {} + + static func reset(): + counts = {} + + static func get_unique_id(str: String) -> int: + if not counts.has(str): + counts[str] = 0 + + counts[str] += 1 + + return counts[str] + + static func make_unique(formatted_string: String) -> String: + var unique_string = formatted_string + var regex = RegEx.new() + regex.compile("\\b__[^\\s]+") + var ids: Dictionary = {} + for result in regex.search_all(formatted_string): + var result_string = result.get_string() + if not ids.has(result_string): + ids[result_string] = get_unique_id(result_string) + unique_string = unique_string.replace(result_string, result_string + "_%d" % ids[result_string]) + + return unique_string + + func generate_text(root_node: TreeNode, start_depth: int = 0) -> String: var out = PackedStringArray() generate_text_recursive(root_node, start_depth, out) diff --git a/addons/block_code/types/types.gd b/addons/block_code/types/types.gd index e4f6ed64..afe4c13e 100644 --- a/addons/block_code/types/types.gd +++ b/addons/block_code/types/types.gd @@ -36,6 +36,7 @@ const cast_relationships = [ [TYPE_INT, TYPE_STRING, "str(%s)"], [TYPE_FLOAT, TYPE_STRING, "str(%s)"], [TYPE_COLOR, TYPE_STRING, "str(%s)"], + [TYPE_VECTOR2, TYPE_STRING, "str(%s)"], ] # Directed graph, edges are CastGraphEdge diff --git a/addons/block_code/ui/block_canvas/node_block_canvas/node_block_canvas.gd b/addons/block_code/ui/block_canvas/node_block_canvas/node_block_canvas.gd index 27ede777..aab18d5e 100644 --- a/addons/block_code/ui/block_canvas/node_block_canvas/node_block_canvas.gd +++ b/addons/block_code/ui/block_canvas/node_block_canvas/node_block_canvas.gd @@ -3,7 +3,7 @@ class_name NodeBlockCanvas extends BlockCanvas -func generate_script_from_current_window(script_inherits: String = ""): +func generate_script_from_current_window(bsd: BlockScriptData): # TODO: implement multiple windows var current_window := _window @@ -21,9 +21,12 @@ func generate_script_from_current_window(script_inherits: String = ""): var script: String = "" - script += "extends %s\n\n" % script_inherits + script += "extends %s\n\n" % bsd.script_inherits - script += "var VAR_DICT := {}\n\n" + for variable in bsd.variables: + script += "var %s: %s\n\n" % [variable.var_name, type_string(variable.var_type)] + + script += "\n" var init_func = InstructionTree.TreeNode.new("func _init():") @@ -43,6 +46,8 @@ func _generate_script_from_entry_blocks(entry_statement: String, entry_blocks: A var signal_node: InstructionTree.TreeNode var is_empty = true + InstructionTree.IDHandler.reset() + for entry_block in entry_blocks: var next_block := entry_block.bottom_snap.get_snapped_block() diff --git a/addons/block_code/ui/block_canvas/variable_resource.gd b/addons/block_code/ui/block_canvas/variable_resource.gd new file mode 100644 index 00000000..119d4371 --- /dev/null +++ b/addons/block_code/ui/block_canvas/variable_resource.gd @@ -0,0 +1,10 @@ +class_name VariableResource +extends Resource + +@export var var_name: String +@export var var_type: Variant.Type + + +func _init(p_var_name: String = "", p_var_type: Variant.Type = TYPE_NIL): + var_name = p_var_name + var_type = p_var_type diff --git a/addons/block_code/ui/blocks/control_block/control_block.gd b/addons/block_code/ui/blocks/control_block/control_block.gd index 1b58522e..0eba1449 100644 --- a/addons/block_code/ui/blocks/control_block/control_block.gd +++ b/addons/block_code/ui/blocks/control_block/control_block.gd @@ -45,6 +45,8 @@ func get_instruction_node() -> InstructionTree.TreeNode: for pair in param_name_input_pairs_array[i]: formatted_statement = formatted_statement.replace("{%s}" % pair[0], pair[1].get_string()) + formatted_statement = InstructionTree.IDHandler.make_unique(formatted_statement) + var new_node := InstructionTree.TreeNode.new(formatted_statement) if i == 0: node = new_node diff --git a/addons/block_code/ui/blocks/parameter_block/parameter_block.gd b/addons/block_code/ui/blocks/parameter_block/parameter_block.gd index 2ee9b51f..95a2b7b4 100644 --- a/addons/block_code/ui/blocks/parameter_block/parameter_block.gd +++ b/addons/block_code/ui/blocks/parameter_block/parameter_block.gd @@ -55,6 +55,8 @@ func get_parameter_string() -> String: for pair in param_name_input_pairs: formatted_statement = formatted_statement.replace("{%s}" % pair[0], pair[1].get_string()) + formatted_statement = InstructionTree.IDHandler.make_unique(formatted_statement) + return formatted_statement diff --git a/addons/block_code/ui/blocks/statement_block/statement_block.gd b/addons/block_code/ui/blocks/statement_block/statement_block.gd index 15015795..20aa2e58 100644 --- a/addons/block_code/ui/blocks/statement_block/statement_block.gd +++ b/addons/block_code/ui/blocks/statement_block/statement_block.gd @@ -58,6 +58,8 @@ func get_instruction_node() -> InstructionTree.TreeNode: for pair in param_name_input_pairs: formatted_statement = formatted_statement.replace("{%s}" % pair[0], pair[1].get_string()) + formatted_statement = InstructionTree.IDHandler.make_unique(formatted_statement) + var statement_lines := formatted_statement.split("\n") var root: InstructionTree.TreeNode = InstructionTree.TreeNode.new(statement_lines[0]) diff --git a/addons/block_code/ui/main_panel.gd b/addons/block_code/ui/main_panel.gd index 45f0f59e..afc9ce61 100644 --- a/addons/block_code/ui/main_panel.gd +++ b/addons/block_code/ui/main_panel.gd @@ -32,6 +32,7 @@ var undo_redo: EditorUndoRedoManager: func _ready(): _picker.block_picked.connect(_drag_manager.copy_picked_block_and_drag) + _picker.variable_created.connect(_create_variable) _block_canvas.reconnect_block.connect(_drag_manager.connect_block_canvas_signals) _drag_manager.block_dropped.connect(save_script) _drag_manager.block_modified.connect(save_script) @@ -142,7 +143,7 @@ func save_script(): undo_redo.add_undo_property(_current_block_code_node.block_script, "generated_script", _current_block_code_node.block_script.generated_script) var block_trees := _block_canvas.get_canvas_block_trees() - var generated_script = _block_canvas.generate_script_from_current_window(block_script.script_inherits) + var generated_script = _block_canvas.generate_script_from_current_window(block_script) block_script.block_trees = block_trees block_script.generated_script = generated_script block_script.version = Constants.CURRENT_DATA_VERSION @@ -174,7 +175,7 @@ func _print_generated_script(): if _current_block_code_node == null: return var block_script: BlockScriptData = _current_block_code_node.block_script - var script: String = _block_canvas.generate_script_from_current_window(block_script.script_inherits) + var script: String = _block_canvas.generate_script_from_current_window(block_script) print(script) print("Debug script! (not saved)") @@ -252,3 +253,22 @@ func _set_selection(nodes: Array[Node]): EditorInterface.get_selection().clear() for node in nodes: EditorInterface.get_selection().add_node(node) + + +func _create_variable(variable: VariableResource): + if _current_block_code_node == null: + print("No script loaded to add variable to.") + return + + var block_script: BlockScriptData = _current_block_code_node.block_script + + undo_redo.create_action("Create variable %s in %s's block code script" % [variable.var_name, _current_block_code_node.get_parent().name]) + undo_redo.add_undo_property(_current_block_code_node.block_script, "variables", _current_block_code_node.block_script.variables) + + var new_variables = block_script.variables.duplicate() + new_variables.append(variable) + + undo_redo.add_do_property(_current_block_code_node.block_script, "variables", new_variables) + undo_redo.commit_action() + + _picker.reload_variables(new_variables) diff --git a/addons/block_code/ui/picker/categories/category_factory.gd b/addons/block_code/ui/picker/categories/category_factory.gd index ba85a11e..ac4ae36f 100644 --- a/addons/block_code/ui/picker/categories/category_factory.gd +++ b/addons/block_code/ui/picker/categories/category_factory.gd @@ -204,7 +204,7 @@ static func get_general_blocks() -> Array[Block]: b = BLOCKS["control_block"].instantiate() b.block_formats = ["repeat {number: INT}"] - b.statements = ["for i in {number}:"] + b.statements = ["for __i in {number}:"] b.category = "Loops" block_list.append(b) @@ -328,38 +328,6 @@ static func get_general_blocks() -> Array[Block]: #endregion #region Variables - - b = BLOCKS["statement_block"].instantiate() - b.block_format = "Set String {var: STRING} {value: STRING}" - b.statement = "VAR_DICT[{var}] = {value}" - b.category = "Variables" - block_list.append(b) - - b = BLOCKS["parameter_block"].instantiate() - b.block_format = "Get String {var: STRING}" - b.statement = "VAR_DICT[{var}]" - b.category = "Variables" - block_list.append(b) - - b = BLOCKS["statement_block"].instantiate() - b.block_format = "Set Int {var: STRING} {value: INT}" - b.statement = "VAR_DICT[{var}] = {value}" - b.category = "Variables" - block_list.append(b) - - b = BLOCKS["parameter_block"].instantiate() - b.variant_type = TYPE_INT - b.block_format = "Get Int {var: STRING}" - b.statement = "VAR_DICT[{var}]" - b.category = "Variables" - block_list.append(b) - - b = BLOCKS["parameter_block"].instantiate() - b.block_format = "To String {int: INT}" - b.statement = "str({int})" - b.category = "Variables" - block_list.append(b) - b = BLOCKS["parameter_block"].instantiate() b.variant_type = TYPE_VECTOR2 b.block_format = "Vector2 x: {x: FLOAT} y: {y: FLOAT}" @@ -455,10 +423,10 @@ static func get_general_blocks() -> Array[Block]: b.block_format = "Load file {file_path: STRING} as sound {name: STRING}" b.statement = ( """ - VAR_DICT[{name}] = AudioStreamPlayer.new() - VAR_DICT[{name}].name = {name} - VAR_DICT[{name}].set_stream(load({file_path})) - add_child(VAR_DICT[{name}]) + var __sound = AudioStreamPlayer.new() + __sound.name = {name} + __sound.set_stream(load({file_path})) + add_child(__sound) """ . dedent() ) @@ -471,9 +439,10 @@ static func get_general_blocks() -> Array[Block]: b.block_format = "Play the sound {name: STRING} with Volume dB {db: FLOAT} and Pitch Scale {pitch: FLOAT}" b.statement = ( """ - VAR_DICT[{name}].volume_db = {db} - VAR_DICT[{name}].pitch_scale = {pitch} - VAR_DICT[{name}].play() + var __sound_node = get_node({name}) + __sound_node.volume_db = {db} + __sound_node.pitch_scale = {pitch} + __sound_node.play() """ . dedent() ) @@ -513,10 +482,10 @@ static func get_general_blocks() -> Array[Block]: static func property_to_blocklist(property: Dictionary) -> Array[Block]: var block_list: Array[Block] = [] - var block_type = property.type + var variant_type = property.type - if block_type: - var type_string: String = Types.VARIANT_TYPE_TO_STRING[block_type] + if variant_type: + var type_string: String = Types.VARIANT_TYPE_TO_STRING[variant_type] var b = BLOCKS["statement_block"].instantiate() b.block_format = "Set %s to {value: %s}" % [property.name.capitalize(), type_string] @@ -531,7 +500,7 @@ static func property_to_blocklist(property: Dictionary) -> Array[Block]: block_list.append(b) b = BLOCKS["parameter_block"].instantiate() - b.block_type = block_type + b.variant_type = variant_type b.block_format = "%s" % property.name.capitalize() b.statement = "%s" % property.name b.category = property.category @@ -766,3 +735,27 @@ static func _get_input_blocks() -> Array[Block]: InputMap.action_add_event(action, event) return block_list + + +static func get_variable_blocks(variables: Array[VariableResource]): + var block_list: Array[Block] + + for variable in variables: + var type_string: String = Types.VARIANT_TYPE_TO_STRING[variable.var_type] + + var b = BLOCKS["parameter_block"].instantiate() + b.variant_type = variable.var_type + b.block_format = variable.var_name + b.statement = variable.var_name + # HACK: Color the blocks since they are outside of the normal picker system + b.color = BUILTIN_PROPS["Variables"].color + block_list.append(b) + + b = BLOCKS["statement_block"].instantiate() + b.block_type = Types.BlockType.EXECUTE + b.block_format = "Set %s to {value: %s}" % [variable.var_name, type_string] + b.statement = "%s = {value}" % [variable.var_name] + b.color = BUILTIN_PROPS["Variables"].color + block_list.append(b) + + return block_list diff --git a/addons/block_code/ui/picker/categories/variable_category/create_variable_button.gd b/addons/block_code/ui/picker/categories/variable_category/create_variable_button.gd new file mode 100644 index 00000000..85959cc9 --- /dev/null +++ b/addons/block_code/ui/picker/categories/variable_category/create_variable_button.gd @@ -0,0 +1,15 @@ +@tool +class_name CreateVariableButton +extends MarginContainer + +signal create_variable(var_name: String, var_type: String) + +@onready var _create_variable_dialog := %CreateVariableDialog + + +func _on_create_button_pressed(): + _create_variable_dialog.visible = true + + +func _on_create_variable_dialog_create_variable(var_name, var_type): + create_variable.emit(var_name, var_type) diff --git a/addons/block_code/ui/picker/categories/variable_category/create_variable_button.tscn b/addons/block_code/ui/picker/categories/variable_category/create_variable_button.tscn new file mode 100644 index 00000000..74770a6c --- /dev/null +++ b/addons/block_code/ui/picker/categories/variable_category/create_variable_button.tscn @@ -0,0 +1,20 @@ +[gd_scene load_steps=3 format=3 uid="uid://t0eoc4ekvjr1"] + +[ext_resource type="Script" path="res://addons/block_code/ui/picker/categories/variable_category/create_variable_button.gd" id="1_cw6c3"] +[ext_resource type="PackedScene" uid="uid://dbrm7wwkao0c0" path="res://addons/block_code/ui/picker/categories/variable_category/create_variable_dialog.tscn" id="2_udpg5"] + +[node name="CreateVariableButton" type="MarginContainer"] +size_flags_horizontal = 0 +theme_override_constants/margin_bottom = 12 +script = ExtResource("1_cw6c3") + +[node name="CreateButton" type="Button" parent="."] +layout_mode = 2 +text = "Create New Variable" + +[node name="CreateVariableDialog" parent="." instance=ExtResource("2_udpg5")] +unique_name_in_owner = true +visible = false + +[connection signal="pressed" from="CreateButton" to="." method="_on_create_button_pressed"] +[connection signal="create_variable" from="CreateVariableDialog" to="." method="_on_create_variable_dialog_create_variable"] diff --git a/addons/block_code/ui/picker/categories/variable_category/create_variable_dialog.gd b/addons/block_code/ui/picker/categories/variable_category/create_variable_dialog.gd new file mode 100644 index 00000000..af1db397 --- /dev/null +++ b/addons/block_code/ui/picker/categories/variable_category/create_variable_dialog.gd @@ -0,0 +1,100 @@ +@tool +extends ConfirmationDialog + +signal create_variable(var_name: String, var_type: String) + +@onready var _variable_input := %VariableInput +@onready var _type_option := %TypeOption +@onready var _messages := %Messages + +const available_types = ["STRING", "BOOL", "INT", "FLOAT", "VECTOR2", "COLOR"] + + +func _ready(): + _type_option.clear() + + for type in available_types: + _type_option.add_item(type) + + check_errors(_variable_input.text) + + +func _clear(): + _variable_input.text = "" + check_errors(_variable_input.text) + _type_option.select(0) + + +func _on_variable_input_text_changed(new_text): + get_ok_button().disabled = check_errors(new_text) + + +func check_errors(new_var_name: String) -> bool: + if new_var_name.contains(" "): + var caret_column = _variable_input.caret_column + new_var_name = new_var_name.replace(" ", "_") + _variable_input.text = new_var_name + _variable_input.caret_column = caret_column + + _messages.clear() + + var errors: Array = [] + + if new_var_name == "": + errors.append("Variable requires a name") + elif new_var_name == "_": + errors.append("Variable name cannot be a single underscore") + elif RegEx.create_from_string("^[0-9]").search(new_var_name) != null: + errors.append("Variable name cannot start with numbers") + + if new_var_name.begins_with("__"): + errors.append("Variable name cannot start with two underscores") + + if RegEx.create_from_string("[^_a-zA-Z0-9-]+").search(new_var_name) != null: + errors.append("Variable name cannot contain special characters") + + var duplicate_variable_name := false + var current_block_code = BlockCodePlugin.main_panel._current_block_code_node + if current_block_code: + var current_bsd = current_block_code.block_script + if current_bsd: + for variable in current_bsd.variables: + if variable.var_name == new_var_name: + duplicate_variable_name = true + break + + if duplicate_variable_name: + errors.append("Variable already exists") + + if errors.is_empty(): + _messages.push_context() + _messages.push_color(Color("73F27F")) + _messages.push_list(0, RichTextLabel.LIST_DOTS, false) + + _messages.add_text("Will create new variable") + + _messages.pop_context() + + return false + else: + _messages.push_context() + _messages.push_color(Color("FF786B")) + _messages.push_list(0, RichTextLabel.LIST_DOTS, false) + + for error in errors: + _messages.add_text(error) + _messages.newline() + + _messages.pop_context() + + return true + + +func _on_confirmed(): + if not check_errors(_variable_input.text): + create_variable.emit(_variable_input.text, _type_option.get_item_text(_type_option.selected)) + _clear() + + +func _on_canceled(): + _clear() diff --git a/addons/block_code/ui/picker/categories/variable_category/create_variable_dialog.tscn b/addons/block_code/ui/picker/categories/variable_category/create_variable_dialog.tscn new file mode 100644 index 00000000..f8678a2f --- /dev/null +++ b/addons/block_code/ui/picker/categories/variable_category/create_variable_dialog.tscn @@ -0,0 +1,68 @@ +[gd_scene load_steps=2 format=3 uid="uid://dbrm7wwkao0c0"] + +[ext_resource type="Script" path="res://addons/block_code/ui/picker/categories/variable_category/create_variable_dialog.gd" id="1_b52me"] + +[node name="CreateVariableDialog" type="ConfirmationDialog"] +title = "Create New Variable" +initial_position = 1 +size = Vector2i(300, 183) +visible = true +ok_button_text = "Create" +script = ExtResource("1_b52me") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +offset_left = 8.0 +offset_top = 8.0 +offset_right = 292.0 +offset_bottom = 134.0 + +[node name="GridContainer" type="GridContainer" parent="VBoxContainer"] +layout_mode = 2 +columns = 2 + +[node name="Label" type="Label" parent="VBoxContainer/GridContainer"] +layout_mode = 2 +text = "Name " + +[node name="VariableInput" type="LineEdit" parent="VBoxContainer/GridContainer"] +unique_name_in_owner = true +layout_mode = 2 + +[node name="Label2" type="Label" parent="VBoxContainer/GridContainer"] +layout_mode = 2 +text = "Type " + +[node name="TypeOption" type="OptionButton" parent="VBoxContainer/GridContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +item_count = 6 +selected = 0 +popup/item_0/text = "STRING" +popup/item_0/id = 0 +popup/item_1/text = "BOOL" +popup/item_1/id = 1 +popup/item_2/text = "INT" +popup/item_2/id = 2 +popup/item_3/text = "FLOAT" +popup/item_3/id = 3 +popup/item_4/text = "VECTOR2" +popup/item_4/id = 4 +popup/item_5/text = "COLOR" +popup/item_5/id = 5 + +[node name="ErrorsContainer" type="MarginContainer" parent="VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +theme_override_constants/margin_top = 8 + +[node name="Messages" type="RichTextLabel" parent="VBoxContainer/ErrorsContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(0, 48) +layout_mode = 2 +theme_override_constants/line_separation = 4 +fit_content = true + +[connection signal="canceled" from="." to="." method="_on_canceled"] +[connection signal="confirmed" from="." to="." method="_on_confirmed"] +[connection signal="text_changed" from="VBoxContainer/GridContainer/VariableInput" to="." method="_on_variable_input_text_changed"] diff --git a/addons/block_code/ui/picker/categories/variable_category/variable_category_display.gd b/addons/block_code/ui/picker/categories/variable_category/variable_category_display.gd new file mode 100644 index 00000000..03de2a0b --- /dev/null +++ b/addons/block_code/ui/picker/categories/variable_category/variable_category_display.gd @@ -0,0 +1,15 @@ +@tool +class_name VariableCategoryDisplay +extends BlockCategoryDisplay + +signal variable_created(variable: VariableResource) + +@onready var variable_blocks := %VariableBlocks + + +func _ready(): + super() + + +func _on_create_variable(var_name, var_type): + variable_created.emit(VariableResource.new(var_name, Types.STRING_TO_VARIANT_TYPE[var_type])) diff --git a/addons/block_code/ui/picker/categories/variable_category/variable_category_display.tscn b/addons/block_code/ui/picker/categories/variable_category/variable_category_display.tscn new file mode 100644 index 00000000..dd681c30 --- /dev/null +++ b/addons/block_code/ui/picker/categories/variable_category/variable_category_display.tscn @@ -0,0 +1,22 @@ +[gd_scene load_steps=4 format=3 uid="uid://byne4g2yvdf3"] + +[ext_resource type="PackedScene" uid="uid://duhpwtfo3k0sk" path="res://addons/block_code/ui/picker/categories/block_category_display.tscn" id="1_vermd"] +[ext_resource type="Script" path="res://addons/block_code/ui/picker/categories/variable_category/variable_category_display.gd" id="2_ggvi7"] +[ext_resource type="PackedScene" uid="uid://t0eoc4ekvjr1" path="res://addons/block_code/ui/picker/categories/variable_category/create_variable_button.tscn" id="3_gjvnq"] + +[node name="VariableCategoryDisplay" instance=ExtResource("1_vermd")] +script = ExtResource("2_ggvi7") + +[node name="CreateVariableButton" parent="VBoxContainer" index="1" instance=ExtResource("3_gjvnq")] +layout_mode = 2 + +[node name="VariableBlocks" type="VBoxContainer" parent="VBoxContainer" index="2"] +unique_name_in_owner = true +layout_mode = 2 +theme_override_constants/separation = 14 + +[node name="Spacer" type="Control" parent="VBoxContainer" index="3"] +custom_minimum_size = Vector2(0, 30) +layout_mode = 2 + +[connection signal="create_variable" from="VBoxContainer/CreateVariableButton" to="." method="_on_create_variable"] diff --git a/addons/block_code/ui/picker/picker.gd b/addons/block_code/ui/picker/picker.gd index 64d9a1b7..a18e5d4b 100644 --- a/addons/block_code/ui/picker/picker.gd +++ b/addons/block_code/ui/picker/picker.gd @@ -3,6 +3,7 @@ class_name Picker extends MarginContainer signal block_picked(block: Block) +signal variable_created(variable: VariableResource) @onready var _block_list := %BlockList @onready var _block_scroll := %BlockScroll @@ -10,6 +11,7 @@ signal block_picked(block: Block) @onready var _widget_container := %WidgetContainer var scroll_tween: Tween +var _variable_category_display: VariableCategoryDisplay = null func bsd_selected(bsd: BlockScriptData): @@ -35,6 +37,7 @@ func bsd_selected(bsd: BlockScriptData): blocks_to_add.append_array(CategoryFactory.get_inherited_blocks(parent_class)) init_picker(blocks_to_add, categories_to_add) + reload_variables(bsd.variables) func reset_picker(): @@ -60,7 +63,14 @@ func init_picker(extra_blocks: Array[Block] = [], extra_categories: Array[BlockC _category_list.add_child(block_category_button) - var block_category_display := preload("res://addons/block_code/ui/picker/categories/block_category_display.tscn").instantiate() + var block_category_display: BlockCategoryDisplay + if category.name != "Variables": + block_category_display = preload("res://addons/block_code/ui/picker/categories/block_category_display.tscn").instantiate() + else: + block_category_display = preload("res://addons/block_code/ui/picker/categories/variable_category/variable_category_display.tscn").instantiate() + block_category_display.variable_created.connect(func(variable): variable_created.emit(variable)) + _variable_category_display = block_category_display + block_category_display.category = category _block_list.add_child(block_category_display) @@ -92,3 +102,19 @@ func _category_selected(category: BlockCategory): func set_collapsed(collapsed: bool): _widget_container.visible = not collapsed + + +func reload_variables(variables: Array[VariableResource]): + if _variable_category_display: + for c in _variable_category_display.variable_blocks.get_children(): + c.queue_free() + + var i := 1 + for block in CategoryFactory.get_variable_blocks(variables): + _variable_category_display.variable_blocks.add_child(block) + block.drag_started.connect(_block_picked) + if i % 2 == 0: + var spacer := Control.new() + spacer.custom_minimum_size.y = 12 + _variable_category_display.variable_blocks.add_child(spacer) + i += 1