├── .gitattributes ├── .github └── workflows │ ├── dispatch-export.yml │ └── push-export.yml ├── .gitignore ├── addons ├── ggt-core │ ├── config.gd │ ├── config.gd.uid │ ├── config.tres │ ├── ggt.gd │ ├── ggt.gd.uid │ ├── plugin.cfg │ ├── plugin.gd │ ├── plugin.gd.uid │ ├── scenes │ │ ├── scene-data.gd │ │ ├── scene-data.gd.uid │ │ ├── scenes-history.gd │ │ └── scenes-history.gd.uid │ ├── transitions │ │ ├── progress.gd │ │ ├── progress.gd.uid │ │ ├── transitions.gd │ │ ├── transitions.gd.uid │ │ └── transitions.tscn │ └── utils │ │ ├── resource_multithread_loader.gd │ │ └── resource_multithread_loader.gd.uid └── ggt-debug-shortcuts │ ├── autoload │ ├── debug_shortcuts.gd │ ├── debug_shortcuts.gd.uid │ └── debug_shortcuts.tscn │ ├── plugin.cfg │ ├── plugin.gd │ └── plugin.gd.uid ├── assets ├── fonts │ ├── LICENSE.txt │ └── open-sans │ │ ├── open-sans-bold.ttf │ │ ├── open-sans-bold.ttf.import │ │ ├── open-sans-regular.ttf │ │ └── open-sans-regular.ttf.import └── sprites │ ├── icon.png │ └── icon.png.import ├── builds └── .gdignore ├── default_bus_layout.tres ├── export_presets.cfg ├── license.txt ├── project.godot ├── readme.md ├── release.sh ├── resources └── theme │ └── theme-main.tres └── scenes ├── gameplay ├── gameplay.gd ├── gameplay.gd.uid ├── gameplay.tscn └── pause-layer │ ├── pause-layer.gd │ ├── pause-layer.gd.uid │ ├── pause-layer.tscn │ ├── pause_button.png │ └── pause_button.png.import └── menu ├── game_version.gd ├── game_version.gd.uid ├── godot_version.gd ├── godot_version.gd.uid ├── menu.gd ├── menu.gd.uid └── menu.tscn /.gitattributes: -------------------------------------------------------------------------------- 1 | # Normalize EOL for all files that Git considers text files. 2 | * text=auto eol=lf 3 | 4 | *.hdr binary -------------------------------------------------------------------------------- /.github/workflows/dispatch-export.yml: -------------------------------------------------------------------------------- 1 | name: "Dispatch Export" 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | godot_version: 6 | description: "Godot Version" 7 | required: true 8 | default: "4.5" 9 | export_platform: 10 | description: "Export Platform - all|windows|linux|web|macos" 11 | required: true 12 | default: "all" 13 | export_folder: 14 | description: "Export Folder - Repository Path" 15 | required: true 16 | default: "." 17 | export_name: 18 | description: "Export Name" 19 | required: true 20 | default: "godot-game-template" 21 | itch_io: 22 | description: "Itch.io Build" 23 | required: false 24 | default: "false" 25 | 26 | env: 27 | GODOT_VERSION: ${{ github.event.inputs.godot_version }} 28 | EXPORT_PLATFORM: ${{ github.event.inputs.export_platform }} 29 | EXPORT_FOLDER: ${{ github.event.inputs.export_folder }} 30 | EXPORT_NAME: ${{ github.event.inputs.export_name }} 31 | ITCH_IO: ${{ github.event.inputs.itch_io }} 32 | 33 | jobs: 34 | export_windows: 35 | name: Windows Export 36 | runs-on: ubuntu-24.04 37 | if: ${{ github.event.inputs.export_platform == 'windows' || github.event.inputs.export_platform == 'all' }} 38 | container: 39 | image: barichello/godot-ci:4.5 40 | steps: 41 | - name: Checkout 42 | uses: actions/checkout@v1 43 | - name: Setup 44 | run: | 45 | mkdir -v -p ~/.local/share/godot/export_templates/ 46 | mkdir -v -p ~/.config/ 47 | mv /root/.config/godot ~/.config/godot 48 | mv /root/.local/share/godot/export_templates/${GODOT_VERSION}.stable ~/.local/share/godot/export_templates/${GODOT_VERSION}.stable 49 | - name: Windows Build 50 | run: | 51 | cd ${EXPORT_FOLDER} 52 | mkdir -v -p build/windows 53 | godot -v --export-release "Windows Desktop" ./build/windows/$EXPORT_NAME.exe 54 | - name: Upload Artifact 55 | uses: actions/upload-artifact@v1 56 | with: 57 | name: Windows 58 | path: ${{ env.EXPORT_FOLDER }}/build/windows 59 | - name: Zip Folder 60 | run: zip -r itch.zip ${{ env.EXPORT_FOLDER }}/build/windows 61 | - name: Deploy to itch.io 62 | if: ${{ env.ITCH_IO == 'true' }} 63 | uses: josephbmanley/butler-publish-itchio-action@master 64 | env: 65 | BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }} 66 | CHANNEL: windows 67 | ITCH_GAME: ${{ secrets.ITCH_GAME }} 68 | ITCH_USER: ${{ secrets.ITCH_USER }} 69 | PACKAGE: itch.zip 70 | 71 | export_linux: 72 | name: Linux Export 73 | runs-on: ubuntu-24.04 74 | if: ${{ github.event.inputs.export_platform == 'linux' || github.event.inputs.export_platform == 'all' }} 75 | container: 76 | image: barichello/godot-ci:4.5 77 | steps: 78 | - name: Checkout 79 | uses: actions/checkout@v1 80 | - name: Setup 81 | run: | 82 | mkdir -v -p ~/.local/share/godot/templates 83 | mv /root/.local/share/godot/templates/${GODOT_VERSION}.stable ~/.local/share/godot/templates/${GODOT_VERSION}.stable 84 | - name: Linux Build 85 | run: | 86 | cd ${EXPORT_FOLDER} 87 | mkdir -v -p build/linux 88 | godot -v --export-release "Linux/X11" ./build/linux/$EXPORT_NAME.x86_64 89 | - name: Upload Artifact 90 | uses: actions/upload-artifact@v1 91 | with: 92 | name: Linux 93 | path: ${{ env.EXPORT_FOLDER }}/build/linux 94 | - name: Zip Folder 95 | run: zip -r itch.zip ${{ env.EXPORT_FOLDER }}/build/linux 96 | - name: Deploy to itch.io 97 | if: ${{ env.ITCH_IO == 'true' }} 98 | uses: josephbmanley/butler-publish-itchio-action@master 99 | env: 100 | BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }} 101 | CHANNEL: linux 102 | ITCH_GAME: ${{ secrets.ITCH_GAME }} 103 | ITCH_USER: ${{ secrets.ITCH_USER }} 104 | PACKAGE: itch.zip 105 | 106 | export_web: 107 | name: Web Export 108 | runs-on: ubuntu-24.04 109 | if: ${{ github.event.inputs.export_platform == 'web' || github.event.inputs.export_platform == 'all' }} 110 | container: 111 | image: barichello/godot-ci:4.5 112 | steps: 113 | - name: Checkout 114 | uses: actions/checkout@v1 115 | - name: Setup 116 | run: | 117 | mkdir -v -p ~/.local/share/godot/export_templates/ 118 | mkdir -v -p ~/.config/ 119 | mv /root/.config/godot ~/.config/godot 120 | mv /root/.local/share/godot/export_templates/${GODOT_VERSION}.stable ~/.local/share/godot/export_templates/${GODOT_VERSION}.stable 121 | - name: Web Build 122 | run: | 123 | cd ${EXPORT_FOLDER} 124 | mkdir -v -p build/web 125 | godot -v --export-release "HTML5" ./build/web/index.html 126 | - name: Upload Artifact 127 | uses: actions/upload-artifact@v1 128 | with: 129 | name: Web 130 | path: ${{ env.EXPORT_FOLDER }}/build/web 131 | # Installing rsync is needed in order to deploy to GitHub Pages. Without it, the build will fail. 132 | - name: Install rsync 📚 133 | run: | 134 | apt-get update && apt-get install -y rsync 135 | - name: Deploy to GitHub Pages 🚀 136 | uses: JamesIves/github-pages-deploy-action@releases/v4 137 | with: 138 | BRANCH: gh-pages # The branch the action should deploy to. 139 | FOLDER: ${{ env.EXPORT_FOLDER }}/build/web # The folder the action should deploy. 140 | - name: Zip Folder 141 | run: zip -r itch.zip ${{ env.EXPORT_FOLDER }}/build/web 142 | - name: Deploy to itch.io 143 | if: ${{ env.ITCH_IO == 'true' }} 144 | uses: josephbmanley/butler-publish-itchio-action@master 145 | env: 146 | BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }} 147 | CHANNEL: HTML 148 | ITCH_GAME: ${{ secrets.ITCH_GAME }} 149 | ITCH_USER: ${{ secrets.ITCH_USER }} 150 | PACKAGE: itch.zip 151 | 152 | export_mac: 153 | name: Mac Export 154 | runs-on: ubuntu-24.04 155 | if: ${{ github.event.inputs.export_platform == 'macos' || github.event.inputs.export_platform == 'all' }} 156 | container: 157 | image: barichello/godot-ci:4.5 158 | steps: 159 | - name: Checkout 160 | uses: actions/checkout@v1 161 | - name: Setup 162 | run: | 163 | mkdir -v -p ~/.local/share/godot/export_templates/ 164 | mkdir -v -p ~/.config/ 165 | mv /root/.config/godot ~/.config/godot 166 | mv /root/.local/share/godot/export_templates/${GODOT_VERSION}.stable ~/.local/share/godot/export_templates/${GODOT_VERSION}.stable 167 | - name: Mac Build 168 | run: | 169 | cd ${EXPORT_FOLDER} 170 | mkdir -v -p build/mac 171 | godot -v --export-release "Mac OSX" ./build/mac/$EXPORT_NAME.zip 172 | - name: Upload Artifact 173 | uses: actions/upload-artifact@v1 174 | with: 175 | name: Mac 176 | path: ${{ env.EXPORT_FOLDER }}/build/mac 177 | - name: Zip Folder 178 | run: zip -r itch.zip ${{ env.EXPORT_FOLDER }}/build/mac 179 | - name: Deploy to itch.io 180 | if: ${{ env.ITCH_IO == 'true' }} 181 | uses: josephbmanley/butler-publish-itchio-action@master 182 | env: 183 | BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }} 184 | CHANNEL: mac 185 | ITCH_GAME: ${{ secrets.ITCH_GAME }} 186 | ITCH_USER: ${{ secrets.ITCH_USER }} 187 | PACKAGE: itch.zip 188 | -------------------------------------------------------------------------------- /.github/workflows/push-export.yml: -------------------------------------------------------------------------------- 1 | name: "Push Export" 2 | on: 3 | push: 4 | branches: 5 | - main 6 | # - "feature/**" 7 | env: 8 | GODOT_VERSION: 4.5 9 | EXPORT_NAME: godot-game-template 10 | ITCH_IO: false #set to true if you want to enable automatic itch.io deploy 11 | 12 | jobs: 13 | export-windows: 14 | if: true 15 | name: Windows Export 16 | runs-on: ubuntu-24.04 17 | container: 18 | image: barichello/godot-ci:4.5 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v1 22 | - name: Setup 23 | run: | 24 | mkdir -v -p ~/.local/share/godot/export_templates/ 25 | mkdir -v -p ~/.config/ 26 | mv /root/.config/godot ~/.config/godot 27 | mv /root/.local/share/godot/export_templates/${GODOT_VERSION}.stable ~/.local/share/godot/export_templates/${GODOT_VERSION}.stable 28 | - name: Windows Build 29 | run: | 30 | mkdir -v -p builds/windows 31 | godot --headless --export-release "Windows Desktop" ./builds/windows/$EXPORT_NAME.exe 32 | - name: Upload Artifact 33 | uses: actions/upload-artifact@v4 34 | with: 35 | name: windows 36 | path: builds/windows 37 | retention-days: 1 38 | - name: Zip Folder 39 | run: zip -r itch.zip builds/windows 40 | - name: Deploy to itch.io 41 | if: ${{ env.ITCH_IO=='true' }} 42 | uses: josephbmanley/butler-publish-itchio-action@master 43 | env: 44 | BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }} 45 | CHANNEL: windows 46 | ITCH_GAME: ${{ secrets.ITCH_GAME }} 47 | ITCH_USER: ${{ secrets.ITCH_USER }} 48 | PACKAGE: itch.zip 49 | 50 | export-linux: 51 | if: true 52 | name: Linux Export 53 | runs-on: ubuntu-24.04 54 | container: 55 | image: barichello/godot-ci:4.5 56 | steps: 57 | - name: Checkout 58 | uses: actions/checkout@v1 59 | - name: Setup 60 | run: | 61 | mkdir -v -p ~/.local/share/godot/export_templates/ 62 | mkdir -v -p ~/.config/ 63 | mv /root/.config/godot ~/.config/godot 64 | mv /root/.local/share/godot/export_templates/${GODOT_VERSION}.stable ~/.local/share/godot/export_templates/${GODOT_VERSION}.stable 65 | - name: Linux Build 66 | run: | 67 | mkdir -v -p builds/linux 68 | godot -v --headless --export-release "Linux/X11" ./builds/linux/$EXPORT_NAME.x86_64 69 | - name: Upload Artifact 70 | uses: actions/upload-artifact@v4 71 | with: 72 | name: linux 73 | path: builds/linux 74 | retention-days: 1 75 | - name: Zip Folder 76 | run: zip -r itch.zip builds/linux 77 | - name: Deploy to itch.io 78 | if: ${{ env.ITCH_IO=='true' }} 79 | uses: josephbmanley/butler-publish-itchio-action@master 80 | env: 81 | BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }} 82 | CHANNEL: linux 83 | ITCH_GAME: ${{ secrets.ITCH_GAME }} 84 | ITCH_USER: ${{ secrets.ITCH_USER }} 85 | PACKAGE: itch.zip 86 | 87 | export-web: 88 | if: true 89 | name: Web Export 90 | runs-on: ubuntu-24.04 91 | container: 92 | image: barichello/godot-ci:4.5 93 | steps: 94 | - name: Checkout 95 | uses: actions/checkout@v1 96 | - name: Setup 97 | run: | 98 | mkdir -v -p ~/.local/share/godot/export_templates/ 99 | mkdir -v -p ~/.config/ 100 | mv /root/.config/godot ~/.config/godot 101 | mv /root/.local/share/godot/export_templates/${GODOT_VERSION}.stable ~/.local/share/godot/export_templates/${GODOT_VERSION}.stable 102 | - name: Web Build 103 | run: | 104 | mkdir -v -p builds/web 105 | godot -v --headless --export-release "Web" ./builds/web/index.html 106 | - name: Upload Artifact 107 | uses: actions/upload-artifact@v4 108 | with: 109 | name: web 110 | path: builds/web 111 | retention-days: 1 112 | # Installing rsync is needed in order to deploy to GitHub Pages. Without it, the build will fail. 113 | - name: Install rsync 📚 114 | run: | 115 | apt-get update && apt-get install -y rsync 116 | - name: Deploy to GitHub Pages 🚀 117 | uses: JamesIves/github-pages-deploy-action@releases/v4 118 | with: 119 | BRANCH: gh-pages # The branch the action should deploy to. 120 | FOLDER: builds/web # The folder the action should deploy. 121 | - name: Zip Folder 122 | run: zip -r itch.zip builds/web 123 | - name: Deploy to itch.io 124 | if: ${{ env.ITCH_IO=='true' }} 125 | uses: josephbmanley/butler-publish-itchio-action@master 126 | env: 127 | BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }} 128 | CHANNEL: HTML 129 | ITCH_GAME: ${{ secrets.ITCH_GAME }} 130 | ITCH_USER: ${{ secrets.ITCH_USER }} 131 | PACKAGE: itch.zip 132 | 133 | export-mac: 134 | if: false # currently broken, see https://github.com/crystal-bit/godot-game-template/issues/82 135 | name: Mac Export 136 | runs-on: ubuntu-24.04 137 | container: 138 | image: barichello/godot-ci:4.5 139 | steps: 140 | - name: Checkout 141 | uses: actions/checkout@v1 142 | - name: Setup 143 | run: | 144 | mkdir -v -p ~/.local/share/godot/export_templates/ 145 | mkdir -v -p ~/.config/ 146 | mv /root/.config/godot ~/.config/godot 147 | mv /root/.local/share/godot/export_templates/${GODOT_VERSION}.stable ~/.local/share/godot/export_templates/${GODOT_VERSION}.stable 148 | - name: Mac Build 149 | run: | 150 | mkdir -v -p builds/mac 151 | godot --headless -v --export-release "macOS" ./builds/mac/$EXPORT_NAME.zip 152 | - name: Upload Artifact 153 | uses: actions/upload-artifact@v4 154 | with: 155 | name: mac 156 | path: builds/mac 157 | retention-days: 1 158 | - name: Zip Folder 159 | run: zip -r itch.zip builds/mac 160 | - name: Deploy to itch.io 161 | if: ${{ env.ITCH_IO=='true' }} 162 | uses: josephbmanley/butler-publish-itchio-action@master 163 | env: 164 | BUTLER_CREDENTIALS: ${{ secrets.BUTLER_CREDENTIALS }} 165 | CHANNEL: mac 166 | ITCH_GAME: ${{ secrets.ITCH_GAME }} 167 | ITCH_USER: ${{ secrets.ITCH_USER }} 168 | PACKAGE: itch.zip 169 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Additional files that you can ignore: 2 | # - https://github.com/github/gitignore/blob/master/Godot.gitignore 3 | 4 | # Godot-specific ignores 5 | .import/ 6 | .godot/ 7 | 8 | # Builds/export directory 9 | builds/**/* 10 | !builds/.gdignore 11 | 12 | # Imported translations (automatically generated from CSV files) 13 | *.translation 14 | 15 | # OSX 16 | .DS_Store -------------------------------------------------------------------------------- /addons/ggt-core/config.gd: -------------------------------------------------------------------------------- 1 | extends Resource 2 | 3 | @export_group("Transitions") 4 | @export var pause_scenes_on_transitions = true 5 | @export var prevent_input_on_transitions = true 6 | @export_range(0.0, 3000.0, 50.0) var transitions_minimum_duration_ms = 300.0 7 | 8 | @export_group("Scenes") 9 | @export_range(0, 10, 1) var max_history_length = 5 10 | -------------------------------------------------------------------------------- /addons/ggt-core/config.gd.uid: -------------------------------------------------------------------------------- 1 | uid://citmpdypfk2vn 2 | -------------------------------------------------------------------------------- /addons/ggt-core/config.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Resource" load_steps=2 format=3 uid="uid://dhl5vgchbcsoc"] 2 | 3 | [ext_resource type="Script" uid="uid://citmpdypfk2vn" path="res://addons/ggt-core/config.gd" id="1_awcn2"] 4 | 5 | [resource] 6 | script = ExtResource("1_awcn2") 7 | pause_scenes_on_transitions = true 8 | prevent_input_on_transitions = true 9 | transitions_minimum_duration_ms = 300.0 10 | max_history_length = 5 11 | -------------------------------------------------------------------------------- /addons/ggt-core/ggt.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | signal scene_transition_started 4 | signal scene_transition_finished 5 | 6 | const _GGT_Transitions = preload("res://addons/ggt-core/transitions/transitions.tscn") 7 | const _config = preload("res://addons/ggt-core/config.tres") 8 | 9 | @onready var _history = preload("res://addons/ggt-core/scenes/scenes-history.gd").new() 10 | @onready var _loader_mt = preload("res://addons/ggt-core/utils/resource_multithread_loader.gd").new() 11 | 12 | var _transitions: Node 13 | var _loading_start_time = 0 14 | var _changing_scene = false 15 | 16 | 17 | func _ready(): 18 | process_mode = Node.PROCESS_MODE_ALWAYS 19 | var cur_scene: Node = get_tree().current_scene 20 | _history.add(cur_scene.scene_file_path, {}) 21 | 22 | _transitions = _GGT_Transitions.instantiate() 23 | get_node("/root").call_deferred("add_child", _transitions) 24 | _loader_mt.connect("resource_stage_loaded", _transitions._on_resource_stage_loaded) 25 | 26 | 27 | func get_current_scene_data() -> GGT_SceneData: 28 | return _history.get_last_loaded_scene_data() 29 | 30 | 31 | func change_scene(new_scene: String, params = {}): 32 | if not ResourceLoader.exists(new_scene): 33 | push_error("Scene resource not found: ", new_scene) 34 | return 35 | _changing_scene = true 36 | emit_signal("scene_transition_started", new_scene, params) 37 | _history.add(new_scene, params) 38 | _loading_start_time = Time.get_ticks_msec() 39 | _transition_appear(params) 40 | _loader_mt.connect("resource_loaded", _on_resource_loaded, CONNECT_ONE_SHOT) 41 | await _transitions.transition_covered_screen 42 | _loader_mt.load_resource(new_scene) 43 | 44 | 45 | # Restart the current scene 46 | func restart_scene(): 47 | var scene_data = get_current_scene_data() 48 | change_scene(scene_data.path, scene_data.params) 49 | 50 | 51 | # Restart the current scene, but use given params 52 | func restart_scene_with_params(override_params): 53 | var scene_data = get_current_scene_data() 54 | change_scene(scene_data.path, override_params) 55 | 56 | 57 | func is_changing_scene() -> bool: 58 | return _changing_scene 59 | 60 | 61 | func _set_new_scene(resource: PackedScene): 62 | get_tree().change_scene_to_packed(resource) 63 | _transitions.fade_out() 64 | await _transitions.anim.animation_finished 65 | emit_signal("scene_transition_finished") 66 | _loading_start_time = 0 67 | _changing_scene = false 68 | 69 | 70 | func _transition_appear(params): 71 | _transitions.fade_in(params) 72 | 73 | 74 | func _on_resource_loaded(resource): 75 | if _transitions.is_transition_in_playing(): 76 | await _transitions.anim.animation_finished 77 | var load_time = Time.get_ticks_msec() - _loading_start_time # ms 78 | print( 79 | "GGT: {scn} loaded in {elapsed}ms".format({"scn": resource.resource_path, "elapsed": load_time}) 80 | ) 81 | # artificially wait some time in order to have a gentle scene transition 82 | if load_time < _config.transitions_minimum_duration_ms: 83 | await get_tree().create_timer((_config.transitions_minimum_duration_ms - load_time) / 1000.0).timeout 84 | _set_new_scene(resource) 85 | -------------------------------------------------------------------------------- /addons/ggt-core/ggt.gd.uid: -------------------------------------------------------------------------------- 1 | uid://cg0wu8g5j7s4w 2 | -------------------------------------------------------------------------------- /addons/ggt-core/plugin.cfg: -------------------------------------------------------------------------------- 1 | [plugin] 2 | 3 | name="ggt-core" 4 | description="Scene manager with transitions, multithread loader and other core utilities." 5 | author="davcri" 6 | version="v2025.06.0" 7 | script="plugin.gd" 8 | -------------------------------------------------------------------------------- /addons/ggt-core/plugin.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends EditorPlugin 3 | 4 | 5 | func _enter_tree(): 6 | pass 7 | 8 | 9 | func _enable_plugin(): 10 | add_autoload_singleton("GGT", "res://addons/ggt-core/ggt.gd") 11 | 12 | 13 | func _exit_tree(): 14 | pass 15 | 16 | 17 | func _disable_plugin(): 18 | remove_autoload_singleton("GGT") 19 | -------------------------------------------------------------------------------- /addons/ggt-core/plugin.gd.uid: -------------------------------------------------------------------------------- 1 | uid://crcv08ugnkyaj 2 | -------------------------------------------------------------------------------- /addons/ggt-core/scenes/scene-data.gd: -------------------------------------------------------------------------------- 1 | class_name GGT_SceneData 2 | extends RefCounted 3 | 4 | var path: String = "" 5 | var params = null 6 | 7 | 8 | func _to_string(): 9 | return path + " | params: " + str(params) 10 | -------------------------------------------------------------------------------- /addons/ggt-core/scenes/scene-data.gd.uid: -------------------------------------------------------------------------------- 1 | uid://c6w4hlh82c42j 2 | -------------------------------------------------------------------------------- /addons/ggt-core/scenes/scenes-history.gd: -------------------------------------------------------------------------------- 1 | extends RefCounted 2 | 3 | const config = preload("res://addons/ggt-core/config.tres") 4 | var _history: Array[GGT_SceneData] = [] 5 | 6 | 7 | func add(scene_path: String, params = null): 8 | var data = GGT_SceneData.new() 9 | data.path = scene_path 10 | data.params = params 11 | _history.push_front(data) 12 | while _history.size() > config.max_history_length: 13 | _history.pop_back() 14 | 15 | 16 | func get_last_loaded_scene_data() -> GGT_SceneData: 17 | if _history.size() == 0: 18 | return null 19 | return _history[0] 20 | -------------------------------------------------------------------------------- /addons/ggt-core/scenes/scenes-history.gd.uid: -------------------------------------------------------------------------------- 1 | uid://cq6eyps7mq2pj 2 | -------------------------------------------------------------------------------- /addons/ggt-core/transitions/progress.gd: -------------------------------------------------------------------------------- 1 | extends Control 2 | 3 | @onready var bar := $ProgressBar 4 | 5 | 6 | func is_completed(): 7 | return bar.value == bar.max_value 8 | -------------------------------------------------------------------------------- /addons/ggt-core/transitions/progress.gd.uid: -------------------------------------------------------------------------------- 1 | uid://c8ru70vkpmvyy 2 | -------------------------------------------------------------------------------- /addons/ggt-core/transitions/transitions.gd: -------------------------------------------------------------------------------- 1 | # Transitions. 2 | # You can tweak transition speed and appearance, just make sure to 3 | # update `is_displayed`. 4 | extends CanvasLayer 5 | 6 | signal progress_bar_filled 7 | signal transition_started(anim_name) 8 | signal transition_finished(anim_name) 9 | signal transition_covered_screen 10 | 11 | 12 | @onready var anim: AnimationPlayer = $AnimationPlayer 13 | @onready var progress: Control = $ColorRect/MarginContainer/Progress 14 | 15 | var target_progress: float = 0.0 16 | var config = preload("res://addons/ggt-core/config.tres") 17 | 18 | 19 | func _ready(): 20 | set_process(false) 21 | 22 | 23 | # Tells if transition is currently displayed/active 24 | func is_displayed() -> bool: 25 | var is_screen_black = $ColorRect.modulate.a == 1 26 | return anim.is_playing() or is_screen_black 27 | 28 | 29 | func is_transition_in_playing(): 30 | return anim.current_animation == "transition-in" and anim.is_playing() 31 | 32 | 33 | # appear 34 | func fade_in(params = {}): 35 | progress.hide() 36 | if params and params.get("show_progress_bar") == true: 37 | progress.show() 38 | anim.play("transition-in") 39 | 40 | 41 | # disappear 42 | func fade_out(): 43 | if progress.visible and not progress.is_completed(): 44 | await self.progress_bar_filled 45 | anim.connect( 46 | "animation_finished", Callable(self, "_on_fade_out_finished").bind(), CONNECT_ONE_SHOT 47 | ) 48 | anim.play("transition-out") 49 | 50 | 51 | func _on_fade_out_finished(cur_anim): 52 | if cur_anim == "transition-out": 53 | progress.bar.value = 0 54 | 55 | 56 | # progress_ratio: value between 0 and 1 57 | func _update_progress_bar(progress_ratio: float): 58 | set_process(true) 59 | target_progress = progress_ratio 60 | 61 | 62 | func _process(delta): 63 | progress.bar.value = move_toward(progress.bar.value, target_progress, delta) 64 | if progress.bar.value > 0.99 and target_progress == 1.0: 65 | await get_tree().create_timer(.4).timeout 66 | emit_signal("progress_bar_filled") 67 | set_process(false) 68 | 69 | 70 | # called by the scene loader 71 | func _on_resource_stage_loaded(progress_percentage: float): 72 | if progress.visible: 73 | _update_progress_bar(progress_percentage) 74 | else: 75 | pass 76 | 77 | 78 | func _on_AnimationPlayer_animation_finished(anim_name): 79 | if anim_name == "transition-out": 80 | emit_signal("transition_finished", anim_name) 81 | if config.pause_scenes_on_transitions: 82 | get_tree().paused = false 83 | elif anim_name == "transition-in": 84 | emit_signal("transition_covered_screen") 85 | 86 | 87 | func _on_AnimationPlayer_animation_started(anim_name): 88 | if anim_name == "transition-in": 89 | emit_signal("transition_started", anim_name) 90 | if config.pause_scenes_on_transitions: 91 | get_tree().paused = true 92 | 93 | 94 | # Prevents all inputs while a graphic transition is playing. 95 | func _input(_event: InputEvent): 96 | if config.prevent_input_on_transitions and is_displayed(): 97 | # prevent all input events 98 | get_viewport().set_input_as_handled() 99 | -------------------------------------------------------------------------------- /addons/ggt-core/transitions/transitions.gd.uid: -------------------------------------------------------------------------------- 1 | uid://cqeuawll14hnl 2 | -------------------------------------------------------------------------------- /addons/ggt-core/transitions/transitions.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=11 format=3 uid="uid://82fiitkfc6wn"] 2 | 3 | [ext_resource type="FontFile" uid="uid://cawekr44fruhm" path="res://assets/fonts/open-sans/open-sans-regular.ttf" id="1"] 4 | [ext_resource type="Script" uid="uid://c8ru70vkpmvyy" path="res://addons/ggt-core/transitions/progress.gd" id="3"] 5 | [ext_resource type="Script" uid="uid://cqeuawll14hnl" path="res://addons/ggt-core/transitions/transitions.gd" id="4"] 6 | 7 | [sub_resource type="FontFile" id="4"] 8 | fallbacks = Array[Font]([ExtResource("1")]) 9 | subpixel_positioning = 0 10 | msdf_pixel_range = 14 11 | msdf_size = 128 12 | cache/0/16/0/ascent = 0.0 13 | cache/0/16/0/descent = 0.0 14 | cache/0/16/0/underline_position = 0.0 15 | cache/0/16/0/underline_thickness = 0.0 16 | cache/0/16/0/scale = 1.0 17 | cache/0/16/0/kerning_overrides/16/0 = Vector2(0, 0) 18 | cache/0/16/0/kerning_overrides/28/0 = Vector2(0, 0) 19 | cache/0/28/0/ascent = 0.0 20 | cache/0/28/0/descent = 0.0 21 | cache/0/28/0/underline_position = 0.0 22 | cache/0/28/0/underline_thickness = 0.0 23 | cache/0/28/0/scale = 1.0 24 | cache/0/28/0/kerning_overrides/16/0 = Vector2(0, 0) 25 | cache/0/28/0/kerning_overrides/28/0 = Vector2(0, 0) 26 | 27 | [sub_resource type="Animation" id="10"] 28 | length = 0.001 29 | tracks/0/type = "value" 30 | tracks/0/imported = false 31 | tracks/0/enabled = true 32 | tracks/0/path = NodePath("ColorRect:color") 33 | tracks/0/interp = 1 34 | tracks/0/loop_wrap = true 35 | tracks/0/keys = { 36 | "times": PackedFloat32Array(0), 37 | "transitions": PackedFloat32Array(1), 38 | "update": 0, 39 | "values": [Color(0.0862745, 0.0862745, 0.0862745, 0)] 40 | } 41 | tracks/1/type = "value" 42 | tracks/1/imported = false 43 | tracks/1/enabled = true 44 | tracks/1/path = NodePath("ColorRect:modulate") 45 | tracks/1/interp = 1 46 | tracks/1/loop_wrap = true 47 | tracks/1/keys = { 48 | "times": PackedFloat32Array(0), 49 | "transitions": PackedFloat32Array(1), 50 | "update": 0, 51 | "values": [Color(1, 1, 1, 0)] 52 | } 53 | tracks/2/type = "value" 54 | tracks/2/imported = false 55 | tracks/2/enabled = true 56 | tracks/2/path = NodePath("ColorRect/MarginContainer/Progress/ProgressBar:modulate") 57 | tracks/2/interp = 1 58 | tracks/2/loop_wrap = true 59 | tracks/2/keys = { 60 | "times": PackedFloat32Array(0), 61 | "transitions": PackedFloat32Array(1), 62 | "update": 0, 63 | "values": [Color(1, 1, 1, 0)] 64 | } 65 | 66 | [sub_resource type="Animation" id="5"] 67 | length = 0.001 68 | tracks/0/type = "value" 69 | tracks/0/imported = false 70 | tracks/0/enabled = true 71 | tracks/0/path = NodePath("ColorRect:color") 72 | tracks/0/interp = 1 73 | tracks/0/loop_wrap = true 74 | tracks/0/keys = { 75 | "times": PackedFloat32Array(0), 76 | "transitions": PackedFloat32Array(1), 77 | "update": 0, 78 | "values": [Color(0.0862745, 0.0862745, 0.0862745, 1)] 79 | } 80 | tracks/1/type = "value" 81 | tracks/1/imported = false 82 | tracks/1/enabled = true 83 | tracks/1/path = NodePath("ColorRect:modulate") 84 | tracks/1/interp = 1 85 | tracks/1/loop_wrap = true 86 | tracks/1/keys = { 87 | "times": PackedFloat32Array(0), 88 | "transitions": PackedFloat32Array(1), 89 | "update": 0, 90 | "values": [Color(1, 1, 1, 1)] 91 | } 92 | 93 | [sub_resource type="Animation" id="6"] 94 | resource_name = "transition-in" 95 | length = 0.3 96 | step = 0.05 97 | tracks/0/type = "value" 98 | tracks/0/imported = false 99 | tracks/0/enabled = true 100 | tracks/0/path = NodePath("ColorRect:color") 101 | tracks/0/interp = 1 102 | tracks/0/loop_wrap = true 103 | tracks/0/keys = { 104 | "times": PackedFloat32Array(0, 0.2), 105 | "transitions": PackedFloat32Array(1, 1), 106 | "update": 0, 107 | "values": [Color(0.0862745, 0.0862745, 0.0862745, 0), Color(0.0862745, 0.0862745, 0.0862745, 1)] 108 | } 109 | tracks/1/type = "value" 110 | tracks/1/imported = false 111 | tracks/1/enabled = true 112 | tracks/1/path = NodePath("ColorRect:modulate") 113 | tracks/1/interp = 1 114 | tracks/1/loop_wrap = true 115 | tracks/1/keys = { 116 | "times": PackedFloat32Array(0, 0.2), 117 | "transitions": PackedFloat32Array(1, 1), 118 | "update": 0, 119 | "values": [Color(1, 1, 1, 0), Color(1, 1, 1, 1)] 120 | } 121 | tracks/2/type = "value" 122 | tracks/2/imported = false 123 | tracks/2/enabled = true 124 | tracks/2/path = NodePath("ColorRect/MarginContainer/Progress/ProgressBar:modulate") 125 | tracks/2/interp = 1 126 | tracks/2/loop_wrap = true 127 | tracks/2/keys = { 128 | "times": PackedFloat32Array(0, 0.2, 0.3), 129 | "transitions": PackedFloat32Array(1, 2, 1), 130 | "update": 0, 131 | "values": [Color(1, 1, 1, 0), Color(1, 1, 1, 0), Color(1, 1, 1, 1)] 132 | } 133 | 134 | [sub_resource type="Animation" id="7"] 135 | length = 0.3 136 | step = 0.05 137 | tracks/0/type = "value" 138 | tracks/0/imported = false 139 | tracks/0/enabled = true 140 | tracks/0/path = NodePath("ColorRect:modulate") 141 | tracks/0/interp = 1 142 | tracks/0/loop_wrap = true 143 | tracks/0/keys = { 144 | "times": PackedFloat32Array(0, 0.1, 0.3), 145 | "transitions": PackedFloat32Array(1, 1, 1), 146 | "update": 0, 147 | "values": [Color(1, 1, 1, 1), Color(1, 1, 1, 1), Color(1, 1, 1, 0)] 148 | } 149 | tracks/1/type = "value" 150 | tracks/1/imported = false 151 | tracks/1/enabled = true 152 | tracks/1/path = NodePath("ColorRect:color") 153 | tracks/1/interp = 1 154 | tracks/1/loop_wrap = true 155 | tracks/1/keys = { 156 | "times": PackedFloat32Array(0, 0.1, 0.3), 157 | "transitions": PackedFloat32Array(1, 1, 1), 158 | "update": 0, 159 | "values": [Color(0.0862745, 0.0862745, 0.0862745, 1), Color(0.0862745, 0.0862745, 0.0862745, 1), Color(0.0862745, 0.0862745, 0.0862745, 0)] 160 | } 161 | tracks/2/type = "value" 162 | tracks/2/imported = false 163 | tracks/2/enabled = true 164 | tracks/2/path = NodePath("ColorRect/MarginContainer/Progress/ProgressBar:modulate") 165 | tracks/2/interp = 1 166 | tracks/2/loop_wrap = true 167 | tracks/2/keys = { 168 | "times": PackedFloat32Array(0, 0.1), 169 | "transitions": PackedFloat32Array(0.5, 1), 170 | "update": 0, 171 | "values": [Color(1, 1, 1, 1), Color(1, 1, 1, 0)] 172 | } 173 | 174 | [sub_resource type="Animation" id="8"] 175 | length = 0.001 176 | tracks/0/type = "value" 177 | tracks/0/imported = false 178 | tracks/0/enabled = true 179 | tracks/0/path = NodePath("ColorRect:color") 180 | tracks/0/interp = 1 181 | tracks/0/loop_wrap = true 182 | tracks/0/keys = { 183 | "times": PackedFloat32Array(0), 184 | "transitions": PackedFloat32Array(1), 185 | "update": 0, 186 | "values": [Color(0.0862745, 0.0862745, 0.0862745, 0)] 187 | } 188 | tracks/1/type = "value" 189 | tracks/1/imported = false 190 | tracks/1/enabled = true 191 | tracks/1/path = NodePath("ColorRect:modulate") 192 | tracks/1/interp = 1 193 | tracks/1/loop_wrap = true 194 | tracks/1/keys = { 195 | "times": PackedFloat32Array(0), 196 | "transitions": PackedFloat32Array(1), 197 | "update": 0, 198 | "values": [Color(1, 1, 1, 0)] 199 | } 200 | 201 | [sub_resource type="AnimationLibrary" id="AnimationLibrary_y1dc8"] 202 | _data = { 203 | &"RESET": SubResource("10"), 204 | &"black": SubResource("5"), 205 | &"transition-in": SubResource("6"), 206 | &"transition-out": SubResource("7"), 207 | &"transparent": SubResource("8") 208 | } 209 | 210 | [node name="GGT_Transitions" type="CanvasLayer"] 211 | process_mode = 3 212 | layer = 100 213 | script = ExtResource("4") 214 | 215 | [node name="ColorRect" type="ColorRect" parent="."] 216 | modulate = Color(1, 1, 1, 0) 217 | anchors_preset = 15 218 | anchor_right = 1.0 219 | anchor_bottom = 1.0 220 | mouse_filter = 2 221 | color = Color(0.0862745, 0.0862745, 0.0862745, 0) 222 | 223 | [node name="MarginContainer" type="MarginContainer" parent="ColorRect"] 224 | layout_mode = 1 225 | anchors_preset = 15 226 | anchor_right = 1.0 227 | anchor_bottom = 1.0 228 | grow_horizontal = 2 229 | grow_vertical = 2 230 | mouse_filter = 2 231 | 232 | [node name="Progress" type="Control" parent="ColorRect/MarginContainer"] 233 | layout_mode = 2 234 | mouse_filter = 2 235 | script = ExtResource("3") 236 | 237 | [node name="ProgressBar" type="ProgressBar" parent="ColorRect/MarginContainer/Progress"] 238 | modulate = Color(1, 1, 1, 0) 239 | layout_mode = 1 240 | anchors_preset = 3 241 | anchor_left = 1.0 242 | anchor_top = 1.0 243 | anchor_right = 1.0 244 | anchor_bottom = 1.0 245 | offset_left = -170.0 246 | offset_top = -27.0 247 | grow_horizontal = 0 248 | grow_vertical = 0 249 | mouse_filter = 2 250 | theme_override_fonts/font = SubResource("4") 251 | theme_override_font_sizes/font_size = 16 252 | max_value = 1.0 253 | 254 | [node name="AnimationPlayer" type="AnimationPlayer" parent="."] 255 | libraries = { 256 | &"": SubResource("AnimationLibrary_y1dc8") 257 | } 258 | autoplay = "transparent" 259 | 260 | [connection signal="animation_finished" from="AnimationPlayer" to="." method="_on_AnimationPlayer_animation_finished"] 261 | [connection signal="animation_started" from="AnimationPlayer" to="." method="_on_AnimationPlayer_animation_started"] 262 | -------------------------------------------------------------------------------- /addons/ggt-core/utils/resource_multithread_loader.gd: -------------------------------------------------------------------------------- 1 | extends RefCounted 2 | 3 | signal resource_loaded(res) 4 | signal resource_stage_loaded(progress_percentage) 5 | 6 | const SIMULATED_DELAY_MS = 32 7 | 8 | var thread 9 | var stages_amount: int 10 | 11 | 12 | func load_resource(path): 13 | if OS.has_feature("web"): 14 | _handle_load(path, true) 15 | else: 16 | if thread == null: 17 | thread = Thread.new() 18 | if ResourceLoader.has_cached(path): 19 | return ResourceLoader.load(path) 20 | else: 21 | _load_resource_threaded(path) 22 | 23 | 24 | func _load_resource_threaded(path): 25 | var state = thread.start(Callable(self, "_handle_load").bind(path, false)) 26 | if state != OK: 27 | push_error("Error while starting thread: " + str(state)) 28 | 29 | 30 | func _handle_load(path, runs_on_main_thread: bool): 31 | var status = ResourceLoader.load_threaded_request(path) 32 | if status != OK: 33 | push_error(status, "resource request failed") 34 | return 35 | 36 | var res = null 37 | var progress_arr = [] 38 | 39 | while true: 40 | var loading_status = ResourceLoader.load_threaded_get_status(path, progress_arr) 41 | 42 | if loading_status == ResourceLoader.THREAD_LOAD_LOADED: 43 | call_deferred("emit_signal", "resource_stage_loaded", float(progress_arr[0])) 44 | res = ResourceLoader.load_threaded_get(path) 45 | break 46 | elif loading_status == ResourceLoader.THREAD_LOAD_FAILED: 47 | push_error("Load failed for: {0}".format([path])) 48 | return 49 | elif loading_status == ResourceLoader.THREAD_LOAD_INVALID_RESOURCE: 50 | push_error("Invalid resource: {0}".format([path])) 51 | return 52 | 53 | if runs_on_main_thread: 54 | await Engine.get_main_loop().create_timer(SIMULATED_DELAY_MS / 1000.0).timeout 55 | else: 56 | OS.delay_msec(SIMULATED_DELAY_MS) 57 | call_deferred("_thread_done", res) 58 | 59 | 60 | func _thread_done(resource): 61 | assert(resource) 62 | if thread: 63 | # Always wait for threads to finish, this is required on Windows. 64 | thread.wait_to_finish() 65 | emit_signal("resource_loaded", resource) 66 | -------------------------------------------------------------------------------- /addons/ggt-core/utils/resource_multithread_loader.gd.uid: -------------------------------------------------------------------------------- 1 | uid://0q25p462cdvq 2 | -------------------------------------------------------------------------------- /addons/ggt-debug-shortcuts/autoload/debug_shortcuts.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | var _advancing_frame = false 4 | var stepped_frames = 0 5 | 6 | 7 | func _ready(): 8 | if OS.is_debug_build() == false: 9 | queue_free() 10 | 11 | 12 | func _unhandled_input(event: InputEvent) -> void: 13 | if _advancing_frame: 14 | return 15 | 16 | if event is InputEventKey: 17 | if event.is_action_pressed("ggt_debug_pause_game"): 18 | get_tree().paused = !get_tree().paused 19 | stepped_frames = 0 20 | if get_tree().paused: 21 | %Label.text = "paused" 22 | else: 23 | %Label.text = "" 24 | elif event.is_action_pressed("ggt_debug_step_frame"): 25 | frame_advance() 26 | elif event.is_action_pressed("ggt_debug_quit_game"): 27 | get_tree().quit() 28 | elif event.is_action_pressed("ggt_debug_restart_scene"): 29 | var ggt = get_node_or_null("/root/GGT") 30 | # if "ggt-core" addon is enabled 31 | if ggt: 32 | ggt.restart_scene() 33 | else: 34 | get_tree().reload_current_scene() 35 | elif event.is_action_pressed("ggt_debug_speedup_game"): 36 | Engine.time_scale = 2 # if your gameplay changes timescale, then you probably want to create a time scale manager script to avoid issues 37 | %Label.text = "Time scale 2x" 38 | elif event.is_action_released("ggt_debug_speedup_game"): 39 | Engine.time_scale = 1 40 | %Label.text = "" 41 | 42 | 43 | func frame_advance(): 44 | if get_tree().paused: 45 | stepped_frames += 1 46 | _advancing_frame = true 47 | get_tree().paused = false 48 | await get_tree().process_frame 49 | await get_tree().physics_frame 50 | get_tree().paused = true 51 | _advancing_frame = false 52 | %Label.text = "paused - stepped %d frames" % stepped_frames 53 | -------------------------------------------------------------------------------- /addons/ggt-debug-shortcuts/autoload/debug_shortcuts.gd.uid: -------------------------------------------------------------------------------- 1 | uid://cwg070drxkjf2 2 | -------------------------------------------------------------------------------- /addons/ggt-debug-shortcuts/autoload/debug_shortcuts.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://dwudswealbjw5"] 2 | 3 | [ext_resource type="Script" uid="uid://cwg070drxkjf2" path="res://addons/ggt-debug-shortcuts/autoload/debug_shortcuts.gd" id="1_h8jbq"] 4 | 5 | [node name="DebugShortcuts" type="Node"] 6 | process_mode = 3 7 | process_priority = -1 8 | process_physics_priority = -1 9 | editor_description = "Node automatically removed on release builds." 10 | script = ExtResource("1_h8jbq") 11 | 12 | [node name="CanvasLayer" type="CanvasLayer" parent="."] 13 | layer = 4096 14 | 15 | [node name="Label" type="Label" parent="CanvasLayer"] 16 | unique_name_in_owner = true 17 | anchors_preset = 2 18 | anchor_top = 1.0 19 | anchor_bottom = 1.0 20 | offset_left = 16.0 21 | offset_top = -44.0 22 | offset_right = 56.0 23 | offset_bottom = -16.0 24 | grow_vertical = 0 25 | vertical_alignment = 2 26 | -------------------------------------------------------------------------------- /addons/ggt-debug-shortcuts/plugin.cfg: -------------------------------------------------------------------------------- 1 | [plugin] 2 | 3 | name="ggt-debug-shortcuts" 4 | description="Shortcuts for quicker development and debugging." 5 | author="davcri" 6 | version="v2025.06.0" 7 | script="plugin.gd" 8 | -------------------------------------------------------------------------------- /addons/ggt-debug-shortcuts/plugin.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends EditorPlugin 3 | 4 | 5 | # this will be loaded only on the first plugin activation. If you want to 6 | # change the KEYS than use Project -> Project Settings -> Input Map 7 | const default_debug_shortcuts = { 8 | "input/ggt_debug_restart_scene": KEY_R, 9 | "input/ggt_debug_pause_game": KEY_P, 10 | "input/ggt_debug_quit_game": KEY_Q, 11 | "input/ggt_debug_speedup_game": KEY_SHIFT, 12 | "input/ggt_debug_step_frame": KEY_PERIOD 13 | } 14 | 15 | 16 | func _enter_tree(): 17 | register_input_mappings(func(): save_project_settings()) 18 | 19 | 20 | func _enable_plugin(): 21 | add_autoload_singleton("GGT_DebugShortcuts", "res://addons/ggt-debug-shortcuts/autoload/debug_shortcuts.tscn") 22 | register_input_mappings(func(): save_project_settings()) 23 | 24 | 25 | func _exit_tree(): 26 | pass 27 | 28 | 29 | func _disable_plugin(): 30 | remove_autoload_singleton("GGT_DebugShortcuts") 31 | unregister_input_mappings() 32 | save_project_settings() 33 | 34 | 35 | func save_project_settings(): 36 | var error = ProjectSettings.save() 37 | if error: 38 | push_error(error) 39 | 40 | 41 | func create_input_action(keycode: Key): 42 | var trigger = InputEventKey.new() 43 | trigger.keycode = keycode 44 | return { 45 | "deadzone": 0.5, 46 | "events": [trigger] 47 | } 48 | 49 | 50 | func register_input_mappings(on_project_settings_changed: Callable): 51 | var dirty = false 52 | for k in default_debug_shortcuts: 53 | var v = default_debug_shortcuts[k] 54 | if ProjectSettings.has_setting(k): 55 | pass # leave user configured action 56 | else: 57 | dirty = true 58 | ProjectSettings.set_setting(k, create_input_action(v)) # set default value 59 | if dirty: 60 | if on_project_settings_changed is Callable: 61 | on_project_settings_changed.call() 62 | 63 | 64 | func unregister_input_mappings(): 65 | for k in default_debug_shortcuts: 66 | ProjectSettings.set_setting(k, null) 67 | -------------------------------------------------------------------------------- /addons/ggt-debug-shortcuts/plugin.gd.uid: -------------------------------------------------------------------------------- 1 | uid://dwv6vrm2ncfcs 2 | -------------------------------------------------------------------------------- /assets/fonts/LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /assets/fonts/open-sans/open-sans-bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crystal-bit/godot-game-template/9caae9ef8d7138b638f0df29d820152212b11926/assets/fonts/open-sans/open-sans-bold.ttf -------------------------------------------------------------------------------- /assets/fonts/open-sans/open-sans-bold.ttf.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="font_data_dynamic" 4 | type="FontFile" 5 | uid="uid://da2t6lyf41wty" 6 | path="res://.godot/imported/open-sans-bold.ttf-57e3060dd99c5c2d620352989d7b033a.fontdata" 7 | 8 | [deps] 9 | 10 | source_file="res://assets/fonts/open-sans/open-sans-bold.ttf" 11 | dest_files=["res://.godot/imported/open-sans-bold.ttf-57e3060dd99c5c2d620352989d7b033a.fontdata"] 12 | 13 | [params] 14 | 15 | Rendering=null 16 | antialiasing=1 17 | generate_mipmaps=false 18 | disable_embedded_bitmaps=true 19 | multichannel_signed_distance_field=false 20 | msdf_pixel_range=8 21 | msdf_size=48 22 | allow_system_fallback=true 23 | force_autohinter=false 24 | hinting=1 25 | subpixel_positioning=1 26 | keep_rounding_remainders=true 27 | oversampling=0.0 28 | Fallbacks=null 29 | fallbacks=[] 30 | Compress=null 31 | compress=true 32 | preload=[] 33 | language_support={} 34 | script_support={} 35 | opentype_features={} 36 | -------------------------------------------------------------------------------- /assets/fonts/open-sans/open-sans-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crystal-bit/godot-game-template/9caae9ef8d7138b638f0df29d820152212b11926/assets/fonts/open-sans/open-sans-regular.ttf -------------------------------------------------------------------------------- /assets/fonts/open-sans/open-sans-regular.ttf.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="font_data_dynamic" 4 | type="FontFile" 5 | uid="uid://cawekr44fruhm" 6 | path="res://.godot/imported/open-sans-regular.ttf-17e45665bae6f7f22a9ebeaf99960c2e.fontdata" 7 | 8 | [deps] 9 | 10 | source_file="res://assets/fonts/open-sans/open-sans-regular.ttf" 11 | dest_files=["res://.godot/imported/open-sans-regular.ttf-17e45665bae6f7f22a9ebeaf99960c2e.fontdata"] 12 | 13 | [params] 14 | 15 | Rendering=null 16 | antialiasing=1 17 | generate_mipmaps=false 18 | disable_embedded_bitmaps=true 19 | multichannel_signed_distance_field=false 20 | msdf_pixel_range=8 21 | msdf_size=48 22 | allow_system_fallback=true 23 | force_autohinter=false 24 | hinting=1 25 | subpixel_positioning=1 26 | keep_rounding_remainders=true 27 | oversampling=0.0 28 | Fallbacks=null 29 | fallbacks=[] 30 | Compress=null 31 | compress=true 32 | preload=[] 33 | language_support={} 34 | script_support={} 35 | opentype_features={} 36 | -------------------------------------------------------------------------------- /assets/sprites/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crystal-bit/godot-game-template/9caae9ef8d7138b638f0df29d820152212b11926/assets/sprites/icon.png -------------------------------------------------------------------------------- /assets/sprites/icon.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://dtwpm3uclaspj" 6 | path="res://.godot/imported/icon.png-9a25435582839ca3cd8bb514b597c2d9.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://assets/sprites/icon.png" 14 | dest_files=["res://.godot/imported/icon.png-9a25435582839ca3cd8bb514b597c2d9.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /builds/.gdignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crystal-bit/godot-game-template/9caae9ef8d7138b638f0df29d820152212b11926/builds/.gdignore -------------------------------------------------------------------------------- /default_bus_layout.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="AudioBusLayout" format=3 uid="uid://055kpm62vfsd"] 2 | 3 | [resource] 4 | bus/1/name = &"SFX" 5 | bus/1/solo = false 6 | bus/1/mute = false 7 | bus/1/bypass_fx = false 8 | bus/1/volume_db = 0.0 9 | bus/1/send = &"Master" 10 | bus/2/name = &"BGM" 11 | bus/2/solo = false 12 | bus/2/mute = false 13 | bus/2/bypass_fx = false 14 | bus/2/volume_db = 0.0 15 | bus/2/send = &"Master" 16 | -------------------------------------------------------------------------------- /export_presets.cfg: -------------------------------------------------------------------------------- 1 | [preset.0] 2 | 3 | name="Windows Desktop" 4 | platform="Windows Desktop" 5 | runnable=true 6 | advanced_options=false 7 | dedicated_server=false 8 | custom_features="" 9 | export_filter="all_resources" 10 | include_filter="" 11 | exclude_filter="" 12 | export_path="" 13 | patches=PackedStringArray() 14 | encryption_include_filters="" 15 | encryption_exclude_filters="" 16 | seed=0 17 | encrypt_pck=false 18 | encrypt_directory=false 19 | script_export_mode=2 20 | 21 | [preset.0.options] 22 | 23 | custom_template/debug="" 24 | custom_template/release="" 25 | debug/export_console_wrapper=1 26 | binary_format/embed_pck=true 27 | texture_format/s3tc_bptc=true 28 | texture_format/etc2_astc=false 29 | binary_format/architecture="x86_64" 30 | codesign/enable=false 31 | codesign/timestamp=true 32 | codesign/timestamp_server_url="" 33 | codesign/digest_algorithm=1 34 | codesign/description="" 35 | codesign/custom_options=PackedStringArray() 36 | application/modify_resources=true 37 | application/icon="" 38 | application/console_wrapper_icon="" 39 | application/icon_interpolation=4 40 | application/file_version="" 41 | application/product_version="" 42 | application/company_name="" 43 | application/product_name="" 44 | application/file_description="" 45 | application/copyright="" 46 | application/trademarks="" 47 | application/export_angle=0 48 | application/export_d3d12=0 49 | application/d3d12_agility_sdk_multiarch=true 50 | ssh_remote_deploy/enabled=false 51 | ssh_remote_deploy/host="user@host_ip" 52 | ssh_remote_deploy/port="22" 53 | ssh_remote_deploy/extra_args_ssh="" 54 | ssh_remote_deploy/extra_args_scp="" 55 | ssh_remote_deploy/run_script="Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}' 56 | $action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}' 57 | $trigger = New-ScheduledTaskTrigger -Once -At 00:00 58 | $settings = New-ScheduledTaskSettingsSet 59 | $task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings 60 | Register-ScheduledTask godot_remote_debug -InputObject $task -Force:$true 61 | Start-ScheduledTask -TaskName godot_remote_debug 62 | while (Get-ScheduledTask -TaskName godot_remote_debug | ? State -eq running) { Start-Sleep -Milliseconds 100 } 63 | Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue" 64 | ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue 65 | Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue 66 | Remove-Item -Recurse -Force '{temp_dir}'" 67 | texture_format/bptc=false 68 | texture_format/s3tc=true 69 | texture_format/etc=false 70 | texture_format/etc2=false 71 | binary_format/64_bits=true 72 | texture_format/no_bptc_fallbacks=true 73 | 74 | [preset.1] 75 | 76 | name="Linux/X11" 77 | platform="Linux" 78 | runnable=true 79 | advanced_options=false 80 | dedicated_server=false 81 | custom_features="" 82 | export_filter="all_resources" 83 | include_filter="" 84 | exclude_filter="" 85 | export_path="builds/linux/godot-game-template.x86_64" 86 | patches=PackedStringArray() 87 | encryption_include_filters="" 88 | encryption_exclude_filters="" 89 | seed=0 90 | encrypt_pck=false 91 | encrypt_directory=false 92 | script_export_mode=2 93 | 94 | [preset.1.options] 95 | 96 | custom_template/debug="" 97 | custom_template/release="" 98 | debug/export_console_wrapper=1 99 | binary_format/embed_pck=true 100 | texture_format/s3tc_bptc=true 101 | texture_format/etc2_astc=false 102 | binary_format/architecture="x86_64" 103 | ssh_remote_deploy/enabled=false 104 | ssh_remote_deploy/host="user@host_ip" 105 | ssh_remote_deploy/port="22" 106 | ssh_remote_deploy/extra_args_ssh="" 107 | ssh_remote_deploy/extra_args_scp="" 108 | ssh_remote_deploy/run_script="#!/usr/bin/env bash 109 | export DISPLAY=:0 110 | unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\" 111 | \"{temp_dir}/{exe_name}\" {cmd_args}" 112 | ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash 113 | kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\") 114 | rm -rf \"{temp_dir}\"" 115 | texture_format/bptc=false 116 | texture_format/s3tc=true 117 | texture_format/etc=false 118 | texture_format/etc2=false 119 | binary_format/64_bits=true 120 | texture_format/no_bptc_fallbacks=true 121 | 122 | [preset.2] 123 | 124 | name="Android" 125 | platform="Android" 126 | runnable=true 127 | advanced_options=false 128 | dedicated_server=false 129 | custom_features="" 130 | export_filter="all_resources" 131 | include_filter="" 132 | exclude_filter="" 133 | export_path="builds/godot-game-template.apk" 134 | patches=PackedStringArray() 135 | encryption_include_filters="" 136 | encryption_exclude_filters="" 137 | seed=0 138 | encrypt_pck=false 139 | encrypt_directory=false 140 | script_export_mode=2 141 | 142 | [preset.2.options] 143 | 144 | custom_template/debug="" 145 | custom_template/release="" 146 | gradle_build/use_gradle_build=false 147 | gradle_build/gradle_build_directory="" 148 | gradle_build/android_source_template="" 149 | gradle_build/compress_native_libraries=false 150 | gradle_build/export_format=0 151 | gradle_build/min_sdk="" 152 | gradle_build/target_sdk="" 153 | architectures/armeabi-v7a=true 154 | architectures/arm64-v8a=true 155 | architectures/x86=false 156 | architectures/x86_64=false 157 | version/code=1 158 | version/name="" 159 | package/unique_name="org.crystalbit.$genname" 160 | package/name="" 161 | package/signed=true 162 | package/app_category=2 163 | package/retain_data_on_uninstall=false 164 | package/exclude_from_recents=false 165 | package/show_in_android_tv=false 166 | package/show_in_app_library=true 167 | package/show_as_launcher_app=false 168 | launcher_icons/main_192x192="" 169 | launcher_icons/adaptive_foreground_432x432="" 170 | launcher_icons/adaptive_background_432x432="" 171 | launcher_icons/adaptive_monochrome_432x432="" 172 | graphics/opengl_debug=false 173 | xr_features/xr_mode=0 174 | gesture/swipe_to_dismiss=false 175 | screen/immersive_mode=true 176 | screen/support_small=true 177 | screen/support_normal=true 178 | screen/support_large=true 179 | screen/support_xlarge=true 180 | user_data_backup/allow=false 181 | command_line/extra_args="" 182 | apk_expansion/enable=false 183 | apk_expansion/SALT="" 184 | apk_expansion/public_key="" 185 | permissions/custom_permissions=PackedStringArray() 186 | permissions/access_checkin_properties=false 187 | permissions/access_coarse_location=false 188 | permissions/access_fine_location=false 189 | permissions/access_location_extra_commands=false 190 | permissions/access_media_location=false 191 | permissions/access_mock_location=false 192 | permissions/access_network_state=false 193 | permissions/access_surface_flinger=false 194 | permissions/access_wifi_state=false 195 | permissions/account_manager=false 196 | permissions/add_voicemail=false 197 | permissions/authenticate_accounts=false 198 | permissions/battery_stats=false 199 | permissions/bind_accessibility_service=false 200 | permissions/bind_appwidget=false 201 | permissions/bind_device_admin=false 202 | permissions/bind_input_method=false 203 | permissions/bind_nfc_service=false 204 | permissions/bind_notification_listener_service=false 205 | permissions/bind_print_service=false 206 | permissions/bind_remoteviews=false 207 | permissions/bind_text_service=false 208 | permissions/bind_vpn_service=false 209 | permissions/bind_wallpaper=false 210 | permissions/bluetooth=false 211 | permissions/bluetooth_admin=false 212 | permissions/bluetooth_privileged=false 213 | permissions/brick=false 214 | permissions/broadcast_package_removed=false 215 | permissions/broadcast_sms=false 216 | permissions/broadcast_sticky=false 217 | permissions/broadcast_wap_push=false 218 | permissions/call_phone=false 219 | permissions/call_privileged=false 220 | permissions/camera=false 221 | permissions/capture_audio_output=false 222 | permissions/capture_secure_video_output=false 223 | permissions/capture_video_output=false 224 | permissions/change_component_enabled_state=false 225 | permissions/change_configuration=false 226 | permissions/change_network_state=false 227 | permissions/change_wifi_multicast_state=false 228 | permissions/change_wifi_state=false 229 | permissions/clear_app_cache=false 230 | permissions/clear_app_user_data=false 231 | permissions/control_location_updates=false 232 | permissions/delete_cache_files=false 233 | permissions/delete_packages=false 234 | permissions/device_power=false 235 | permissions/diagnostic=false 236 | permissions/disable_keyguard=false 237 | permissions/dump=false 238 | permissions/expand_status_bar=false 239 | permissions/factory_test=false 240 | permissions/flashlight=false 241 | permissions/force_back=false 242 | permissions/get_accounts=false 243 | permissions/get_package_size=false 244 | permissions/get_tasks=false 245 | permissions/get_top_activity_info=false 246 | permissions/global_search=false 247 | permissions/hardware_test=false 248 | permissions/inject_events=false 249 | permissions/install_location_provider=false 250 | permissions/install_packages=false 251 | permissions/install_shortcut=false 252 | permissions/internal_system_window=false 253 | permissions/internet=false 254 | permissions/kill_background_processes=false 255 | permissions/location_hardware=false 256 | permissions/manage_accounts=false 257 | permissions/manage_app_tokens=false 258 | permissions/manage_documents=false 259 | permissions/manage_external_storage=false 260 | permissions/master_clear=false 261 | permissions/media_content_control=false 262 | permissions/modify_audio_settings=false 263 | permissions/modify_phone_state=false 264 | permissions/mount_format_filesystems=false 265 | permissions/mount_unmount_filesystems=false 266 | permissions/nfc=false 267 | permissions/persistent_activity=false 268 | permissions/post_notifications=false 269 | permissions/process_outgoing_calls=false 270 | permissions/read_calendar=false 271 | permissions/read_call_log=false 272 | permissions/read_contacts=false 273 | permissions/read_external_storage=false 274 | permissions/read_frame_buffer=false 275 | permissions/read_history_bookmarks=false 276 | permissions/read_input_state=false 277 | permissions/read_logs=false 278 | permissions/read_media_audio=false 279 | permissions/read_media_images=false 280 | permissions/read_media_video=false 281 | permissions/read_media_visual_user_selected=false 282 | permissions/read_phone_state=false 283 | permissions/read_profile=false 284 | permissions/read_sms=false 285 | permissions/read_social_stream=false 286 | permissions/read_sync_settings=false 287 | permissions/read_sync_stats=false 288 | permissions/read_user_dictionary=false 289 | permissions/reboot=false 290 | permissions/receive_boot_completed=false 291 | permissions/receive_mms=false 292 | permissions/receive_sms=false 293 | permissions/receive_wap_push=false 294 | permissions/record_audio=false 295 | permissions/reorder_tasks=false 296 | permissions/restart_packages=false 297 | permissions/send_respond_via_message=false 298 | permissions/send_sms=false 299 | permissions/set_activity_watcher=false 300 | permissions/set_alarm=false 301 | permissions/set_always_finish=false 302 | permissions/set_animation_scale=false 303 | permissions/set_debug_app=false 304 | permissions/set_orientation=false 305 | permissions/set_pointer_speed=false 306 | permissions/set_preferred_applications=false 307 | permissions/set_process_limit=false 308 | permissions/set_time=false 309 | permissions/set_time_zone=false 310 | permissions/set_wallpaper=false 311 | permissions/set_wallpaper_hints=false 312 | permissions/signal_persistent_processes=false 313 | permissions/status_bar=false 314 | permissions/subscribed_feeds_read=false 315 | permissions/subscribed_feeds_write=false 316 | permissions/system_alert_window=false 317 | permissions/transmit_ir=false 318 | permissions/uninstall_shortcut=false 319 | permissions/update_device_stats=false 320 | permissions/use_credentials=false 321 | permissions/use_sip=false 322 | permissions/vibrate=false 323 | permissions/wake_lock=false 324 | permissions/write_apn_settings=false 325 | permissions/write_calendar=false 326 | permissions/write_call_log=false 327 | permissions/write_contacts=false 328 | permissions/write_external_storage=false 329 | permissions/write_gservices=false 330 | permissions/write_history_bookmarks=false 331 | permissions/write_profile=false 332 | permissions/write_secure_settings=false 333 | permissions/write_settings=false 334 | permissions/write_sms=false 335 | permissions/write_social_stream=false 336 | permissions/write_sync_settings=false 337 | permissions/write_user_dictionary=false 338 | xr_features/hand_tracking=0 339 | xr_features/hand_tracking_frequency=0 340 | xr_features/passthrough=0 341 | custom_template/use_custom_build=false 342 | custom_template/export_format=0 343 | one_click_deploy/clear_previous_install=false 344 | package/classify_as_game=true 345 | graphics/32_bits_framebuffer=true 346 | 347 | [preset.3] 348 | 349 | name="Android-CI-job (Do not edit)" 350 | platform="Android" 351 | runnable=false 352 | advanced_options=false 353 | dedicated_server=false 354 | custom_features="" 355 | export_filter="all_resources" 356 | include_filter="" 357 | exclude_filter="" 358 | export_path="builds/godot-template.apk" 359 | patches=PackedStringArray() 360 | encryption_include_filters="" 361 | encryption_exclude_filters="" 362 | seed=0 363 | encrypt_pck=false 364 | encrypt_directory=false 365 | script_export_mode=2 366 | 367 | [preset.3.options] 368 | 369 | custom_template/debug="" 370 | custom_template/release="" 371 | gradle_build/use_gradle_build=false 372 | gradle_build/gradle_build_directory="" 373 | gradle_build/android_source_template="" 374 | gradle_build/compress_native_libraries=false 375 | gradle_build/export_format=0 376 | gradle_build/min_sdk="" 377 | gradle_build/target_sdk="" 378 | architectures/armeabi-v7a=true 379 | architectures/arm64-v8a=true 380 | architectures/x86=false 381 | architectures/x86_64=false 382 | version/code=1 383 | version/name="1.0" 384 | package/unique_name="org.godotengine.$genname" 385 | package/name="" 386 | package/signed=true 387 | package/app_category=2 388 | package/retain_data_on_uninstall=false 389 | package/exclude_from_recents=false 390 | package/show_in_android_tv=false 391 | package/show_in_app_library=true 392 | package/show_as_launcher_app=false 393 | launcher_icons/main_192x192="" 394 | launcher_icons/adaptive_foreground_432x432="" 395 | launcher_icons/adaptive_background_432x432="" 396 | launcher_icons/adaptive_monochrome_432x432="" 397 | graphics/opengl_debug=false 398 | xr_features/xr_mode=0 399 | gesture/swipe_to_dismiss=false 400 | screen/immersive_mode=true 401 | screen/support_small=true 402 | screen/support_normal=true 403 | screen/support_large=true 404 | screen/support_xlarge=true 405 | user_data_backup/allow=false 406 | command_line/extra_args="" 407 | apk_expansion/enable=false 408 | apk_expansion/SALT="" 409 | apk_expansion/public_key="" 410 | permissions/custom_permissions=PackedStringArray() 411 | permissions/access_checkin_properties=false 412 | permissions/access_coarse_location=false 413 | permissions/access_fine_location=false 414 | permissions/access_location_extra_commands=false 415 | permissions/access_media_location=false 416 | permissions/access_mock_location=false 417 | permissions/access_network_state=false 418 | permissions/access_surface_flinger=false 419 | permissions/access_wifi_state=false 420 | permissions/account_manager=false 421 | permissions/add_voicemail=false 422 | permissions/authenticate_accounts=false 423 | permissions/battery_stats=false 424 | permissions/bind_accessibility_service=false 425 | permissions/bind_appwidget=false 426 | permissions/bind_device_admin=false 427 | permissions/bind_input_method=false 428 | permissions/bind_nfc_service=false 429 | permissions/bind_notification_listener_service=false 430 | permissions/bind_print_service=false 431 | permissions/bind_remoteviews=false 432 | permissions/bind_text_service=false 433 | permissions/bind_vpn_service=false 434 | permissions/bind_wallpaper=false 435 | permissions/bluetooth=false 436 | permissions/bluetooth_admin=false 437 | permissions/bluetooth_privileged=false 438 | permissions/brick=false 439 | permissions/broadcast_package_removed=false 440 | permissions/broadcast_sms=false 441 | permissions/broadcast_sticky=false 442 | permissions/broadcast_wap_push=false 443 | permissions/call_phone=false 444 | permissions/call_privileged=false 445 | permissions/camera=false 446 | permissions/capture_audio_output=false 447 | permissions/capture_secure_video_output=false 448 | permissions/capture_video_output=false 449 | permissions/change_component_enabled_state=false 450 | permissions/change_configuration=false 451 | permissions/change_network_state=false 452 | permissions/change_wifi_multicast_state=false 453 | permissions/change_wifi_state=false 454 | permissions/clear_app_cache=false 455 | permissions/clear_app_user_data=false 456 | permissions/control_location_updates=false 457 | permissions/delete_cache_files=false 458 | permissions/delete_packages=false 459 | permissions/device_power=false 460 | permissions/diagnostic=false 461 | permissions/disable_keyguard=false 462 | permissions/dump=false 463 | permissions/expand_status_bar=false 464 | permissions/factory_test=false 465 | permissions/flashlight=false 466 | permissions/force_back=false 467 | permissions/get_accounts=false 468 | permissions/get_package_size=false 469 | permissions/get_tasks=false 470 | permissions/get_top_activity_info=false 471 | permissions/global_search=false 472 | permissions/hardware_test=false 473 | permissions/inject_events=false 474 | permissions/install_location_provider=false 475 | permissions/install_packages=false 476 | permissions/install_shortcut=false 477 | permissions/internal_system_window=false 478 | permissions/internet=false 479 | permissions/kill_background_processes=false 480 | permissions/location_hardware=false 481 | permissions/manage_accounts=false 482 | permissions/manage_app_tokens=false 483 | permissions/manage_documents=false 484 | permissions/manage_external_storage=false 485 | permissions/master_clear=false 486 | permissions/media_content_control=false 487 | permissions/modify_audio_settings=false 488 | permissions/modify_phone_state=false 489 | permissions/mount_format_filesystems=false 490 | permissions/mount_unmount_filesystems=false 491 | permissions/nfc=false 492 | permissions/persistent_activity=false 493 | permissions/post_notifications=false 494 | permissions/process_outgoing_calls=false 495 | permissions/read_calendar=false 496 | permissions/read_call_log=false 497 | permissions/read_contacts=false 498 | permissions/read_external_storage=false 499 | permissions/read_frame_buffer=false 500 | permissions/read_history_bookmarks=false 501 | permissions/read_input_state=false 502 | permissions/read_logs=false 503 | permissions/read_media_audio=false 504 | permissions/read_media_images=false 505 | permissions/read_media_video=false 506 | permissions/read_media_visual_user_selected=false 507 | permissions/read_phone_state=false 508 | permissions/read_profile=false 509 | permissions/read_sms=false 510 | permissions/read_social_stream=false 511 | permissions/read_sync_settings=false 512 | permissions/read_sync_stats=false 513 | permissions/read_user_dictionary=false 514 | permissions/reboot=false 515 | permissions/receive_boot_completed=false 516 | permissions/receive_mms=false 517 | permissions/receive_sms=false 518 | permissions/receive_wap_push=false 519 | permissions/record_audio=false 520 | permissions/reorder_tasks=false 521 | permissions/restart_packages=false 522 | permissions/send_respond_via_message=false 523 | permissions/send_sms=false 524 | permissions/set_activity_watcher=false 525 | permissions/set_alarm=false 526 | permissions/set_always_finish=false 527 | permissions/set_animation_scale=false 528 | permissions/set_debug_app=false 529 | permissions/set_orientation=false 530 | permissions/set_pointer_speed=false 531 | permissions/set_preferred_applications=false 532 | permissions/set_process_limit=false 533 | permissions/set_time=false 534 | permissions/set_time_zone=false 535 | permissions/set_wallpaper=false 536 | permissions/set_wallpaper_hints=false 537 | permissions/signal_persistent_processes=false 538 | permissions/status_bar=false 539 | permissions/subscribed_feeds_read=false 540 | permissions/subscribed_feeds_write=false 541 | permissions/system_alert_window=false 542 | permissions/transmit_ir=false 543 | permissions/uninstall_shortcut=false 544 | permissions/update_device_stats=false 545 | permissions/use_credentials=false 546 | permissions/use_sip=false 547 | permissions/vibrate=false 548 | permissions/wake_lock=false 549 | permissions/write_apn_settings=false 550 | permissions/write_calendar=false 551 | permissions/write_call_log=false 552 | permissions/write_contacts=false 553 | permissions/write_external_storage=false 554 | permissions/write_gservices=false 555 | permissions/write_history_bookmarks=false 556 | permissions/write_profile=false 557 | permissions/write_secure_settings=false 558 | permissions/write_settings=false 559 | permissions/write_sms=false 560 | permissions/write_social_stream=false 561 | permissions/write_sync_settings=false 562 | permissions/write_user_dictionary=false 563 | xr_features/hand_tracking=0 564 | xr_features/hand_tracking_frequency=0 565 | xr_features/passthrough=0 566 | custom_template/use_custom_build=false 567 | custom_template/export_format=0 568 | one_click_deploy/clear_previous_install=false 569 | package/classify_as_game=true 570 | graphics/32_bits_framebuffer=true 571 | 572 | [preset.4] 573 | 574 | name="Web" 575 | platform="Web" 576 | runnable=true 577 | advanced_options=false 578 | dedicated_server=false 579 | custom_features="" 580 | export_filter="all_resources" 581 | include_filter="" 582 | exclude_filter="" 583 | export_path="builds/godot-game-template.html" 584 | patches=PackedStringArray() 585 | encryption_include_filters="" 586 | encryption_exclude_filters="" 587 | seed=0 588 | encrypt_pck=false 589 | encrypt_directory=false 590 | script_export_mode=2 591 | 592 | [preset.4.options] 593 | 594 | custom_template/debug="" 595 | custom_template/release="" 596 | variant/extensions_support=false 597 | variant/thread_support=false 598 | vram_texture_compression/for_desktop=true 599 | vram_texture_compression/for_mobile=false 600 | html/export_icon=true 601 | html/custom_html_shell="" 602 | html/head_include="" 603 | html/canvas_resize_policy=2 604 | html/focus_canvas_on_start=true 605 | html/experimental_virtual_keyboard=false 606 | progressive_web_app/enabled=false 607 | progressive_web_app/ensure_cross_origin_isolation_headers=true 608 | progressive_web_app/offline_page="" 609 | progressive_web_app/display=1 610 | progressive_web_app/orientation=0 611 | progressive_web_app/icon_144x144="" 612 | progressive_web_app/icon_180x180="" 613 | progressive_web_app/icon_512x512="" 614 | progressive_web_app/background_color=Color(0, 0, 0, 1) 615 | 616 | [preset.5] 617 | 618 | name="macOS" 619 | platform="macOS" 620 | runnable=true 621 | advanced_options=false 622 | dedicated_server=false 623 | custom_features="" 624 | export_filter="all_resources" 625 | include_filter="" 626 | exclude_filter="" 627 | export_path="builds/osx/godot-game-template.dmg" 628 | patches=PackedStringArray() 629 | encryption_include_filters="" 630 | encryption_exclude_filters="" 631 | seed=0 632 | encrypt_pck=false 633 | encrypt_directory=false 634 | script_export_mode=2 635 | 636 | [preset.5.options] 637 | 638 | export/distribution_type=1 639 | binary_format/architecture="universal" 640 | custom_template/debug="" 641 | custom_template/release="" 642 | debug/export_console_wrapper=1 643 | application/icon="" 644 | application/icon_interpolation=4 645 | application/bundle_identifier="crystalbit.godot-game-template" 646 | application/signature="" 647 | application/app_category="Games" 648 | application/short_version="1.0" 649 | application/version="1.0" 650 | application/copyright="" 651 | application/copyright_localized={} 652 | application/min_macos_version_x86_64="10.12" 653 | application/min_macos_version_arm64="11.00" 654 | application/export_angle=0 655 | display/high_res=true 656 | application/additional_plist_content="" 657 | xcode/platform_build="14C18" 658 | xcode/sdk_version="13.1" 659 | xcode/sdk_build="22C55" 660 | xcode/sdk_name="macosx13.1" 661 | xcode/xcode_version="1420" 662 | xcode/xcode_build="14C18" 663 | codesign/codesign=0 664 | codesign/installer_identity="" 665 | codesign/apple_team_id="" 666 | codesign/identity="" 667 | codesign/entitlements/custom_file="" 668 | codesign/entitlements/allow_jit_code_execution=false 669 | codesign/entitlements/allow_unsigned_executable_memory=false 670 | codesign/entitlements/allow_dyld_environment_variables=false 671 | codesign/entitlements/disable_library_validation=true 672 | codesign/entitlements/audio_input=false 673 | codesign/entitlements/camera=false 674 | codesign/entitlements/location=false 675 | codesign/entitlements/address_book=false 676 | codesign/entitlements/calendars=false 677 | codesign/entitlements/photos_library=false 678 | codesign/entitlements/apple_events=false 679 | codesign/entitlements/debugging=false 680 | codesign/entitlements/app_sandbox/enabled=false 681 | codesign/entitlements/app_sandbox/network_server=false 682 | codesign/entitlements/app_sandbox/network_client=false 683 | codesign/entitlements/app_sandbox/device_usb=false 684 | codesign/entitlements/app_sandbox/device_bluetooth=false 685 | codesign/entitlements/app_sandbox/files_downloads=0 686 | codesign/entitlements/app_sandbox/files_pictures=0 687 | codesign/entitlements/app_sandbox/files_music=0 688 | codesign/entitlements/app_sandbox/files_movies=0 689 | codesign/entitlements/app_sandbox/files_user_selected=0 690 | codesign/entitlements/app_sandbox/helper_executables=[] 691 | codesign/entitlements/additional="" 692 | codesign/custom_options=PackedStringArray() 693 | notarization/notarization=0 694 | privacy/microphone_usage_description="" 695 | privacy/microphone_usage_description_localized={} 696 | privacy/camera_usage_description="" 697 | privacy/camera_usage_description_localized={} 698 | privacy/location_usage_description="" 699 | privacy/location_usage_description_localized={} 700 | privacy/address_book_usage_description="" 701 | privacy/address_book_usage_description_localized={} 702 | privacy/calendar_usage_description="" 703 | privacy/calendar_usage_description_localized={} 704 | privacy/photos_library_usage_description="" 705 | privacy/photos_library_usage_description_localized={} 706 | privacy/desktop_folder_usage_description="" 707 | privacy/desktop_folder_usage_description_localized={} 708 | privacy/documents_folder_usage_description="" 709 | privacy/documents_folder_usage_description_localized={} 710 | privacy/downloads_folder_usage_description="" 711 | privacy/downloads_folder_usage_description_localized={} 712 | privacy/network_volumes_usage_description="" 713 | privacy/network_volumes_usage_description_localized={} 714 | privacy/removable_volumes_usage_description="" 715 | privacy/removable_volumes_usage_description_localized={} 716 | privacy/tracking_enabled=false 717 | privacy/tracking_domains=PackedStringArray() 718 | privacy/collected_data/name/collected=false 719 | privacy/collected_data/name/linked_to_user=false 720 | privacy/collected_data/name/used_for_tracking=false 721 | privacy/collected_data/name/collection_purposes=0 722 | privacy/collected_data/email_address/collected=false 723 | privacy/collected_data/email_address/linked_to_user=false 724 | privacy/collected_data/email_address/used_for_tracking=false 725 | privacy/collected_data/email_address/collection_purposes=0 726 | privacy/collected_data/phone_number/collected=false 727 | privacy/collected_data/phone_number/linked_to_user=false 728 | privacy/collected_data/phone_number/used_for_tracking=false 729 | privacy/collected_data/phone_number/collection_purposes=0 730 | privacy/collected_data/physical_address/collected=false 731 | privacy/collected_data/physical_address/linked_to_user=false 732 | privacy/collected_data/physical_address/used_for_tracking=false 733 | privacy/collected_data/physical_address/collection_purposes=0 734 | privacy/collected_data/other_contact_info/collected=false 735 | privacy/collected_data/other_contact_info/linked_to_user=false 736 | privacy/collected_data/other_contact_info/used_for_tracking=false 737 | privacy/collected_data/other_contact_info/collection_purposes=0 738 | privacy/collected_data/health/collected=false 739 | privacy/collected_data/health/linked_to_user=false 740 | privacy/collected_data/health/used_for_tracking=false 741 | privacy/collected_data/health/collection_purposes=0 742 | privacy/collected_data/fitness/collected=false 743 | privacy/collected_data/fitness/linked_to_user=false 744 | privacy/collected_data/fitness/used_for_tracking=false 745 | privacy/collected_data/fitness/collection_purposes=0 746 | privacy/collected_data/payment_info/collected=false 747 | privacy/collected_data/payment_info/linked_to_user=false 748 | privacy/collected_data/payment_info/used_for_tracking=false 749 | privacy/collected_data/payment_info/collection_purposes=0 750 | privacy/collected_data/credit_info/collected=false 751 | privacy/collected_data/credit_info/linked_to_user=false 752 | privacy/collected_data/credit_info/used_for_tracking=false 753 | privacy/collected_data/credit_info/collection_purposes=0 754 | privacy/collected_data/other_financial_info/collected=false 755 | privacy/collected_data/other_financial_info/linked_to_user=false 756 | privacy/collected_data/other_financial_info/used_for_tracking=false 757 | privacy/collected_data/other_financial_info/collection_purposes=0 758 | privacy/collected_data/precise_location/collected=false 759 | privacy/collected_data/precise_location/linked_to_user=false 760 | privacy/collected_data/precise_location/used_for_tracking=false 761 | privacy/collected_data/precise_location/collection_purposes=0 762 | privacy/collected_data/coarse_location/collected=false 763 | privacy/collected_data/coarse_location/linked_to_user=false 764 | privacy/collected_data/coarse_location/used_for_tracking=false 765 | privacy/collected_data/coarse_location/collection_purposes=0 766 | privacy/collected_data/sensitive_info/collected=false 767 | privacy/collected_data/sensitive_info/linked_to_user=false 768 | privacy/collected_data/sensitive_info/used_for_tracking=false 769 | privacy/collected_data/sensitive_info/collection_purposes=0 770 | privacy/collected_data/contacts/collected=false 771 | privacy/collected_data/contacts/linked_to_user=false 772 | privacy/collected_data/contacts/used_for_tracking=false 773 | privacy/collected_data/contacts/collection_purposes=0 774 | privacy/collected_data/emails_or_text_messages/collected=false 775 | privacy/collected_data/emails_or_text_messages/linked_to_user=false 776 | privacy/collected_data/emails_or_text_messages/used_for_tracking=false 777 | privacy/collected_data/emails_or_text_messages/collection_purposes=0 778 | privacy/collected_data/photos_or_videos/collected=false 779 | privacy/collected_data/photos_or_videos/linked_to_user=false 780 | privacy/collected_data/photos_or_videos/used_for_tracking=false 781 | privacy/collected_data/photos_or_videos/collection_purposes=0 782 | privacy/collected_data/audio_data/collected=false 783 | privacy/collected_data/audio_data/linked_to_user=false 784 | privacy/collected_data/audio_data/used_for_tracking=false 785 | privacy/collected_data/audio_data/collection_purposes=0 786 | privacy/collected_data/gameplay_content/collected=false 787 | privacy/collected_data/gameplay_content/linked_to_user=false 788 | privacy/collected_data/gameplay_content/used_for_tracking=false 789 | privacy/collected_data/gameplay_content/collection_purposes=0 790 | privacy/collected_data/customer_support/collected=false 791 | privacy/collected_data/customer_support/linked_to_user=false 792 | privacy/collected_data/customer_support/used_for_tracking=false 793 | privacy/collected_data/customer_support/collection_purposes=0 794 | privacy/collected_data/other_user_content/collected=false 795 | privacy/collected_data/other_user_content/linked_to_user=false 796 | privacy/collected_data/other_user_content/used_for_tracking=false 797 | privacy/collected_data/other_user_content/collection_purposes=0 798 | privacy/collected_data/browsing_history/collected=false 799 | privacy/collected_data/browsing_history/linked_to_user=false 800 | privacy/collected_data/browsing_history/used_for_tracking=false 801 | privacy/collected_data/browsing_history/collection_purposes=0 802 | privacy/collected_data/search_hhistory/collected=false 803 | privacy/collected_data/search_hhistory/linked_to_user=false 804 | privacy/collected_data/search_hhistory/used_for_tracking=false 805 | privacy/collected_data/search_hhistory/collection_purposes=0 806 | privacy/collected_data/user_id/collected=false 807 | privacy/collected_data/user_id/linked_to_user=false 808 | privacy/collected_data/user_id/used_for_tracking=false 809 | privacy/collected_data/user_id/collection_purposes=0 810 | privacy/collected_data/device_id/collected=false 811 | privacy/collected_data/device_id/linked_to_user=false 812 | privacy/collected_data/device_id/used_for_tracking=false 813 | privacy/collected_data/device_id/collection_purposes=0 814 | privacy/collected_data/purchase_history/collected=false 815 | privacy/collected_data/purchase_history/linked_to_user=false 816 | privacy/collected_data/purchase_history/used_for_tracking=false 817 | privacy/collected_data/purchase_history/collection_purposes=0 818 | privacy/collected_data/product_interaction/collected=false 819 | privacy/collected_data/product_interaction/linked_to_user=false 820 | privacy/collected_data/product_interaction/used_for_tracking=false 821 | privacy/collected_data/product_interaction/collection_purposes=0 822 | privacy/collected_data/advertising_data/collected=false 823 | privacy/collected_data/advertising_data/linked_to_user=false 824 | privacy/collected_data/advertising_data/used_for_tracking=false 825 | privacy/collected_data/advertising_data/collection_purposes=0 826 | privacy/collected_data/other_usage_data/collected=false 827 | privacy/collected_data/other_usage_data/linked_to_user=false 828 | privacy/collected_data/other_usage_data/used_for_tracking=false 829 | privacy/collected_data/other_usage_data/collection_purposes=0 830 | privacy/collected_data/crash_data/collected=false 831 | privacy/collected_data/crash_data/linked_to_user=false 832 | privacy/collected_data/crash_data/used_for_tracking=false 833 | privacy/collected_data/crash_data/collection_purposes=0 834 | privacy/collected_data/performance_data/collected=false 835 | privacy/collected_data/performance_data/linked_to_user=false 836 | privacy/collected_data/performance_data/used_for_tracking=false 837 | privacy/collected_data/performance_data/collection_purposes=0 838 | privacy/collected_data/other_diagnostic_data/collected=false 839 | privacy/collected_data/other_diagnostic_data/linked_to_user=false 840 | privacy/collected_data/other_diagnostic_data/used_for_tracking=false 841 | privacy/collected_data/other_diagnostic_data/collection_purposes=0 842 | privacy/collected_data/environment_scanning/collected=false 843 | privacy/collected_data/environment_scanning/linked_to_user=false 844 | privacy/collected_data/environment_scanning/used_for_tracking=false 845 | privacy/collected_data/environment_scanning/collection_purposes=0 846 | privacy/collected_data/hands/collected=false 847 | privacy/collected_data/hands/linked_to_user=false 848 | privacy/collected_data/hands/used_for_tracking=false 849 | privacy/collected_data/hands/collection_purposes=0 850 | privacy/collected_data/head/collected=false 851 | privacy/collected_data/head/linked_to_user=false 852 | privacy/collected_data/head/used_for_tracking=false 853 | privacy/collected_data/head/collection_purposes=0 854 | privacy/collected_data/other_data_types/collected=false 855 | privacy/collected_data/other_data_types/linked_to_user=false 856 | privacy/collected_data/other_data_types/used_for_tracking=false 857 | privacy/collected_data/other_data_types/collection_purposes=0 858 | ssh_remote_deploy/enabled=false 859 | ssh_remote_deploy/host="user@host_ip" 860 | ssh_remote_deploy/port="22" 861 | ssh_remote_deploy/extra_args_ssh="" 862 | ssh_remote_deploy/extra_args_scp="" 863 | ssh_remote_deploy/run_script="#!/usr/bin/env bash 864 | unzip -o -q \"{temp_dir}/{archive_name}\" -d \"{temp_dir}\" 865 | open \"{temp_dir}/{exe_name}.app\" --args {cmd_args}" 866 | ssh_remote_deploy/cleanup_script="#!/usr/bin/env bash 867 | kill $(pgrep -x -f \"{temp_dir}/{exe_name}.app/Contents/MacOS/{exe_name} {cmd_args}\") 868 | rm -rf \"{temp_dir}\"" 869 | application/min_macos_version="10.12" 870 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Crystal Bit 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 | -------------------------------------------------------------------------------- /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=5 10 | 11 | [application] 12 | 13 | config/name="godot-game-template" 14 | config/version="0.0.1" 15 | run/main_scene="res://scenes/menu/menu.tscn" 16 | config/features=PackedStringArray("4.5") 17 | config/icon="res://assets/sprites/icon.png" 18 | 19 | [autoload] 20 | 21 | GGT="*res://addons/ggt-core/ggt.gd" 22 | GGT_DebugShortcuts="*res://addons/ggt-debug-shortcuts/autoload/debug_shortcuts.tscn" 23 | 24 | [category] 25 | 26 | property_name=1 27 | 28 | [display] 29 | 30 | window/stretch/mode="2d" 31 | window/stretch/aspect="expand" 32 | 33 | [editor_plugins] 34 | 35 | enabled=PackedStringArray("res://addons/ggt-core/plugin.cfg", "res://addons/ggt-debug-shortcuts/plugin.cfg") 36 | 37 | [gui] 38 | 39 | theme/custom="res://resources/theme/theme-main.tres" 40 | 41 | [input] 42 | 43 | ui_accept={ 44 | "deadzone": 0.5, 45 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194309,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) 46 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194310,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) 47 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":32,"physical_keycode":0,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null) 48 | , Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":0,"pressure":0.0,"pressed":false,"script":null) 49 | ] 50 | } 51 | pause={ 52 | "deadzone": 0.5, 53 | "events": [Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":6,"pressure":0.0,"pressed":false,"script":null) 54 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194305,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) 55 | ] 56 | } 57 | ggt_debug_restart_scene={ 58 | "deadzone": 0.5, 59 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":82,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) 60 | ] 61 | } 62 | ggt_debug_pause_game={ 63 | "deadzone": 0.5, 64 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":80,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) 65 | ] 66 | } 67 | ggt_debug_quit_game={ 68 | "deadzone": 0.5, 69 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":81,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) 70 | ] 71 | } 72 | ggt_debug_speedup_game={ 73 | "deadzone": 0.5, 74 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194325,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) 75 | ] 76 | } 77 | ggt_debug_step_frame={ 78 | "deadzone": 0.5, 79 | "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":46,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) 80 | ] 81 | } 82 | 83 | [rendering] 84 | 85 | textures/vram_compression/import_etc2_astc=true 86 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ![game-template-overview](https://github.com/user-attachments/assets/a89a031c-f880-45f6-ac84-4450c8bb4a22) 2 | 3 | > 🌟 You make games, the template handles the boring stuff. 4 | 5 |

