├── 2d ├── icon.png ├── default_env.tres ├── Home.gd ├── project.godot ├── icon.png.import ├── FileMenu.tscn ├── ConfirmQuit.gd ├── ConfirmQuit.tscn ├── Home.tscn ├── Graph.gd ├── FileMenu.gd └── Graph.tscn ├── 3d ├── icon.png ├── HomeButton.gd ├── Home.gd ├── default_env.tres ├── OrbitingCamera.tscn ├── HomeButton.tscn ├── project.godot ├── icon.png.import ├── Home.tscn ├── CameraControl.gd └── OrbitingCameraScene.tscn ├── media └── 3d-camera.png ├── .gitignore ├── LICENSE └── README.md /2d/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrew-wilkes/godot-scene-templates/HEAD/2d/icon.png -------------------------------------------------------------------------------- /3d/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrew-wilkes/godot-scene-templates/HEAD/3d/icon.png -------------------------------------------------------------------------------- /media/3d-camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrew-wilkes/godot-scene-templates/HEAD/media/3d-camera.png -------------------------------------------------------------------------------- /3d/HomeButton.gd: -------------------------------------------------------------------------------- 1 | extends Button 2 | 3 | func _on_HomeButton_pressed(): 4 | var _e = get_tree().change_scene("res://Home.tscn") 5 | -------------------------------------------------------------------------------- /3d/Home.gd: -------------------------------------------------------------------------------- 1 | extends CenterContainer 2 | 3 | func _on_OrbitingCamera_pressed(): 4 | var _e = get_tree().change_scene("res://OrbitingCameraScene.tscn") 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Godot-specific ignores 3 | .import/ 4 | export.cfg 5 | export_presets.cfg 6 | 7 | # Mono-specific ignores 8 | .mono/ 9 | data_*/ 10 | -------------------------------------------------------------------------------- /2d/default_env.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Environment" load_steps=2 format=2] 2 | 3 | [sub_resource type="ProceduralSky" id=1] 4 | 5 | [resource] 6 | background_mode = 2 7 | background_sky = SubResource( 1 ) 8 | -------------------------------------------------------------------------------- /3d/default_env.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Environment" load_steps=2 format=2] 2 | 3 | [sub_resource type="ProceduralSky" id=1] 4 | 5 | [resource] 6 | background_sky = SubResource( 1 ) 7 | ambient_light_color = Color( 0.623529, 0.623529, 0.623529, 1 ) 8 | -------------------------------------------------------------------------------- /2d/Home.gd: -------------------------------------------------------------------------------- 1 | extends CenterContainer 2 | 3 | func _on_FileMenuButton_pressed(): 4 | var _e = get_tree().change_scene("res://FileMenu.tscn") 5 | 6 | 7 | func _on_ConfirmQuitButton_pressed(): 8 | var _e = get_tree().change_scene("res://ConfirmQuit.tscn") 9 | 10 | 11 | func _on_GraphButton_pressed(): 12 | var _e = get_tree().change_scene("res://Graph.tscn") 13 | -------------------------------------------------------------------------------- /3d/OrbitingCamera.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=2] 2 | 3 | [ext_resource path="res://CameraControl.gd" type="Script" id=1] 4 | 5 | [node name="OrbitingCamera" type="Spatial"] 6 | 7 | [node name="Pivot" type="Position3D" parent="."] 8 | script = ExtResource( 1 ) 9 | 10 | [node name="Camera" type="Camera" parent="Pivot"] 11 | transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 4.83841 ) 12 | -------------------------------------------------------------------------------- /3d/HomeButton.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=2] 2 | 3 | [ext_resource path="res://HomeButton.gd" type="Script" id=1] 4 | 5 | [node name="HomeButton" type="Button"] 6 | anchor_left = 1.0 7 | anchor_right = 1.0 8 | margin_left = -119.0 9 | margin_top = 50.0 10 | margin_right = -54.0 11 | margin_bottom = 70.0 12 | text = "Back to Home" 13 | script = ExtResource( 1 ) 14 | 15 | [connection signal="pressed" from="." to="." method="_on_HomeButton_pressed"] 16 | -------------------------------------------------------------------------------- /2d/project.godot: -------------------------------------------------------------------------------- 1 | ; Engine configuration file. 2 | ; It's best edited using the editor UI and not directly, 3 | ; since the parameters that go here are not all obvious. 4 | ; 5 | ; Format: 6 | ; [section] ; section goes between [] 7 | ; param=value ; assign values to parameters 8 | 9 | config_version=4 10 | 11 | [application] 12 | 13 | config/name="2D Scenes" 14 | run/main_scene="res://Home.tscn" 15 | config/icon="res://icon.png" 16 | 17 | [gui] 18 | 19 | common/drop_mouse_on_gui_input_disabled=true 20 | 21 | [physics] 22 | 23 | common/enable_pause_aware_picking=true 24 | 25 | [rendering] 26 | 27 | environment/default_clear_color=Color( 0.188235, 0.188235, 0.188235, 1 ) 28 | environment/default_environment="res://default_env.tres" 29 | -------------------------------------------------------------------------------- /3d/project.godot: -------------------------------------------------------------------------------- 1 | ; Engine configuration file. 2 | ; It's best edited using the editor UI and not directly, 3 | ; since the parameters that go here are not all obvious. 4 | ; 5 | ; Format: 6 | ; [section] ; section goes between [] 7 | ; param=value ; assign values to parameters 8 | 9 | config_version=4 10 | 11 | [application] 12 | 13 | config/name="3D Scenes" 14 | run/main_scene="res://Home.tscn" 15 | config/icon="res://icon.png" 16 | 17 | [display] 18 | 19 | window/size/width=600 20 | window/size/height=400 21 | 22 | [gui] 23 | 24 | common/drop_mouse_on_gui_input_disabled=true 25 | 26 | [physics] 27 | 28 | common/enable_pause_aware_picking=true 29 | 30 | [rendering] 31 | 32 | environment/default_clear_color=Color( 0.188235, 0.188235, 0.188235, 1 ) 33 | environment/default_environment="res://default_env.tres" 34 | -------------------------------------------------------------------------------- /2d/icon.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://icon.png" 13 | dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /3d/icon.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://icon.png" 13 | dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /3d/Home.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=3 format=2] 2 | 3 | [ext_resource path="res://Home.gd" type="Script" id=1] 4 | 5 | [sub_resource type="Theme" id=1] 6 | 7 | [node name="Scene Switcher" type="CenterContainer"] 8 | anchor_right = 1.0 9 | anchor_bottom = 1.0 10 | theme = SubResource( 1 ) 11 | script = ExtResource( 1 ) 12 | 13 | [node name="VBoxContainer" type="VBoxContainer" parent="."] 14 | margin_left = 242.0 15 | margin_top = 178.0 16 | margin_right = 358.0 17 | margin_bottom = 222.0 18 | custom_constants/separation = 10 19 | 20 | [node name="Label" type="Label" parent="VBoxContainer"] 21 | margin_right = 116.0 22 | margin_bottom = 14.0 23 | text = "MENU" 24 | align = 1 25 | 26 | [node name="OrbitingCamera" type="Button" parent="VBoxContainer"] 27 | margin_top = 24.0 28 | margin_right = 116.0 29 | margin_bottom = 44.0 30 | text = "Orbiting Camera" 31 | 32 | [connection signal="pressed" from="VBoxContainer/OrbitingCamera" to="." method="_on_OrbitingCamera_pressed"] 33 | -------------------------------------------------------------------------------- /2d/FileMenu.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=2] 2 | 3 | [ext_resource path="res://FileMenu.gd" type="Script" id=1] 4 | 5 | [node name="FileMenu" type="Control"] 6 | anchor_right = 1.0 7 | anchor_bottom = 1.0 8 | script = ExtResource( 1 ) 9 | 10 | [node name="HBox" type="HBoxContainer" parent="."] 11 | margin_right = 40.0 12 | margin_bottom = 40.0 13 | 14 | [node name="FileMenu" type="MenuButton" parent="HBox"] 15 | margin_right = 35.0 16 | margin_bottom = 40.0 17 | text = "File" 18 | 19 | [node name="SubMenu" type="PopupMenu" parent="HBox/FileMenu"] 20 | margin_right = 20.0 21 | margin_bottom = 20.0 22 | 23 | [node name="AboutMenu" type="MenuButton" parent="HBox"] 24 | margin_left = 39.0 25 | margin_right = 89.0 26 | margin_bottom = 40.0 27 | text = "About" 28 | 29 | [node name="FileDialog" type="FileDialog" parent="."] 30 | margin_right = 602.0 31 | margin_bottom = 325.0 32 | access = 2 33 | 34 | [node name="Label" type="Label" parent="."] 35 | margin_left = 23.0 36 | margin_top = 291.0 37 | margin_right = 248.0 38 | margin_bottom = 305.0 39 | -------------------------------------------------------------------------------- /2d/ConfirmQuit.gd: -------------------------------------------------------------------------------- 1 | extends Control 2 | 3 | var saved = false 4 | 5 | func _ready(): 6 | # The following may also be done via Project settings (application/project/auto_accept_quit) 7 | get_tree().set_auto_accept_quit(false) 8 | 9 | 10 | func _on_QuitButton_pressed(): 11 | try_to_quit() 12 | 13 | 14 | func _unhandled_input(event): # Or use: func _unhandled_key_input(event) maybe? 15 | if event is InputEventKey and event.pressed and event.scancode == KEY_ESCAPE: 16 | try_to_quit() 17 | 18 | 19 | # Listen for notification of quit request such as after user clicked on x of window 20 | func _notification(what): 21 | if what == MainLoop.NOTIFICATION_WM_QUIT_REQUEST: 22 | try_to_quit() 23 | 24 | 25 | func try_to_quit(): 26 | if saved: 27 | quit() 28 | else: 29 | $ConfirmationDialog.popup_centered() 30 | 31 | 32 | func _on_ConfirmationDialog_confirmed(): 33 | quit() 34 | 35 | 36 | func quit(): 37 | # Usually we write: get_tree().quit() instead of the following code 38 | get_tree().set_auto_accept_quit(true) 39 | var _e = get_tree().change_scene("res://Home.tscn") 40 | -------------------------------------------------------------------------------- /2d/ConfirmQuit.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=2] 2 | 3 | [ext_resource path="res://ConfirmQuit.gd" type="Script" id=1] 4 | 5 | [node name="ConfirmQuit" type="Control"] 6 | anchor_right = 1.0 7 | anchor_bottom = 1.0 8 | script = ExtResource( 1 ) 9 | 10 | [node name="QuitButton" type="Button" parent="."] 11 | anchor_left = 0.5 12 | anchor_top = 0.5 13 | anchor_right = 0.5 14 | anchor_bottom = 0.5 15 | margin_left = -20.0 16 | margin_top = -10.0 17 | margin_right = 20.0 18 | margin_bottom = 10.0 19 | text = "Quit" 20 | 21 | [node name="ConfirmationDialog" type="ConfirmationDialog" parent="."] 22 | margin_right = 200.0 23 | margin_bottom = 70.0 24 | dialog_text = "Quit without saving?" 25 | 26 | [node name="Label" type="Label" parent="."] 27 | margin_left = 297.0 28 | margin_top = 292.0 29 | margin_right = 482.0 30 | margin_bottom = 306.0 31 | text = "Press Esc key or this button: " 32 | 33 | [connection signal="pressed" from="QuitButton" to="." method="_on_QuitButton_pressed"] 34 | [connection signal="confirmed" from="ConfirmationDialog" to="." method="_on_ConfirmationDialog_confirmed"] 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Andrew Wilkes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Godot Scene Templates for Godot 3.x 2 | 3 | A growing collection of useful scene templates for the Godot Game Engine. 4 | 5 | For each category (2D/3D), a Home scene is provided to give a menu to navigate to the various example scenes. 6 | 7 | You can download or clone this repository to your PC to try them out. 8 | 9 | ## [2D Scenes](2d) 10 | 11 | This is demo project that may be imported into Godot. 12 | 13 | - ConfirmQuit - Popup asks for confirmation when quitting without saving 14 | - FileMenu - File Menu with example backend code and File Dialog 15 | - Graph - Example using the GraphEdit node with Graph nodes. [Tutorial](https://gdscript.com/solutions/godot-graphnode-and-graphedit-tutorial/) 16 | 17 | ## [3D Scenes](3d) 18 | - OrbitingCamera - Node Tree for easy orbiting of a Camera around a pivot point 19 | 20 | This is also a demo project that may be imported into Godot. 21 | 22 | - OrbitingCamera - Node Tree for easy orbiting of a Camera around a point using the mouse or keyboard 23 | 24 | ![3D Camera Scene](media/3d-camera.png) 25 | 26 | --- 27 | Encourage me to do more: [Buy me a coffee](https://buymeacoffee.com/gdscriptdude) 28 | 29 | See also: [GDScript Examples](https://github.com/andrew-wilkes/gdscript-examples) -------------------------------------------------------------------------------- /2d/Home.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=3 format=2] 2 | 3 | [ext_resource path="res://Home.gd" type="Script" id=1] 4 | 5 | [sub_resource type="Theme" id=1] 6 | 7 | [node name="Home" type="CenterContainer"] 8 | anchor_right = 1.0 9 | anchor_bottom = 1.0 10 | theme = SubResource( 1 ) 11 | script = ExtResource( 1 ) 12 | 13 | [node name="VBoxContainer" type="VBoxContainer" parent="."] 14 | margin_left = 465.0 15 | margin_top = 248.0 16 | margin_right = 559.0 17 | margin_bottom = 352.0 18 | custom_constants/separation = 10 19 | 20 | [node name="Label" type="Label" parent="VBoxContainer"] 21 | margin_right = 94.0 22 | margin_bottom = 14.0 23 | text = "MENU" 24 | align = 1 25 | 26 | [node name="FileMenuButton" type="Button" parent="VBoxContainer"] 27 | margin_top = 24.0 28 | margin_right = 94.0 29 | margin_bottom = 44.0 30 | text = "File Menu" 31 | 32 | [node name="ConfirmQuitButton" type="Button" parent="VBoxContainer"] 33 | margin_top = 54.0 34 | margin_right = 94.0 35 | margin_bottom = 74.0 36 | text = "Confirm Quit" 37 | 38 | [node name="GraphButton" type="Button" parent="VBoxContainer"] 39 | margin_top = 84.0 40 | margin_right = 94.0 41 | margin_bottom = 104.0 42 | text = "Graph" 43 | 44 | [connection signal="pressed" from="VBoxContainer/FileMenuButton" to="." method="_on_FileMenuButton_pressed"] 45 | [connection signal="pressed" from="VBoxContainer/ConfirmQuitButton" to="." method="_on_ConfirmQuitButton_pressed"] 46 | [connection signal="pressed" from="VBoxContainer/GraphButton" to="." method="_on_GraphButton_pressed"] 47 | -------------------------------------------------------------------------------- /3d/CameraControl.gd: -------------------------------------------------------------------------------- 1 | extends Position3D 2 | 3 | export var ROTATION_SPEED = 0.01 4 | export var PANNING_SPEED = 0.05 5 | export var ZOOMING_SPEED = 0.05 6 | 7 | enum { ROTATING, PANNING, ZOOMING } 8 | 9 | var moving = false 10 | var amount 11 | 12 | 13 | func _process(delta): 14 | delta *= 4 15 | var b = transform.basis 16 | if (Input.is_key_pressed(KEY_DOWN)): 17 | rotate(b.x.normalized(), delta) 18 | if (Input.is_key_pressed(KEY_UP)): 19 | rotate(b.x.normalized(), -delta) 20 | if (Input.is_key_pressed(KEY_RIGHT)): 21 | rotate(b.y.normalized(), delta) 22 | if (Input.is_key_pressed(KEY_LEFT)): 23 | rotate(b.y.normalized(), -delta) 24 | if (Input.is_key_pressed(KEY_Z)): 25 | $Camera.translation.z += delta 26 | if (Input.is_key_pressed(KEY_X)): 27 | $Camera.translation.z -= delta 28 | if (Input.is_key_pressed(KEY_W)): 29 | $Camera.translation.y -= delta 30 | if (Input.is_key_pressed(KEY_A)): 31 | $Camera.translation.x += delta 32 | if (Input.is_key_pressed(KEY_S)): 33 | $Camera.translation.y += delta 34 | if (Input.is_key_pressed(KEY_D)): 35 | $Camera.translation.x -= delta 36 | 37 | 38 | func _unhandled_input(event): 39 | if event is InputEventMouseButton and event.button_index == BUTTON_LEFT: 40 | if event.pressed: 41 | moving = true 42 | else: 43 | moving = false 44 | if event is InputEventMouseMotion and moving: 45 | var mode = ROTATING 46 | if Input.is_key_pressed(KEY_CONTROL): 47 | mode = ZOOMING 48 | match mode: 49 | ROTATING: 50 | var b = transform.basis 51 | rotate(b.x.normalized(), event.relative.y * ROTATION_SPEED) 52 | rotate(b.y.normalized(), event.relative.x * ROTATION_SPEED) 53 | ZOOMING: 54 | $Camera.translation.z += event.relative.y * ZOOMING_SPEED 55 | -------------------------------------------------------------------------------- /3d/OrbitingCameraScene.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://OrbitingCamera.tscn" type="PackedScene" id=1] 4 | [ext_resource path="res://HomeButton.tscn" type="PackedScene" id=2] 5 | 6 | [sub_resource type="SpatialMaterial" id=1] 7 | albedo_color = Color( 0.0705882, 0.517647, 0.619608, 1 ) 8 | 9 | [node name="OrbitingCameraScene" type="Spatial"] 10 | 11 | [node name="CSGBox" type="CSGBox" parent="."] 12 | material = SubResource( 1 ) 13 | 14 | [node name="OrbitingCamera" parent="." instance=ExtResource( 1 )] 15 | 16 | [node name="CanvasLayer" type="CanvasLayer" parent="."] 17 | 18 | [node name="Label" type="Label" parent="CanvasLayer"] 19 | anchor_top = 0.5 20 | anchor_bottom = 0.5 21 | margin_left = 23.0 22 | margin_top = -92.0 23 | margin_right = 230.0 24 | margin_bottom = 143.0 25 | text = "ROTATE 26 | 27 | UP/DOWN/LEFT/RIGHT 28 | Mouse + Left button 29 | 30 | PAN 31 | 32 | WASD 33 | Shift + Mouse + Left button 34 | 35 | ZOOM 36 | 37 | ZX 38 | Ctrl + Mouse + Left button" 39 | 40 | [node name="Title" type="Label" parent="CanvasLayer"] 41 | anchor_left = 0.5 42 | anchor_right = 0.5 43 | margin_left = -52.0 44 | margin_top = 56.0 45 | margin_right = 52.0 46 | margin_bottom = 70.0 47 | text = "Orbiting Camera" 48 | 49 | [node name="HomeButton" parent="CanvasLayer" instance=ExtResource( 2 )] 50 | margin_left = -127.0 51 | margin_top = 26.0 52 | margin_right = -28.0 53 | margin_bottom = 46.0 54 | 55 | [node name="DirectionalLight" type="DirectionalLight" parent="."] 56 | transform = Transform( 0.811972, -0.233937, -0.534767, 0.195372, 0.972252, -0.128672, 0.550029, 0, 0.835146, -6.26023, 0, 0 ) 57 | 58 | [node name="DirectionalLight2" type="DirectionalLight" parent="."] 59 | transform = Transform( -0.512741, 0.213102, 0.831676, 0.195372, 0.972252, -0.128672, -0.836018, 0.0965105, -0.540147, -6.26023, 0, 0 ) 60 | light_color = Color( 0.694118, 0.694118, 0.694118, 1 ) 61 | -------------------------------------------------------------------------------- /2d/Graph.gd: -------------------------------------------------------------------------------- 1 | extends Control 2 | 3 | onready var graph = $GraphEdit 4 | onready var gnode = $GraphNode 5 | 6 | export var SPAWN_STEP = Vector2(20, 20) 7 | var spawn_offset = SPAWN_STEP 8 | var selected_nodes = {} 9 | 10 | func _ready(): 11 | # Add buttons to the menu box 12 | # We save a bit of code here for node relocation 13 | graph.get_zoom_hbox().add_child($AddButton.duplicate()) 14 | $AddButton.queue_free() 15 | graph.get_zoom_hbox().add_child($HomeButton.duplicate()) 16 | $HomeButton.queue_free() 17 | gnode.offset = Vector2(100, 100) 18 | graph.add_child(gnode.duplicate()) 19 | gnode.hide() 20 | 21 | 22 | func _on_AddButton_pressed(): 23 | var node = gnode.duplicate() 24 | node.show() 25 | node.offset += spawn_offset 26 | spawn_offset += SPAWN_STEP 27 | graph.add_child(node) 28 | 29 | 30 | # There is a documentation bug here where "slot" should say "port" since ports are indexes of active slots 31 | func _on_GraphEdit_connection_request(from, from_slot, to, to_slot): 32 | graph.connect_node(from, from_slot, to, to_slot) 33 | 34 | 35 | func _on_GraphEdit_disconnection_request(from, from_slot, to, to_slot): 36 | graph.disconnect_node(from, from_slot, to, to_slot) 37 | 38 | 39 | func _on_GraphEdit_node_selected(node): 40 | selected_nodes[node] = true 41 | 42 | 43 | func _on_GraphEdit_node_unselected(node): 44 | selected_nodes[node] = false 45 | 46 | 47 | func _on_GraphEdit_delete_nodes_request(_nodes): 48 | # This list of _nodes is not relevant in our case 49 | # It is indicating what nodes have cancel boxes checked 50 | if selected_nodes.size() > 0: 51 | # Want to keep our original model of the node. 52 | # Normally we would implement a generator. 53 | # We don't need to iterate over keys here since it is done by default with Dictionaries 54 | for node in selected_nodes: 55 | if selected_nodes[node]: 56 | remove_connections_to_node(node) 57 | node.queue_free() 58 | selected_nodes = {} 59 | 60 | 61 | func remove_connections_to_node(node): 62 | for con in graph.get_connection_list(): 63 | if con.to == node.name or con.from == node.name: 64 | graph.disconnect_node(con.from, con.from_port, con.to, con.to_port) 65 | 66 | 67 | func _on_HomeButton_pressed(): 68 | var _e = get_tree().change_scene("res://Home.tscn") 69 | -------------------------------------------------------------------------------- /2d/FileMenu.gd: -------------------------------------------------------------------------------- 1 | extends Control 2 | 3 | enum { NO_ACTION, NEW, OPEN, SAVE, SAVE_AS, QUIT, ABOUT, SUB_MENU } 4 | 5 | onready var file_menu = find_node("FileMenu").get_popup() 6 | onready var file_dialog = find_node("FileDialog") 7 | onready var about_menu = find_node("AboutMenu").get_popup() 8 | 9 | var menu_action = NO_ACTION 10 | 11 | # This data is normally saved/loaded to/from disk as part of a resourse object 12 | var settings = { "last_dir": "", "current_file": "" } 13 | 14 | func _ready(): 15 | settings.last_dir = OS.get_system_dir(OS.SYSTEM_DIR_DOCUMENTS) 16 | var _e = file_dialog.connect("file_selected", self, "_on_FileDialog_file_selected") 17 | configure_menu() 18 | 19 | 20 | func configure_menu(): 21 | file_menu.add_item("New", NEW, KEY_MASK_CTRL | KEY_N) 22 | file_menu.add_item("Open", OPEN, KEY_MASK_CTRL | KEY_O) 23 | file_menu.add_separator() 24 | file_menu.add_item("Save", SAVE, KEY_MASK_CTRL | KEY_S) 25 | file_menu.add_item("Save As...", SAVE_AS, KEY_MASK_CTRL | KEY_MASK_SHIFT | KEY_S) 26 | file_menu.add_separator() 27 | file_menu.add_submenu_item("Sub Menu", "../SubMenu") 28 | file_menu.add_separator() 29 | file_menu.add_item("Quit", QUIT, KEY_MASK_CTRL | KEY_Q) 30 | file_menu.connect("id_pressed", self, "_on_FileMenu_id_pressed") 31 | 32 | about_menu.add_item("About", ABOUT) 33 | about_menu.connect("id_pressed", self, "_on_AboutMenu_id_pressed") 34 | 35 | var sub_menu = find_node("SubMenu") 36 | sub_menu.add_item("Submenu Item...", SUB_MENU) 37 | sub_menu.connect("id_pressed", self, "_on_SubMenu_id_pressed") 38 | 39 | 40 | func _on_FileMenu_id_pressed(id): 41 | menu_action = id 42 | match id: 43 | NEW: 44 | settings.current_file = "" 45 | $Label.set_text("New file") 46 | OPEN: 47 | do_action() 48 | SAVE: 49 | do_action() 50 | SAVE_AS: 51 | menu_action = SAVE 52 | settings.current_file = "" 53 | do_action() 54 | QUIT: 55 | var _e = get_tree().change_scene("res://Home.tscn") 56 | 57 | 58 | func do_action(): 59 | match menu_action: 60 | OPEN: 61 | file_dialog.current_dir = settings.last_dir 62 | file_dialog.current_file = settings.current_file 63 | file_dialog.mode = FileDialog.MODE_OPEN_FILE 64 | file_dialog.popup_centered() 65 | SAVE: 66 | if settings.current_file == "": 67 | file_dialog.current_dir = settings.last_dir 68 | file_dialog.current_file = "" 69 | file_dialog.mode = FileDialog.MODE_SAVE_FILE 70 | file_dialog.popup_centered() 71 | else: 72 | save_file() 73 | 74 | 75 | func _on_FileDialog_file_selected(path): 76 | settings.current_file = path.get_file() 77 | if menu_action == SAVE: 78 | save_file() 79 | else: 80 | $Label.set_text("Load file: " + settings.last_dir + "/" + settings.current_file) 81 | 82 | 83 | func save_file(): 84 | $Label.set_text("Save file: " + settings.last_dir + "/" + settings.current_file) 85 | 86 | 87 | func _on_SubMenu_id_pressed(id): 88 | $Label.set_text("Sub menu ID: %d pressed" % id) 89 | 90 | 91 | func _on_AboutMenu_id_pressed(id): 92 | $Label.set_text("About menu ID: %d pressed" % id) 93 | -------------------------------------------------------------------------------- /2d/Graph.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=5 format=2] 2 | 3 | [ext_resource path="res://Graph.gd" type="Script" id=1] 4 | [ext_resource path="res://icon.png" type="Texture" id=2] 5 | 6 | [sub_resource type="StyleBoxFlat" id=1] 7 | bg_color = Color( 0.0745098, 0.470588, 0.560784, 1 ) 8 | border_width_left = 2 9 | border_width_top = 2 10 | border_width_right = 2 11 | border_width_bottom = 2 12 | border_color = Color( 0.4, 0.572549, 0.713726, 1 ) 13 | corner_radius_top_left = 5 14 | corner_radius_top_right = 5 15 | corner_radius_bottom_right = 5 16 | corner_radius_bottom_left = 5 17 | 18 | [sub_resource type="StyleBoxFlat" id=2] 19 | bg_color = Color( 0, 0.737255, 0.65098, 1 ) 20 | border_width_left = 2 21 | border_width_top = 2 22 | border_width_right = 2 23 | border_width_bottom = 2 24 | border_color = Color( 0.12549, 0.815686, 0.831373, 1 ) 25 | corner_radius_top_left = 5 26 | corner_radius_top_right = 5 27 | corner_radius_bottom_right = 5 28 | corner_radius_bottom_left = 5 29 | 30 | [node name="Graph" type="Control"] 31 | anchor_right = 1.0 32 | anchor_bottom = 1.0 33 | script = ExtResource( 1 ) 34 | 35 | [node name="GraphEdit" type="GraphEdit" parent="."] 36 | anchor_right = 1.0 37 | anchor_bottom = 1.0 38 | mouse_filter = 1 39 | right_disconnects = true 40 | 41 | [node name="GraphNode" type="GraphNode" parent="."] 42 | margin_left = 40.0 43 | margin_top = 40.0 44 | margin_right = 133.0 45 | margin_bottom = 158.0 46 | mouse_filter = 1 47 | custom_colors/title_color = Color( 1, 1, 1, 1 ) 48 | custom_styles/frame = SubResource( 1 ) 49 | custom_styles/selectedframe = SubResource( 2 ) 50 | slot/0/left_enabled = true 51 | slot/0/left_type = 0 52 | slot/0/left_color = Color( 1, 1, 1, 1 ) 53 | slot/0/right_enabled = true 54 | slot/0/right_type = 0 55 | slot/0/right_color = Color( 1, 1, 1, 1 ) 56 | slot/1/left_enabled = true 57 | slot/1/left_type = 1 58 | slot/1/left_color = Color( 0, 1, 0, 1 ) 59 | slot/1/right_enabled = true 60 | slot/1/right_type = 1 61 | slot/1/right_color = Color( 0, 1, 0, 1 ) 62 | slot/2/left_enabled = true 63 | slot/2/left_type = 1 64 | slot/2/left_color = Color( 1, 1, 0, 1 ) 65 | slot/2/right_enabled = true 66 | slot/2/right_type = 2 67 | slot/2/right_color = Color( 1, 0, 0, 1 ) 68 | 69 | [node name="Control1" type="Control" parent="GraphNode"] 70 | margin_left = 2.0 71 | margin_top = 2.0 72 | margin_right = 91.0 73 | margin_bottom = 26.0 74 | rect_min_size = Vector2( 0, 24 ) 75 | mouse_filter = 1 76 | 77 | [node name="CenterContainer" type="CenterContainer" parent="GraphNode"] 78 | margin_left = 2.0 79 | margin_top = 27.0 80 | margin_right = 91.0 81 | margin_bottom = 91.0 82 | mouse_filter = 1 83 | 84 | [node name="TextureRect" type="TextureRect" parent="GraphNode/CenterContainer"] 85 | margin_left = 12.0 86 | margin_right = 76.0 87 | margin_bottom = 64.0 88 | texture = ExtResource( 2 ) 89 | 90 | [node name="Control2" type="Control" parent="GraphNode"] 91 | margin_left = 2.0 92 | margin_top = 92.0 93 | margin_right = 91.0 94 | margin_bottom = 116.0 95 | rect_min_size = Vector2( 0, 24 ) 96 | mouse_filter = 1 97 | 98 | [node name="AddButton" type="Button" parent="."] 99 | margin_left = 263.0 100 | margin_top = 11.0 101 | margin_right = 338.0 102 | margin_bottom = 31.0 103 | text = "Add Node" 104 | 105 | [node name="HomeButton" type="Button" parent="."] 106 | margin_right = 12.0 107 | margin_bottom = 20.0 108 | text = "Home" 109 | 110 | [connection signal="connection_request" from="GraphEdit" to="." method="_on_GraphEdit_connection_request"] 111 | [connection signal="delete_nodes_request" from="GraphEdit" to="." method="_on_GraphEdit_delete_nodes_request"] 112 | [connection signal="disconnection_request" from="GraphEdit" to="." method="_on_GraphEdit_disconnection_request"] 113 | [connection signal="node_selected" from="GraphEdit" to="." method="_on_GraphEdit_node_selected"] 114 | [connection signal="node_unselected" from="GraphEdit" to="." method="_on_GraphEdit_node_unselected"] 115 | [connection signal="pressed" from="AddButton" to="." method="_on_AddButton_pressed"] 116 | [connection signal="pressed" from="HomeButton" to="." method="_on_HomeButton_pressed"] 117 | --------------------------------------------------------------------------------