6 | 7 | Godot Download badge 8 | 9 | 10 | 11 | GitHub release (latest by date) 12 | 13 |

14 | 15 | **Godot Game Template**, also GGT in short, is a simple generic starter project for Godot games. 16 | 17 | Provides a solid base for quick iterations. 18 | 19 | It worked well when used by small teams in game jams, but it should be generic 20 | enough to work for mid sized teams as well. 21 | 22 | ## Used by 23 | 24 | | Logo | Godot | Title | Platforms | 25 | | ------------------------------------------------------------------------------------------------------------------------------------------- | ----- | -------------------------- | ----------------------------------------------------------------------------------------------------------------- | 26 | | ![YouAreUto icon](https://play-lh.googleusercontent.com/lL54YNps-UPuDONDHfy3pmn8_aVUZGMorHJcDArimJWCQKjjNax0QMxpiAWCc5PUPbU=s100-rw) | 3.4 | **YouAreUto** (2019) | Android, iOS, [GitHub](https://github.com/YouAreUto/YouAreUto) | 27 | | ![Defending Todot icon](https://imgur.com/Bn10XAf.png) | 3.2.3 | **Defending Todot** (2020) | [HTML5](https://crystal-bit.github.io/defending-todot/), [GitHub](https://github.com/crystal-bit/defending-todot) | 28 | | ![Karooto No Gase icon](https://play-lh.googleusercontent.com/sWgjV9dJxa1jKina0mNbU3fGmqA4zuqtRWXfhn_dfEK6reW90GH1uz0wsai1SG898bOZ=s100-rw) | 3.x | **Karooto No Gase** (2021) | Android, HTML5 [Itch.io](https://calalinta.itch.io/) | 29 | | ![Pizza Poison Logo](https://github.com/user-attachments/assets/8f794de0-dcf8-4f8f-b29c-f1c619ba51d2) | 4.3 | **Pizza Poison** (2025) | [Itch.io](https://spesknight.itch.io/pizza-poison) | 30 | | Pangolick Quest icon | 4.4.1 | **Pangolick Quest** (2025) | HTML5, Windows, Linux, OSX [Itch.io](https://havbit.itch.io/pangolick-quest) | 31 | # Features Overview 32 | 33 | GGT is composed of multiple parts: 34 | 35 | 1. **ggt-core** addon 36 | 2. **ggt-shortcuts** addon 37 | 3. Godot project boilerplate (this repository) 38 | 39 | **ggt-core** provides: 40 | 41 | - Scene management with transitions and optional progress bar 42 | - Parameter passing between scenes 43 | - Multithreaded scene loading 44 | - single threaded loading fallback for web exports 45 | 46 | **ggt-shortcuts** provides: 47 | 48 | - Debug shortcuts mapped to keyboard keys for restart (R), pause frame (P), advance frame (.), speed up time scale (SHIFT), quit (Q) 49 | - easily configurable via Godot Input Map 50 | - Automatic shortcuts removal for release builds 51 | 52 | The godot project boilerplate provides: 53 | 54 | - GitHub Actions workflows for automatic builds+web deploy on Github Pages after each commit (thanks to [aBARICHELLO/godot-ci](https://github.com/aBARICHELLO/godot-ci)) 55 | - or you can use manual workflow dispatch 56 | - or you can use a local `release.sh` script to export multiple targets (Windows, Linux, Mac, ...) with a single command 57 | - or you can export manually from Godot as usual 58 | - A project structure that follows Godot best practices and naming conventions 59 | - Placeholder menu and gameplay scenes with support for keyboard, gamepad or touch inputs 60 | - A preconfigured a global theme for control nodes. Tweak `resources/theme/theme-main.tres` and every control nodes will inherit from it 61 | 62 | # Get started 63 | 64 | You have 2 options: 65 | 66 | ## 1. Get started with Github Templates: 67 | 68 | 1. [Create a new repo using this template](https://github.com/crystal-bit/godot-game-template/generate) 69 | 2. Clone the new repository locally 70 | 3. Open the project in [Godot](https://godotengine.org/download/) (GDScript) 71 | 72 | ## 2. Get started with a local project: 73 | 74 | 1. Go to https://github.com/crystal-bit/godot-game-template/releases 75 | 2. Download _Source code (zip)_ 76 | 3. Unzip the project 77 | 4. Open the project in [Godot Engine](https://godotengine.org/download/) (GDScript) and create your game! 78 | 79 | # How to... 80 | 81 | ## Change scene 82 | 83 | ```gdscript 84 | GGT.change_scene("res://scenes/gameplay/gameplay.tscn") 85 | ``` 86 | 87 | ![change_scene](https://user-images.githubusercontent.com/6860637/162567110-026c1979-6237-4255-bb2a-97815fc4b0c4.gif) 88 | 89 | ## Change scene and show progress bar 90 | 91 | ```gdscript 92 | GGT.change_scene("res://scenes/gameplay/gameplay.tscn", { 93 | "show_progress_bar": true 94 | }) 95 | ``` 96 | 97 | ![progress](https://user-images.githubusercontent.com/6860637/162567097-81b5c54e-1ee5-42b9-a583-60764ecff069.gif) 98 | 99 | ## Change scene and pass parameters 100 | 101 | ```gdscript 102 | var params = { 103 | "level": 4, 104 | "skin": "dark" 105 | } 106 | GGT.change_scene("res://scenes/gameplay/gameplay.tscn", params) 107 | ``` 108 | 109 | Nodes in the loaded scene can read params with: 110 | 111 | ```gdscript 112 | # gameplay.gd 113 | 114 | func _ready(): 115 | var params = GGT.get_current_scene_data().params 116 | print(params.level) # 4 117 | print(params.skin) # 'dark' 118 | # setup your scene here 119 | ``` 120 | 121 | ## Await scene transition to finish 122 | 123 | Note: all the tree is already paused during scene transitions, but if you need to 124 | wait for the graphic transition to completely disappear before calling some code you 125 | can use this approach: 126 | 127 | ```gdscript 128 | # gameplay.gd 129 | 130 | func _ready() -> void: 131 | if GGT.is_changing_scene(): # this will be false for the starting scene or if you start the scene with "Run current scene" or F6 shortcut during development 132 | await GGT.scene_transition_finished 133 | # activate your game logic here 134 | pass 135 | ``` 136 | 137 | ## Restart the current scene 138 | 139 | ```gd 140 | GGT.restart_scene() # old params will be reused 141 | ``` 142 | 143 | ## Restart the current scene and override params 144 | 145 | ```gd 146 | var new_params = { 147 | "level": 5, 148 | } 149 | GGT.restart_scene_with_params(new_params) 150 | ``` 151 | 152 | # addons/ggt-debug-shortcuts 153 | 154 | `addons/ggt-debug-shortcuts` is enabled by default and it builds on top of `ggt-core`. 155 | 156 | By default it will set these input actions to the project: 157 | 158 | | action | key | description | 159 | | ------------------------- | ---------- | ------------------------------------------------------------ | 160 | | "ggt_debug_pause_game" | KEY_P | Pauses the tree | 161 | | "ggt_debug_step_frame" | KEY_PERIOD | It advances 1 process_frame and 1 physics_frame during pause | 162 | | "ggt_debug_restart_scene" | KEY_R | Restarts the current scene, with the same parameters | 163 | | "ggt_debug_quit_game" | KEY_Q | Closes the game | 164 | | "ggt_debug_speedup_game" | KEY_SHIFT | Sets Engine.time_scale to 2 while holding key | 165 | 166 | You can change, remove or add shortcuts in [debug_shortcuts.gd](./addons/ggt-debug-shortcuts/autoload/debug_shortcuts.gd). 167 | 168 | **These shortcuts work in the editor and in debug builds and are automatically removed on release builds.** 169 | 170 | # Conventions and project structure 171 | 172 | - `assets/` 173 | - Contains textures, sprites, sounds, music, fonts, ... 174 | - `builds/` 175 | - output directory for game builds generated via `release.sh` (ignored by .gitignore and .gdignore) 176 | - `scenes/` 177 | - Contains Godot scenes (both entities, reusable scenes and "game screen" scenes) 178 | - Scene folders can contain `.gd` scripts or resources used by the scene 179 | 180 | Mostly inspired by the official [Godot Engine guidelines][l1]: 181 | 182 | - **snake_case** for files and folders (eg: game.gd, game.tscn) 183 | - **PascalCase** for node names (eg: Game, Player) 184 | 185 | [l1]: https://docs.godotengine.org/en/stable/getting_started/workflow/project_setup/project_organization.html#style-guide 186 | 187 | ### Lower Case file names 188 | 189 | This convention avoids having filesystem issues on different platforms. Stick with it 190 | and it will save you time. Read more 191 | [here](https://docs.godotengine.org/en/stable/getting_started/workflow/project_setup/project_organization.html#case-sensitivity): 192 | 193 | > Windows and recent macOS versions use case-insensitive filesystems by default, 194 | > whereas Linux distributions use a case-sensitive filesystem by default. This 195 | > can cause issues after exporting a project, since Godot's PCK virtual 196 | > filesystem is case-sensitive. To avoid this, it's recommended to stick to 197 | > snake_case naming for all files in the project (and lowercase characters in 198 | > general). 199 | 200 | See also [this PR](https://github.com/godotengine/godot/pull/82957/files) that adds `is_case_sensitive()`. 201 | 202 | ### Trim whitespaces on save 203 | 204 | If every developer on the team is using the built-in Godot Engine text editor I strongly suggest 205 | to activate this option: 206 | 207 | - Editor -> Editor Settings -> Text Editor/Behaviour -> Trim Trailing Whitespace on Save 208 | 209 | It avoids whitespace changes that may add noise in team work. 210 | 211 | # Export utilities 212 | 213 | ## `release.sh` 214 | 215 | From your project root: 216 | 217 | ```sh 218 | ./release.sh # this assumes that you have a "godot" binary/alias in your $PATH 219 | ``` 220 | 221 | Look inside the ./builds/ directory: 222 | 223 | ```sh 224 | builds 225 | └── ProjectName 226 | ├── html5 227 | │   ├── build.log # an export log + build datetime and git hash 228 | │   ├── index.html 229 | │   ├── ... 230 | ├── linux 231 | │   ├── ProjectName.x86_64 232 | │   └── build.log 233 | ├── osx 234 | │   ├── ProjectName.dmg 235 | │   └── build.log 236 | └── windows 237 | ├── ProjectName.exe 238 | └── build.log 239 | ``` 240 | 241 | ## Github Actions 242 | 243 | If you are using Github you can take advantage of: 244 | 245 | 1. automatic exports for every commit push (see [push-export.yml][ci-push-export]) 246 | 2. manual exports via Github CI (see [dispatch-export.yml][ci-dispatch] ) 247 | 248 | [ci-push-export]: ./.github/workflows/push-export.yml 249 | [ci-dispatch]: ./.github/workflows/push-export.yml 250 | 251 | You can read more on [Wiki - Continuos Integration][wiki_ci] 252 | 253 | [wiki_ci]: https://github.com/crystal-bit/godot-game-template/wiki/1.-Continuous-integration-(via-GitHub-Actions) 254 | 255 | # Contributing 256 | 257 | If you want to help the project, create games and feel free to get in touch and report any issue. 258 | 259 | ![Discord](https://img.shields.io/discord/686600734636376102?logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2) 260 | 261 | You can also join [the Discord server](https://discord.gg/SA6S2Db) (`#godot-game-template` channel). 262 | 263 | Before adding new features please open an issue to discuss it with other contributors. 264 | 265 | ## Contributors 266 | 267 | Many features were implemented only thanks to the help of: 268 | 269 | - [Andrea-Miele](https://github.com/Andrea-Miele) 270 | - [Fahien](https://github.com/Fahien) 271 | - [Andrea1141](https://github.com/Andrea1141) 272 | - [vini-guerrero](https://github.com/vini-guerrero) 273 | - [idbrii](https://github.com/idbrii) 274 | - [jrassa](https://github.com/jrassa) 275 | 276 | Also many tools were already available in the open source community, see the [Thanks](#thanks) section. 277 | 278 | # Thanks 279 | 280 | - For support & inspiration: 281 | - All the [contributors](https://github.com/crystal-bit/godot-game-template/graphs/contributors) 282 | - Crystal Bit community 283 | - GameLoop.it 284 | - Godot Engine Italia 285 | - Godot Engine 286 | - For their work on free and open source software: 287 | - [aBARICHELLO](https://github.com/aBARICHELLO/godot-ci) 288 | - [croconut](https://github.com/croconut/godot-multi-builder) 289 | - [josephbmanley](https://github.com/josephbmanley) 290 | - [GDQuest](https://github.com/GDquest) 291 | - [Scony](https://github.com/Scony) 292 | - [myood](https://github.com/myood) 293 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | # Set GODOT_BIN to a default value or expect it in PATH 5 | GODOT_BIN="godot" 6 | 7 | if ! which "$GODOT_BIN" >/dev/null; then 8 | echo "Error: '$GODOT_BIN binary executable not found." 9 | echo "Please ensure '$GODOT_BIN' is in your PATH." 10 | echo "Your path is:\n$PATH" 11 | exit 1 12 | fi 13 | 14 | if [ "$#" -ge 1 ] && [ "$1" = "--force" ]; then 15 | FORCE_BUILD=true 16 | else 17 | FORCE_BUILD=false 18 | fi 19 | 20 | # Derive export name 21 | PROJECT_NAME=$(grep '^config/name=' project.godot | sed -E 's/config\/name="([^"]+)"/\1/') 22 | GAME_VERSION=$(grep '^config/version=' project.godot | sed -E 's/config\/version="([^"]+)"/\1/') 23 | GODOT_VERSION=$($GODOT_BIN --version) 24 | if [ -z "$PROJECT_NAME" ] || [ -z "$GAME_VERSION" ]; then 25 | echo "Error: Could not extract config/name or config/version from project.godot" 26 | exit 1 27 | fi 28 | EXPORT_NAME="${PROJECT_NAME}-${GAME_VERSION}-[godot.$GODOT_VERSION]" 29 | 30 | # Check for uncommitted changes or untracked files in the Git workspace 31 | if [ "$FORCE_BUILD" != "true" ] && [ -n "$(git status --porcelain)" ]; then 32 | echo "Error: There are uncommitted changes or untracked files in the Git workspace." 33 | echo "Please commit/stash them before building. Or run the script with --force flag." 34 | exit 1 35 | fi 36 | 37 | # Export the game and redirect Godot output to a file 38 | export_game() { 39 | local export_preset="$1" 40 | local output_dir="$2" 41 | local build_name="$3" 42 | local logfile="$output_dir/build.log" 43 | 44 | # Get the current date and time 45 | current_datetime=$(date "+%Y-%m-%d %H:%M:%S") 46 | 47 | # Get the current Git commit hash (if available) 48 | git_commit=$(git rev-parse --short HEAD 2>/dev/null || echo "No Git commit available") 49 | 50 | # Create a log entry with date, time, and Git commit 51 | log_entry="$current_datetime - $PROJECT_NAME - Git commit: $git_commit" 52 | 53 | echo "Building $export_preset..." 54 | 55 | # Append the log entry to the build log file 56 | mkdir -p "$output_dir" 57 | touch $logfile 58 | echo "$log_entry" > "$logfile" 59 | 60 | $GODOT_BIN --headless --export-release "$export_preset" "$output_dir/$build_name" >> $logfile 2>&1 61 | 62 | echo "Done.\n" 63 | } 64 | 65 | export_game "Linux/X11" "builds/$EXPORT_NAME/linux" "$EXPORT_NAME.x86_64" 66 | export_game "Windows Desktop" "builds/$EXPORT_NAME/windows" "$EXPORT_NAME.exe" 67 | export_game "macOS" "builds/$EXPORT_NAME/osx" "$EXPORT_NAME.dmg" -------------------------------------------------------------------------------- /resources/theme/theme-main.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Theme" load_steps=2 format=3 uid="uid://ducfept6pmkkm"] 2 | 3 | [ext_resource type="FontFile" uid="uid://cawekr44fruhm" path="res://assets/fonts/open-sans/open-sans-regular.ttf" id="1_6yttj"] 4 | 5 | [resource] 6 | default_font = ExtResource("1_6yttj") 7 | default_font_size = 20 8 | LabelSmall/base_type = &"Label" 9 | LabelSmall/font_sizes/font_size = 16 10 | MarginContainer/constants/margin_bottom = 32 11 | MarginContainer/constants/margin_left = 32 12 | MarginContainer/constants/margin_right = 32 13 | MarginContainer/constants/margin_top = 32 14 | -------------------------------------------------------------------------------- /scenes/gameplay/gameplay.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | @onready var sprite_2d: Sprite2D = $Sprite2D 4 | 5 | var t = 0 6 | 7 | func _ready() -> void: 8 | var scene_data = GGT.get_current_scene_data() 9 | print("GGT/Gameplay: scene params are ", scene_data.params) 10 | 11 | sprite_2d.position = get_viewport().get_visible_rect().size / 2 12 | 13 | if GGT.is_changing_scene(): # this will be false if starting the scene with "Run current scene" or F6 shortcut 14 | await GGT.scene_transition_finished 15 | 16 | print("GGT/Gameplay: scene transition animation finished") 17 | 18 | 19 | func _process(delta): 20 | var size = get_viewport().get_visible_rect().size 21 | t += delta * 1.5 22 | sprite_2d.position.x = size.x / 2.0 + 200.0 * sin(t * 0.8) 23 | sprite_2d.position.y = size.y / 2.0 + 140.0 * sin(t) 24 | -------------------------------------------------------------------------------- /scenes/gameplay/gameplay.gd.uid: -------------------------------------------------------------------------------- 1 | uid://b83omkj4aqsph 2 | -------------------------------------------------------------------------------- /scenes/gameplay/gameplay.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=3 uid="uid://4fyoq8npekf0"] 2 | 3 | [ext_resource type="Texture2D" uid="uid://dtwpm3uclaspj" path="res://assets/sprites/icon.png" id="1"] 4 | [ext_resource type="PackedScene" uid="uid://barl4q1kugrmm" path="res://scenes/gameplay/pause-layer/pause-layer.tscn" id="2"] 5 | [ext_resource type="Script" uid="uid://b83omkj4aqsph" path="res://scenes/gameplay/gameplay.gd" id="5"] 6 | 7 | [node name="Gameplay" type="Node"] 8 | script = ExtResource("5") 9 | 10 | [node name="Sprite2D" type="Sprite2D" parent="."] 11 | texture = ExtResource("1") 12 | 13 | [node name="PauseLayer" parent="." instance=ExtResource("2")] 14 | -------------------------------------------------------------------------------- /scenes/gameplay/pause-layer/pause-layer.gd: -------------------------------------------------------------------------------- 1 | extends CanvasLayer 2 | 3 | @onready var pause := self 4 | @onready var pause_button := $MarginContainer/Control/PauseButton 5 | @onready var resume_option := $MarginContainer/Control/VBoxOptions/Resume 6 | @onready var label = $MarginContainer/Control/Label 7 | @onready var pause_options = $MarginContainer/Control/VBoxOptions 8 | @onready var color_rect = $ColorRect 9 | 10 | @onready var nodes_grp1 = [pause_button, label] # should be visible during gamemplay and hidden during pause 11 | @onready var nodes_grp2 = [pause_options, color_rect] # should be visible only in pause menu 12 | 13 | 14 | func _ready(): 15 | pause_hide() 16 | 17 | 18 | func pause_show(): 19 | for n in nodes_grp1: 20 | n.hide() 21 | for n in nodes_grp2: 22 | n.show() 23 | 24 | 25 | func pause_hide(): 26 | for n in nodes_grp1: 27 | if n: 28 | n.show() 29 | 30 | for n in nodes_grp2: 31 | if n: 32 | n.hide() 33 | 34 | 35 | func _unhandled_input(event): 36 | if event.is_action_pressed("pause"): 37 | if get_tree().paused: 38 | resume() 39 | else: 40 | pause_game() 41 | get_viewport().set_input_as_handled() 42 | 43 | 44 | func resume(): 45 | get_tree().paused = false 46 | pause_hide() 47 | 48 | 49 | func pause_game(): 50 | resume_option.grab_focus() 51 | get_tree().paused = true 52 | pause_show() 53 | 54 | 55 | func _on_Resume_pressed(): 56 | resume() 57 | 58 | 59 | func _on_PauseButton_pressed(): 60 | pause_game() 61 | 62 | 63 | func _on_main_menu_pressed(): 64 | GGT.change_scene("res://scenes/menu/menu.tscn", {"show_progress_bar": false}) 65 | -------------------------------------------------------------------------------- /scenes/gameplay/pause-layer/pause-layer.gd.uid: -------------------------------------------------------------------------------- 1 | uid://do7kkb4ijqk5p 2 | -------------------------------------------------------------------------------- /scenes/gameplay/pause-layer/pause-layer.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=3 uid="uid://barl4q1kugrmm"] 2 | 3 | [ext_resource type="Script" uid="uid://do7kkb4ijqk5p" path="res://scenes/gameplay/pause-layer/pause-layer.gd" id="2"] 4 | [ext_resource type="Theme" uid="uid://ducfept6pmkkm" path="res://resources/theme/theme-main.tres" id="3"] 5 | [ext_resource type="Texture2D" uid="uid://byniue2cdd2yv" path="res://scenes/gameplay/pause-layer/pause_button.png" id="4"] 6 | 7 | [node name="PauseLayer" type="CanvasLayer"] 8 | process_mode = 3 9 | script = ExtResource("2") 10 | 11 | [node name="ColorRect" type="ColorRect" parent="."] 12 | visible = false 13 | anchors_preset = 15 14 | anchor_right = 1.0 15 | anchor_bottom = 1.0 16 | mouse_filter = 2 17 | color = Color(0.243137, 0.211765, 0.290196, 0.717647) 18 | 19 | [node name="MarginContainer" type="MarginContainer" parent="."] 20 | anchors_preset = 15 21 | anchor_right = 1.0 22 | anchor_bottom = 1.0 23 | grow_horizontal = 2 24 | grow_vertical = 2 25 | mouse_filter = 2 26 | 27 | [node name="Control" type="Control" parent="MarginContainer"] 28 | layout_mode = 2 29 | mouse_filter = 2 30 | 31 | [node name="PauseButton" type="TextureButton" parent="MarginContainer/Control"] 32 | layout_mode = 1 33 | offset_right = 42.0 34 | offset_bottom = 42.0 35 | size_flags_horizontal = 0 36 | mouse_filter = 1 37 | texture_normal = ExtResource("4") 38 | ignore_texture_size = true 39 | stretch_mode = 0 40 | 41 | [node name="VBoxOptions" type="VBoxContainer" parent="MarginContainer/Control"] 42 | visible = false 43 | layout_mode = 1 44 | anchors_preset = 8 45 | anchor_left = 0.5 46 | anchor_top = 0.5 47 | anchor_right = 0.5 48 | anchor_bottom = 0.5 49 | offset_left = -58.0 50 | offset_top = -38.0 51 | offset_right = 58.0 52 | offset_bottom = 38.0 53 | grow_horizontal = 2 54 | grow_vertical = 2 55 | mouse_filter = 2 56 | theme_override_constants/separation = 20 57 | 58 | [node name="Resume" type="LinkButton" parent="MarginContainer/Control/VBoxOptions"] 59 | layout_mode = 2 60 | focus_mode = 2 61 | mouse_filter = 1 62 | text = "RESUME" 63 | 64 | [node name="MainMenu" type="LinkButton" parent="MarginContainer/Control/VBoxOptions"] 65 | layout_mode = 2 66 | focus_mode = 2 67 | mouse_filter = 1 68 | text = "MAIN MENU" 69 | 70 | [node name="Label" type="Label" parent="MarginContainer/Control"] 71 | layout_mode = 1 72 | anchors_preset = 5 73 | anchor_left = 0.5 74 | anchor_right = 0.5 75 | offset_left = -222.0 76 | offset_right = 222.0 77 | offset_bottom = 28.0 78 | grow_horizontal = 2 79 | theme = ExtResource("3") 80 | theme_override_colors/font_color = Color(0.788235, 0.788235, 0.788235, 1) 81 | text = "Pause: ESC (keyboard) or START button (joypad)" 82 | 83 | [connection signal="pressed" from="MarginContainer/Control/PauseButton" to="." method="_on_PauseButton_pressed"] 84 | [connection signal="pressed" from="MarginContainer/Control/VBoxOptions/Resume" to="." method="_on_Resume_pressed"] 85 | [connection signal="pressed" from="MarginContainer/Control/VBoxOptions/MainMenu" to="." method="_on_main_menu_pressed"] 86 | -------------------------------------------------------------------------------- /scenes/gameplay/pause-layer/pause_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crystal-bit/godot-game-template/9caae9ef8d7138b638f0df29d820152212b11926/scenes/gameplay/pause-layer/pause_button.png -------------------------------------------------------------------------------- /scenes/gameplay/pause-layer/pause_button.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://byniue2cdd2yv" 6 | path="res://.godot/imported/pause_button.png-70c9bf3f2acf4e572f86b5334cb6e8a3.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://scenes/gameplay/pause-layer/pause_button.png" 14 | dest_files=["res://.godot/imported/pause_button.png-70c9bf3f2acf4e572f86b5334cb6e8a3.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /scenes/menu/game_version.gd: -------------------------------------------------------------------------------- 1 | extends Label 2 | 3 | 4 | func _ready(): 5 | text = ProjectSettings.get_setting("application/config/version") # you need to enable "Advanced Settings" to make this property visible 6 | -------------------------------------------------------------------------------- /scenes/menu/game_version.gd.uid: -------------------------------------------------------------------------------- 1 | uid://dfnwymtygg1to 2 | -------------------------------------------------------------------------------- /scenes/menu/godot_version.gd: -------------------------------------------------------------------------------- 1 | extends Label 2 | 3 | 4 | func _ready(): 5 | text = "Godot %s" % Engine.get_version_info().string 6 | -------------------------------------------------------------------------------- /scenes/menu/godot_version.gd.uid: -------------------------------------------------------------------------------- 1 | uid://baky6bgu7psf2 2 | -------------------------------------------------------------------------------- /scenes/menu/menu.gd: -------------------------------------------------------------------------------- 1 | extends Control 2 | 3 | @onready var btn_play = $MarginContainer/Control/VBoxContainer/PlayButton 4 | @onready var btn_exit = $MarginContainer/Control/VBoxContainer/ExitButton 5 | 6 | 7 | func _ready(): 8 | # needed for gamepads to work 9 | btn_play.grab_focus() 10 | if OS.has_feature('web'): 11 | btn_exit.queue_free() # exit button dosn't make sense on HTML5 12 | 13 | 14 | func _on_PlayButton_pressed() -> void: 15 | var params = { 16 | "show_progress_bar": true, 17 | "a_number": 10, 18 | "a_string": "Ciao!", 19 | "an_array": [1, 2, 3, 4], 20 | "a_dict": { 21 | "name": "test", 22 | "val": 15 23 | }, 24 | } 25 | GGT.change_scene("res://scenes/gameplay/gameplay.tscn", params) 26 | 27 | 28 | func _on_ExitButton_pressed() -> void: 29 | # gently shutdown the game 30 | var transitions = get_node_or_null("/root/GGT_Transitions") 31 | if transitions: 32 | transitions.fade_in({ 33 | 'show_progress_bar': false 34 | }) 35 | await transitions.anim.animation_finished 36 | await get_tree().create_timer(0.3).timeout 37 | get_tree().quit() 38 | -------------------------------------------------------------------------------- /scenes/menu/menu.gd.uid: -------------------------------------------------------------------------------- 1 | uid://cvc42inud8fxx 2 | -------------------------------------------------------------------------------- /scenes/menu/menu.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=5 format=3 uid="uid://c2gocuhw2o7py"] 2 | 3 | [ext_resource type="FontFile" uid="uid://da2t6lyf41wty" path="res://assets/fonts/open-sans/open-sans-bold.ttf" id="4"] 4 | [ext_resource type="Script" uid="uid://dfnwymtygg1to" path="res://scenes/menu/game_version.gd" id="4_3hod2"] 5 | [ext_resource type="Script" uid="uid://cvc42inud8fxx" path="res://scenes/menu/menu.gd" id="5"] 6 | [ext_resource type="Script" uid="uid://baky6bgu7psf2" path="res://scenes/menu/godot_version.gd" id="5_fdyjp"] 7 | 8 | [node name="Menu" type="Control"] 9 | layout_mode = 3 10 | anchors_preset = 15 11 | anchor_right = 1.0 12 | anchor_bottom = 1.0 13 | grow_horizontal = 2 14 | grow_vertical = 2 15 | script = ExtResource("5") 16 | 17 | [node name="ColorRect" type="ColorRect" parent="."] 18 | layout_mode = 1 19 | anchors_preset = 15 20 | anchor_right = 1.0 21 | anchor_bottom = 1.0 22 | grow_horizontal = 2 23 | grow_vertical = 2 24 | color = Color(0.176471, 0.682353, 0.647059, 1) 25 | 26 | [node name="MarginContainer" type="MarginContainer" parent="."] 27 | layout_mode = 1 28 | anchors_preset = 15 29 | anchor_right = 1.0 30 | anchor_bottom = 1.0 31 | grow_horizontal = 2 32 | grow_vertical = 2 33 | 34 | [node name="Control" type="Control" parent="MarginContainer"] 35 | layout_mode = 2 36 | 37 | [node name="CenterContainer" type="CenterContainer" parent="MarginContainer/Control"] 38 | layout_mode = 1 39 | anchors_preset = 15 40 | anchor_right = 1.0 41 | anchor_bottom = 1.0 42 | offset_left = -8.0 43 | offset_right = -8.0 44 | offset_bottom = -339.0 45 | grow_horizontal = 2 46 | grow_vertical = 2 47 | 48 | [node name="Title" type="Label" parent="MarginContainer/Control/CenterContainer"] 49 | layout_mode = 2 50 | theme_override_fonts/font = ExtResource("4") 51 | theme_override_font_sizes/font_size = 60 52 | text = "Godot Game Template" 53 | uppercase = true 54 | 55 | [node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer/Control"] 56 | layout_mode = 1 57 | anchors_preset = 8 58 | anchor_left = 0.5 59 | anchor_top = 0.5 60 | anchor_right = 0.5 61 | anchor_bottom = 0.5 62 | offset_left = -104.0 63 | offset_top = -30.0 64 | offset_right = 96.0 65 | offset_bottom = 134.0 66 | grow_horizontal = 2 67 | grow_vertical = 2 68 | theme_override_constants/separation = 16 69 | 70 | [node name="PlayButton" type="Button" parent="MarginContainer/Control/VBoxContainer"] 71 | custom_minimum_size = Vector2(200, 70) 72 | layout_mode = 2 73 | focus_neighbor_bottom = NodePath("../ExitButton") 74 | focus_next = NodePath("../ExitButton") 75 | text = "START" 76 | 77 | [node name="ExitButton" type="Button" parent="MarginContainer/Control/VBoxContainer"] 78 | custom_minimum_size = Vector2(200, 70) 79 | layout_mode = 2 80 | focus_neighbor_top = NodePath("../PlayButton") 81 | focus_previous = NodePath("../PlayButton") 82 | text = "EXIT" 83 | 84 | [node name="Version" type="VBoxContainer" parent="MarginContainer/Control"] 85 | layout_mode = 1 86 | anchors_preset = 2 87 | anchor_top = 1.0 88 | anchor_bottom = 1.0 89 | offset_top = -50.0 90 | offset_right = 122.0 91 | grow_vertical = 0 92 | 93 | [node name="GameVersion" type="Label" parent="MarginContainer/Control/Version"] 94 | layout_mode = 2 95 | theme_type_variation = &"LabelSmall" 96 | text = "" 97 | script = ExtResource("4_3hod2") 98 | 99 | [node name="GodotVersion" type="Label" parent="MarginContainer/Control/Version"] 100 | layout_mode = 2 101 | theme_type_variation = &"LabelSmall" 102 | theme_override_colors/font_color = Color(0.92549, 0.92549, 0.92549, 1) 103 | text = "" 104 | script = ExtResource("5_fdyjp") 105 | 106 | [node name="Credits" type="VBoxContainer" parent="MarginContainer/Control"] 107 | layout_mode = 1 108 | anchors_preset = 3 109 | anchor_left = 1.0 110 | anchor_top = 1.0 111 | anchor_right = 1.0 112 | anchor_bottom = 1.0 113 | offset_left = -86.0 114 | offset_top = -23.0 115 | grow_horizontal = 0 116 | grow_vertical = 0 117 | 118 | [node name="MadeByLabel" type="Label" parent="MarginContainer/Control/Credits"] 119 | layout_mode = 2 120 | theme_type_variation = &"LabelSmall" 121 | theme_override_colors/font_color = Color(1, 1, 1, 1) 122 | text = "made by: ..." 123 | 124 | [node name="Developer1" type="Label" parent="MarginContainer/Control/Credits"] 125 | visible = false 126 | layout_mode = 2 127 | theme_type_variation = &"LabelSmall" 128 | theme_override_colors/font_color = Color(0.92549, 0.92549, 0.92549, 1) 129 | 130 | [node name="Developer2" type="Label" parent="MarginContainer/Control/Credits"] 131 | visible = false 132 | layout_mode = 2 133 | theme_type_variation = &"LabelSmall" 134 | theme_override_colors/font_color = Color(0.886275, 0.87451, 0.87451, 1) 135 | text = "Developer 2" 136 | 137 | [node name="Developer3" type="Label" parent="MarginContainer/Control/Credits"] 138 | visible = false 139 | layout_mode = 2 140 | theme_type_variation = &"LabelSmall" 141 | theme_override_colors/font_color = Color(0.886275, 0.87451, 0.87451, 1) 142 | text = "Developer 3" 143 | 144 | [connection signal="pressed" from="MarginContainer/Control/VBoxContainer/PlayButton" to="." method="_on_PlayButton_pressed"] 145 | [connection signal="pressed" from="MarginContainer/Control/VBoxContainer/ExitButton" to="." method="_on_ExitButton_pressed"] 146 | --------------------------------------------------------------------------------