├── .cursorrules ├── .envrc ├── .github ├── pull_request_template.md └── workflows │ ├── benchmark-comment.yml │ ├── benchmarks.yml │ ├── book.yml │ └── ci.yml ├── .gitignore ├── CLAUDE.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── addons └── godot-bevy │ ├── README.md │ ├── bevy_app_singleton.tscn │ ├── optimized_scene_tree_watcher.gd │ ├── optimized_scene_tree_watcher.gd.uid │ ├── plugin.cfg │ ├── plugin.gd │ ├── plugin.gd.uid │ └── wizard │ ├── project_wizard.gd │ ├── project_wizard.gd.uid │ └── project_wizard.tscn ├── book ├── book.toml └── src │ ├── SUMMARY.md │ ├── getting-started │ ├── basic-concepts.md │ ├── examples.md │ ├── index.md │ ├── installation.md │ └── plugins.md │ ├── input │ ├── bevy-vs-godot.md │ ├── index.md │ └── signals.md │ ├── introduction.md │ ├── migration │ ├── index.md │ ├── v0.6-to-v0.7.md │ ├── v0.7-to-v0.8.md │ └── v0.8-to-v0.9.md │ ├── platform-targets │ ├── android.md │ └── index.md │ ├── profiling │ └── profiling.md │ ├── scene-tree │ ├── custom-nodes │ │ ├── automatic-markers.md │ │ ├── index.md │ │ ├── nodes-from-components-and-bundles.md │ │ └── property-mapping-with-bevy-bundle.md │ ├── index.md │ ├── querying.md │ └── timing.md │ ├── threading │ └── index.md │ ├── timing │ └── index.md │ └── transforms │ ├── custom-sync.md │ ├── index.md │ └── sync-modes.md ├── devenv.lock ├── devenv.nix ├── devenv.yaml ├── examples ├── avian-physics-demo │ ├── README.md │ ├── godot │ │ ├── .editorconfig │ │ ├── .gitattributes │ │ ├── .gitignore │ │ ├── export_presets.cfg │ │ ├── icon.svg │ │ ├── icon.svg.import │ │ ├── project.godot │ │ ├── rust.gdextension │ │ ├── rust.gdextension.uid │ │ └── scenes │ │ │ ├── bevy_app_singleton.tscn │ │ │ ├── floor.tscn │ │ │ ├── main.tscn │ │ │ └── simple_box.tscn │ ├── rust │ │ ├── Cargo.toml │ │ └── src │ │ │ └── lib.rs │ └── screenshot.png ├── dodge-the-creeps-2d │ ├── README.md │ ├── godot │ │ ├── .editorconfig │ │ ├── .gitattributes │ │ ├── .gitignore │ │ ├── art │ │ │ ├── enemyFlyingAlt_1.png │ │ │ ├── enemyFlyingAlt_1.png.import │ │ │ ├── enemyFlyingAlt_2.png │ │ │ ├── enemyFlyingAlt_2.png.import │ │ │ ├── enemySwimming_1.png │ │ │ ├── enemySwimming_1.png.import │ │ │ ├── enemySwimming_2.png │ │ │ ├── enemySwimming_2.png.import │ │ │ ├── enemyWalking_1.png │ │ │ ├── enemyWalking_1.png.import │ │ │ ├── enemyWalking_2.png │ │ │ ├── enemyWalking_2.png.import │ │ │ ├── playerGrey_up1.png │ │ │ ├── playerGrey_up1.png.import │ │ │ ├── playerGrey_up2.png │ │ │ ├── playerGrey_up2.png.import │ │ │ ├── playerGrey_walk1.png │ │ │ ├── playerGrey_walk1.png.import │ │ │ ├── playerGrey_walk2.png │ │ │ └── playerGrey_walk2.png.import │ │ ├── audio │ │ │ ├── House In a Forest Loop.ogg │ │ │ ├── House In a Forest Loop.ogg.import │ │ │ ├── gameover.wav │ │ │ ├── gameover.wav.import │ │ │ ├── plop.ogg │ │ │ └── plop.ogg.import │ │ ├── export_presets.cfg │ │ ├── fonts │ │ │ ├── FONTLOG.txt │ │ │ ├── LICENSE.txt │ │ │ ├── Xolonium-Regular.ttf │ │ │ └── Xolonium-Regular.ttf.import │ │ ├── icon.svg │ │ ├── icon.svg.import │ │ ├── project.godot │ │ ├── rust.gdextension │ │ ├── rust.gdextension.uid │ │ └── scenes │ │ │ ├── bevy_app_singleton.tscn │ │ │ ├── hud.tscn │ │ │ ├── main.tscn │ │ │ ├── mob.tscn │ │ │ └── player.tscn │ └── rust │ │ ├── Cargo.toml │ │ └── src │ │ ├── commands.rs │ │ ├── gameplay │ │ ├── audio.rs │ │ ├── countdown.rs │ │ ├── gameover.rs │ │ ├── mob.rs │ │ ├── mod.rs │ │ ├── player.rs │ │ └── score.rs │ │ ├── lib.rs │ │ ├── main_menu.rs │ │ └── nodes │ │ ├── mod.rs │ │ └── player.rs ├── input-event-demo │ ├── README.md │ ├── godot │ │ ├── .editorconfig │ │ ├── .gitattributes │ │ ├── .gitignore │ │ ├── export_presets.cfg │ │ ├── icon.svg │ │ ├── icon.svg.import │ │ ├── project.godot │ │ ├── rust.gdextension │ │ ├── rust.gdextension.uid │ │ └── scenes │ │ │ ├── bevy_app_singleton.tscn │ │ │ └── main.tscn │ └── rust │ │ ├── Cargo.toml │ │ └── src │ │ ├── bevy_enhanced_input.rs │ │ ├── bevy_input.rs │ │ ├── godot_input.rs │ │ ├── leafwing_input.rs │ │ └── lib.rs ├── perf-test │ ├── .gitignore │ ├── BENCHMARKING.md │ ├── README.md │ ├── baseline.json │ ├── benchmark.sh │ ├── godot │ │ ├── .editorconfig │ │ ├── .gitattributes │ │ ├── .gitignore │ │ ├── addons │ │ ├── boids.pck │ │ ├── export_presets.cfg │ │ ├── icon.svg │ │ ├── icon.svg.import │ │ ├── project.godot │ │ ├── rust.gdextension │ │ ├── rust.gdextension.uid │ │ ├── scenes │ │ │ ├── benchmark_cli.tscn │ │ │ ├── boid.tscn │ │ │ ├── main.tscn │ │ │ ├── particle.tscn │ │ │ └── test_ui_only.tscn │ │ ├── scripts │ │ │ ├── benchmark_cli.gd │ │ │ ├── benchmark_cli.gd.uid │ │ │ ├── godot_boids.gd │ │ │ ├── godot_boids.gd.backup │ │ │ ├── godot_boids.gd.uid │ │ │ ├── main.gd │ │ │ └── main.gd.uid │ │ └── textures │ │ │ └── boid_circle.tres │ ├── regression_test.py │ └── rust │ │ ├── Cargo.toml │ │ └── src │ │ ├── container.rs │ │ ├── lib.rs │ │ └── particle_rain.rs ├── platformer-2d │ ├── README.md │ ├── godot │ │ ├── .editorconfig │ │ ├── .gitattributes │ │ ├── .gitignore │ │ ├── assets │ │ │ ├── art │ │ │ │ ├── monochrome_tilemap_transparent.png │ │ │ │ └── monochrome_tilemap_transparent.png.import │ │ │ └── audio │ │ │ │ ├── actiontheme-v3.ogg │ │ │ │ ├── actiontheme-v3.ogg.import │ │ │ │ ├── annoyingwaltz.wav │ │ │ │ ├── annoyingwaltz.wav.import │ │ │ │ ├── gem.wav │ │ │ │ ├── gem.wav.import │ │ │ │ ├── jump.wav │ │ │ │ └── jump.wav.import │ │ ├── export_presets.cfg │ │ ├── icon.svg │ │ ├── icon.svg.import │ │ ├── project.godot │ │ ├── rust.gdextension │ │ ├── rust.gdextension.uid │ │ └── scenes │ │ │ ├── bevy_app_singleton.tscn │ │ │ ├── levels │ │ │ ├── level_1.tscn │ │ │ ├── level_2.tscn │ │ │ ├── level_3.tscn │ │ │ └── main_menu.tscn │ │ │ ├── sprites │ │ │ ├── door.tscn │ │ │ ├── gem.tscn │ │ │ └── player.tscn │ │ │ └── ui │ │ │ └── hud.tscn │ └── rust │ │ ├── Cargo.toml │ │ └── src │ │ ├── components.rs │ │ ├── gameplay │ │ ├── audio.rs │ │ ├── door.rs │ │ ├── gem.rs │ │ ├── hud.rs │ │ ├── mod.rs │ │ └── player.rs │ │ ├── level_manager.rs │ │ ├── lib.rs │ │ ├── main_menu.rs │ │ └── scene_management.rs ├── plugin-test │ ├── .editorconfig │ ├── .gitignore │ ├── addons │ ├── icon.svg │ ├── icon.svg.import │ ├── main.tscn │ └── project.godot ├── run_godot.rs ├── simple-node2d-movement │ ├── README.md │ ├── final-product-screencast.gif │ ├── godot │ │ ├── .editorconfig │ │ ├── .gitattributes │ │ ├── .gitignore │ │ ├── bevy_app_singleton.tscn │ │ ├── icon.svg │ │ ├── icon.svg.import │ │ ├── main.tscn │ │ ├── project.godot │ │ ├── rust.gdextension │ │ └── rust.gdextension.uid │ └── rust │ │ ├── Cargo.toml │ │ └── src │ │ └── lib.rs ├── timing-test │ ├── README.md │ ├── godot │ │ ├── .editorconfig │ │ ├── .gitattributes │ │ ├── .gitignore │ │ ├── export_presets.cfg │ │ ├── icon.svg │ │ ├── icon.svg.import │ │ ├── project.godot │ │ ├── rust.gdextension │ │ ├── rust.gdextension.uid │ │ └── scenes │ │ │ ├── bevy_app_singleton.tscn │ │ │ └── main.tscn │ └── rust │ │ ├── Cargo.toml │ │ └── src │ │ └── lib.rs └── two-way-sync-demo │ ├── README.md │ ├── godot │ ├── .editorconfig │ ├── .gitattributes │ ├── .gitignore │ ├── bevy_app_singleton.tscn │ ├── main.tscn │ ├── project.godot │ ├── quad.gd │ ├── quad.gd.uid │ ├── rust.gdextension │ └── rust.gdextension.uid │ └── rust │ ├── Cargo.toml │ └── src │ └── lib.rs ├── godot-bevy-macros ├── Cargo.toml └── src │ ├── bevy_bundle.rs │ ├── godot_node │ ├── attr.rs │ ├── bundle.rs │ ├── component.rs │ └── mod.rs │ ├── lib.rs │ └── node_tree_view.rs ├── godot-bevy ├── Cargo.toml └── src │ ├── app.rs │ ├── interop │ ├── godot_node_handle.rs │ ├── godot_resource_handle.rs │ ├── mod.rs │ ├── node_markers.rs │ └── utils.rs │ ├── lib.rs │ ├── node_tree_view.rs │ ├── plugins │ ├── assets.rs │ ├── audio │ │ ├── channel.rs │ │ ├── command.rs │ │ ├── mod.rs │ │ ├── output.rs │ │ ├── player.rs │ │ ├── plugin.rs │ │ ├── settings.rs │ │ └── tween.rs │ ├── collisions.rs │ ├── core.rs │ ├── godot_bevy_logger.rs │ ├── input │ │ ├── events.rs │ │ ├── input_bridge.rs │ │ └── mod.rs │ ├── mod.rs │ ├── packed_scene.rs │ ├── scene_tree │ │ ├── autosync.rs │ │ ├── mod.rs │ │ ├── node_type_checking_generated.rs │ │ └── plugin.rs │ ├── signals.rs │ └── transforms │ │ ├── change_filter.rs │ │ ├── config.rs │ │ ├── conversions.rs │ │ ├── custom_sync.rs │ │ ├── math.rs │ │ ├── mod.rs │ │ ├── plugin.rs │ │ └── sync_systems.rs │ ├── prelude.rs │ ├── tests │ ├── mod.rs │ └── reflect_tests.rs │ ├── utils │ ├── debug.rs │ ├── math.rs │ ├── mod.rs │ └── profiling.rs │ └── watchers │ ├── collision_watcher.rs │ ├── input_watcher.rs │ ├── mod.rs │ └── scene_tree_watcher.rs ├── itest ├── BENCHMARKING.md ├── README.md ├── baseline.json ├── godot │ ├── .gitignore │ ├── BenchRunner.gd │ ├── BenchRunner.tscn │ ├── TestRunner.gd │ ├── TestRunner.gd.uid │ ├── TestRunner.tscn │ ├── addons │ │ └── godot-bevy │ ├── itest.gdextension │ ├── itest.gdextension.uid │ └── project.godot ├── run-benches.sh ├── run-tests.sh └── rust │ ├── Cargo.toml │ ├── macros │ ├── Cargo.toml │ └── src │ │ └── lib.rs │ └── src │ ├── benchmarks.rs │ ├── framework │ ├── bencher.rs │ ├── mod.rs │ ├── test_app.rs │ └── test_helpers.rs │ ├── lib.rs │ ├── real_frame_tests.rs │ ├── scene_tree_tests.rs │ └── transform_sync_tests.rs ├── nix └── godot-bin.nix ├── rust-toolchain.toml ├── rustfmt.toml └── scripts ├── README.md └── generate_godot_types.py /.envrc: -------------------------------------------------------------------------------- 1 | export DIRENV_WARN_TIMEOUT=20s 2 | export DEVENV_TASKS_QUIET=true 3 | 4 | eval "$(devenv direnvrc)" 5 | 6 | # The use_devenv function supports passing flags to the devenv command 7 | # For example: use devenv --impure --option services.postgres.enable:bool true 8 | use devenv --quiet 9 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | 4 | 5 | 6 | ## Checklist 7 | 8 | - [ ] Create awesomeness! 9 | - [ ] Update book (if needed) 10 | - [ ] Add/update tests (if needed) 11 | - [ ] Update examples (if needed) 12 | - [ ] Run examples 13 | - [ ] Run `cargo fmt` 14 | 15 | ## Related Issues 16 | 17 | Closes #[issue_number] 18 | -------------------------------------------------------------------------------- /.github/workflows/book.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Book 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - 'book/**' 9 | - '.github/workflows/book.yml' 10 | pull_request: 11 | paths: 12 | - 'book/**' 13 | - '.github/workflows/book.yml' 14 | workflow_dispatch: 15 | 16 | permissions: 17 | contents: read 18 | pages: write 19 | id-token: write 20 | 21 | concurrency: 22 | group: "pages" 23 | cancel-in-progress: false 24 | 25 | jobs: 26 | build: 27 | runs-on: ubuntu-latest 28 | steps: 29 | - uses: actions/checkout@v4 30 | 31 | - name: Setup mdBook 32 | uses: peaceiris/actions-mdbook@v2 33 | with: 34 | mdbook-version: '0.4.40' 35 | 36 | - name: Build book 37 | run: | 38 | cd book 39 | mdbook build 40 | 41 | - name: Upload artifact 42 | if: github.event_name == 'push' && github.ref == 'refs/heads/main' 43 | uses: actions/upload-pages-artifact@v3 44 | with: 45 | path: ./book/book 46 | 47 | deploy: 48 | if: github.event_name == 'push' && github.ref == 'refs/heads/main' 49 | environment: 50 | name: github-pages 51 | url: ${{ steps.deployment.outputs.page_url }} 52 | runs-on: ubuntu-latest 53 | needs: build 54 | steps: 55 | - name: Deploy to GitHub Pages 56 | id: deployment 57 | uses: actions/deploy-pages@v4 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .DS_Store 3 | 4 | # Jetbrains IDEs 5 | .idea 6 | 7 | profile.json.gz 8 | 9 | # Book 10 | book/book 11 | benchmark_results/ 12 | 13 | # https://devenv.sh/ 14 | .devenv* 15 | .devenv/ 16 | devenv.local.nix 17 | # The .pre-commit-config.yaml file is a symlink to an autogenerated file in your 18 | # devenv Nix store. It is not necessary to commit this file to your repository 19 | # and it can safely be ignored. 20 | .pre-commit-config.yaml 21 | 22 | # https://direnv.net/ 23 | .direnv 24 | 25 | # tracy profiler captures 26 | *.tracy 27 | 28 | .cargo/ 29 | /inspo 30 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace.package] 2 | version = "0.9.2" 3 | edition = "2024" 4 | authors = ["David Chavez "] 5 | repository = "https://github.com/bytemeadow/godot-bevy" 6 | keywords = ["godot", "game", "engine", "gamedev", "graphics"] 7 | categories = ["game-engines"] 8 | license = "MIT OR Apache-2.0" 9 | 10 | [workspace] 11 | members = [ 12 | "godot-bevy", 13 | "godot-bevy-macros", 14 | "itest/rust", 15 | "examples/avian-physics-demo/rust", 16 | "examples/dodge-the-creeps-2d/rust", 17 | "examples/timing-test/rust", 18 | "examples/input-event-demo/rust", 19 | "examples/platformer-2d/rust", 20 | "examples/simple-node2d-movement/rust", 21 | "examples/perf-test/rust", 22 | "examples/two-way-sync-demo/rust", 23 | ] 24 | resolver = "2" 25 | 26 | [workspace.dependencies] 27 | godot = { version = "0.4.1", features = ["experimental-threads"] } 28 | godot-bevy-macros = { version = "0.9.2", path = "godot-bevy-macros" } 29 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /addons/godot-bevy/bevy_app_singleton.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://bjsfwt816j4tp"] 2 | 3 | [sub_resource type="GDScript" id="GDScript_1"] 4 | script/source = "extends BevyApp 5 | 6 | 7 | # Bulk Transform Optimization Methods 8 | # Automatically detected by godot-bevy library for performance optimization 9 | 10 | func bulk_update_transforms_3d( 11 | instance_ids: PackedInt64Array, 12 | positions: PackedVector3Array, 13 | rotations: PackedVector4Array, 14 | scales: PackedVector3Array 15 | ) -> void: 16 | var rotation: Quaternion = Quaternion() 17 | for i: int in range(instance_ids.size()): 18 | var node: Node3D = instance_from_id(instance_ids[i]) as Node3D 19 | # Trust instance IDs are valid 20 | node.position = positions[i] 21 | # Copy quaternion, avoiding heap allocation 22 | rotation.x = rotations[i].x 23 | rotation.y = rotations[i].y 24 | rotation.z = rotations[i].z 25 | rotation.w = rotations[i].w 26 | node.quaternion = rotation 27 | node.scale = scales[i] 28 | 29 | func bulk_update_transforms_2d( 30 | instance_ids: PackedInt64Array, 31 | positions: PackedVector2Array, 32 | rotations: PackedFloat32Array, 33 | scales: PackedVector2Array 34 | ) -> void: 35 | for i: int in range(instance_ids.size()): 36 | var node: Node2D = instance_from_id(instance_ids[i]) as Node2D 37 | # Trust instance IDs are valid 38 | node.position = positions[i] 39 | node.rotation = rotations[i] 40 | node.scale = scales[i] 41 | " 42 | 43 | [node name="BevyApp" type="BevyApp"] 44 | script = SubResource("GDScript_1") 45 | -------------------------------------------------------------------------------- /addons/godot-bevy/optimized_scene_tree_watcher.gd.uid: -------------------------------------------------------------------------------- 1 | uid://bjqaf5fdwnhf5 2 | -------------------------------------------------------------------------------- /addons/godot-bevy/plugin.cfg: -------------------------------------------------------------------------------- 1 | [plugin] 2 | 3 | name="godot-bevy" 4 | description="Seamlessly integrate Bevy ECS with Godot 4. Provides project scaffolding, BevyApp singleton setup, and development tools." 5 | author="dcvz" 6 | version="0.9.2" 7 | script="plugin.gd" 8 | -------------------------------------------------------------------------------- /addons/godot-bevy/plugin.gd.uid: -------------------------------------------------------------------------------- 1 | uid://d3480j26pxx1a 2 | -------------------------------------------------------------------------------- /addons/godot-bevy/wizard/project_wizard.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends ConfirmationDialog 3 | 4 | signal project_created(project_info: Dictionary) 5 | 6 | @onready var project_name_input: LineEdit = $VBox/ProjectName/LineEdit 7 | @onready var version_input: LineEdit = $VBox/Version/LineEdit 8 | @onready var release_build_check: CheckBox = $VBox/ReleaseBuild 9 | 10 | const DEFAULT_VERSION = "0.9.2" 11 | 12 | func _ready(): 13 | title = "Setup godot-bevy Project" 14 | get_ok_button().text = "Create Project" 15 | get_cancel_button().text = "Cancel" 16 | 17 | # Set defaults 18 | project_name_input.text = "my_game" 19 | version_input.text = DEFAULT_VERSION 20 | 21 | # Connect signals 22 | get_ok_button().pressed.connect(_on_create_pressed) 23 | 24 | # Force proper sizing - known Godot issue workaround 25 | call_deferred("_fix_dialog_size") 26 | 27 | 28 | func _fix_dialog_size(): 29 | # Workaround for Godot's dialog sizing issues 30 | # Reset minimum size to force recalculation 31 | min_size = Vector2.ZERO 32 | size = Vector2.ZERO 33 | # Force layout update 34 | await get_tree().process_frame 35 | # Let dialog calculate proper size 36 | reset_size() 37 | # Set fixed width but keep auto height 38 | size.x = 800 39 | min_size.x = 800 40 | 41 | func _on_create_pressed(): 42 | var info = { 43 | "project_name": project_name_input.text, 44 | "godot_bevy_version": version_input.text, 45 | "release_build": release_build_check.button_pressed 46 | } 47 | 48 | project_created.emit(info) 49 | hide() 50 | -------------------------------------------------------------------------------- /addons/godot-bevy/wizard/project_wizard.gd.uid: -------------------------------------------------------------------------------- 1 | uid://guo1kx7de5ss 2 | -------------------------------------------------------------------------------- /addons/godot-bevy/wizard/project_wizard.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=2 format=3 uid="uid://dqhby7f587fe0"] 2 | 3 | [ext_resource type="Script" uid="uid://guo1kx7de5ss" path="res://addons/godot-bevy/wizard/project_wizard.gd" id="1"] 4 | 5 | [node name="ProjectWizard" type="ConfirmationDialog"] 6 | title = "Setup godot-bevy Project" 7 | initial_position = 2 8 | ok_button_text = "Create Project" 9 | script = ExtResource("1") 10 | 11 | [node name="VBox" type="VBoxContainer" parent="."] 12 | 13 | [node name="Label" type="Label" parent="VBox"] 14 | text = "Configure your godot-bevy project:" 15 | 16 | [node name="HSeparator" type="HSeparator" parent="VBox"] 17 | 18 | [node name="ProjectName" type="HBoxContainer" parent="VBox"] 19 | 20 | [node name="Label" type="Label" parent="VBox/ProjectName"] 21 | custom_minimum_size = Vector2(120, 0) 22 | text = "Project Name:" 23 | 24 | [node name="LineEdit" type="LineEdit" parent="VBox/ProjectName"] 25 | size_flags_horizontal = 3 26 | text = "my_game" 27 | placeholder_text = "Enter project name..." 28 | 29 | [node name="Version" type="HBoxContainer" parent="VBox"] 30 | 31 | [node name="Label" type="Label" parent="VBox/Version"] 32 | custom_minimum_size = Vector2(120, 0) 33 | text = "godot-bevy Version:" 34 | 35 | [node name="LineEdit" type="LineEdit" parent="VBox/Version"] 36 | size_flags_horizontal = 3 37 | text = "0.9" 38 | placeholder_text = "e.g., 0.9" 39 | 40 | [node name="HSeparator2" type="HSeparator" parent="VBox"] 41 | 42 | [node name="ReleaseBuild" type="CheckBox" parent="VBox"] 43 | text = "Configure for release builds" 44 | 45 | [node name="HSeparator3" type="HSeparator" parent="VBox"] 46 | 47 | [node name="PluginNote" type="RichTextLabel" parent="VBox"] 48 | bbcode_enabled = true 49 | text = "[b]Note:[/b] This wizard creates a project with [i]GodotDefaultPlugins[/i] which includes all standard godot-bevy functionality.\n\nAfter generation, you can customize plugin selection in your lib.rs file." 50 | fit_content = true 51 | scroll_active = false 52 | -------------------------------------------------------------------------------- /book/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["David Chavez"] 3 | language = "en" 4 | multilingual = false 5 | src = "src" 6 | title = "The godot-bevy Book 👾" 7 | 8 | [output.html] 9 | git-repository-url = "https://github.com/bytemeadow/godot-bevy" 10 | edit-url-template = "https://github.com/bytemeadow/godot-bevy/edit/main/book/{path}" 11 | fold.enable = true 12 | fold.level = 1 13 | -------------------------------------------------------------------------------- /book/src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | - [Introduction](./introduction.md) 2 | 3 | --- 4 | 5 | - [Getting Started](./getting-started/index.md) 6 | - [Installation](./getting-started/installation.md) 7 | - [Basic Concepts](./getting-started/basic-concepts.md) 8 | - [Plugin System](./getting-started/plugins.md) 9 | - [Examples](./getting-started/examples.md) 10 | 11 | --- 12 | 13 | - [Scene Tree](./scene-tree/index.md) 14 | - [Initialization and Timing](./scene-tree/timing.md) 15 | - [Querying with Node Type Markers](./scene-tree/querying.md) 16 | - [Custom Nodes](./scene-tree/custom-nodes/index.md) 17 | - [Automatic Markers](./scene-tree/custom-nodes/automatic-markers.md) 18 | - [Property Mapping (BevyBundle)](./scene-tree/custom-nodes/property-mapping-with-bevy-bundle.md) 19 | - [Nodes from Components and Bundles](scene-tree/custom-nodes/nodes-from-components-and-bundles.md) 20 | 21 | --- 22 | 23 | - [Transform System](./transforms/index.md) 24 | - [Sync Modes](./transforms/sync-modes.md) 25 | - [Custom Transform Sync](./transforms/custom-sync.md) 26 | 27 | --- 28 | 29 | - [Input Handling](./input/index.md) 30 | - [Bevy vs Godot Input](./input/bevy-vs-godot.md) 31 | - [Signal Handling](./input/signals.md) 32 | 33 | --- 34 | 35 | - [Timing & Schedules](./timing/index.md) 36 | 37 | --- 38 | 39 | - [Threading & Main Thread Access](./threading/index.md) 40 | 41 | --- 42 | 43 | - [Bevy Godot Profiling](./profiling/profiling.md) 44 | 45 | --- 46 | 47 | - [Platform Targets](./platform-targets/index.md) 48 | - [Android](./platform-targets/android.md) 49 | 50 | --- 51 | 52 | - [Migration Guides](./migration/index.md) 53 | - [v0.6 to v0.7](./migration/v0.6-to-v0.7.md) 54 | - [v0.7 to v0.8](./migration/v0.7-to-v0.8.md) 55 | - [v0.8 to v0.9](./migration/v0.8-to-v0.9.md) 56 | -------------------------------------------------------------------------------- /book/src/getting-started/examples.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | Many additional godot-bevy examples are available in the [examples](https://github.com/bytemeadow/godot-bevy/tree/main/examples) directory. Examples are set up as executable binaries. An example can then be executed using the following cargo command line in the root of the godot-bevy repository: 4 | 5 | ``` 6 | cargo run --bin platformer_2d 7 | ``` 8 | 9 | The following additional examples are currently available if you want to check them out: 10 | 11 | 12 | | Example | Description | 13 | | :-------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 14 | | [Dodge the Creeps](https://github.com/bytemeadow/godot-bevy/tree/main/examples/dodge-the-creeps-2d) | Ported example from Godot's tutorial on making a 2D game. 15 | | [Input Event Demo](https://github.com/bytemeadow/godot-bevy/tree/main/examples/input-event-demo) | Showcases the different ways in which you can get input either via Bevy's input API or using Godot's. 16 | | [Platformer 2D](https://github.com/bytemeadow/godot-bevy/tree/main/examples/platformer-2d) | A more complete example showing how to tag Godot nodes for an editor heavy. 17 | | [Simple Node2D Movement](https://github.com/bytemeadow/godot-bevy/tree/main/examples/simple-node2d-movement) | A minimal example with basic movement. 18 | | [Timing Test](https://github.com/bytemeadow/godot-bevy/tree/main/examples/timing-test) | Internal test to measure frames. 19 | -------------------------------------------------------------------------------- /book/src/getting-started/index.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | - [Installation](installation.md) 4 | - [Basic Concepts](basic-concepts.md) 5 | - [Plugin System](plugins.md) 6 | - [Examples](examples.md) 7 | -------------------------------------------------------------------------------- /book/src/input/index.md: -------------------------------------------------------------------------------- 1 | # Input Handling 2 | 3 | - [Bevy vs Godot Input](bevy-vs-godot.md) 4 | - [Signal Handling](signals.md) 5 | -------------------------------------------------------------------------------- /book/src/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Welcome to **godot-bevy**, a Rust library that brings [Bevy's](https://bevyengine.org/) powerful Entity Component System (ECS) to the versatile [Godot Game Engine](https://godotengine.org/). 4 | 5 | ## What is godot-bevy? 6 | 7 | godot-bevy enables you to write high-performance game logic using Bevy's ergonomic ECS within your Godot projects. This is not a Godot plugin for Bevy users, but rather a library for **Godot developers who want to leverage Rust and ECS** for their game logic while keeping Godot's excellent editor and engine features. 8 | 9 | ## Why godot-bevy? 10 | 11 | ### The Best of Both Worlds 12 | 13 | - **Godot's Strengths**: Visual scene editor, node system, asset pipeline, cross-platform deployment 14 | - **Bevy's Strengths**: High-performance ECS, Rust's safety and speed, data-oriented architecture 15 | - **godot-bevy**: Seamless integration between the two, letting you use each tool where it shines 16 | 17 | ### Key Benefits 18 | 19 | 1. **Performance**: Bevy's ECS provides cache-friendly data layouts and parallel system execution 20 | 2. **Safety**: Rust's type system catches bugs at compile time 21 | 3. **Modularity**: ECS encourages clean, decoupled code architecture 22 | 4. **Flexibility**: Mix and match Godot nodes with ECS components as needed 23 | 24 | ## Core Features 25 | 26 | - **Deep ECS Integration**: True Bevy systems controlling Godot nodes 27 | - **Transform Synchronization**: Automatic syncing between Bevy and Godot transforms 28 | - **Signal Handling**: React to Godot signals in your ECS systems 29 | - **Collision Events**: Handle physics collisions through the ECS 30 | - **Resource Management**: Load Godot assets through Bevy's asset system 31 | - **Smart Scheduling**: Separate physics and rendering update rates 32 | 33 | ## Who Should Use godot-bevy? 34 | 35 | This library is ideal for: 36 | 37 | - Godot developers wanting to use Rust for game logic 38 | - Teams looking for better code organization through ECS 39 | - Projects requiring high-performance game systems 40 | - Developers familiar with data-oriented design patterns 41 | 42 | ## Getting Help 43 | 44 | - **Discord**: Join our [community Discord](https://discord.gg/gqkeBsH93H) 45 | - **Documentation**: Check the [API docs](https://docs.rs/godot-bevy/latest/godot_bevy/) 46 | - **Examples**: Browse the [example projects](https://github.com/bytemeadow/godot-bevy/tree/main/examples) 47 | - **Issues**: Report bugs on [GitHub](https://github.com/bytemeadow/godot-bevy/issues) 48 | 49 | ## Ready to Get Started? 50 | 51 | Head to the [Installation](./getting-started/installation.md) chapter to begin your godot-bevy journey! 52 | -------------------------------------------------------------------------------- /book/src/migration/index.md: -------------------------------------------------------------------------------- 1 | # Migration Guides 2 | 3 | This section contains migration guides for various versions. 4 | -------------------------------------------------------------------------------- /book/src/platform-targets/index.md: -------------------------------------------------------------------------------- 1 | # Platform Targets 2 | 3 | Platform-specific setup guides for godot-bevy projects. 4 | 5 | - [Android](./android.md) - Android development setup -------------------------------------------------------------------------------- /book/src/profiling/profiling.md: -------------------------------------------------------------------------------- 1 | # Profiling 2 | 3 | Godot-Bevy, together with Bevy native, supports several methods of profiling. In this article, 4 | we'll discuss using Tracy. We recommend you read [Bevy's profiling doc](https://github.com/bevyengine/bevy/blob/main/docs/profiling.md) first. 5 | 6 | # Instructions 7 | 8 | - In your `Cargo.toml`, under `dependencies` add necessary tracy dependencies, e.g.: 9 | 10 | ```toml 11 | [dependencies] 12 | tracing = "0.1" 13 | tracing-tracy = { version = "0.11.4", default-features = false, features = [ 14 | "enable", 15 | "manual-lifetime", 16 | "ondemand", 17 | "broadcast", # announce presence 18 | ], optional = true } 19 | ``` 20 | 21 | - In your `Cargo.toml`, under `features` add a `trace_tracy` (feel free to rename it): 22 | 23 | ```toml 24 | [features] 25 | trace_tracy = ["dep:tracing-tracy", "godot-bevy/trace_tracy"] 26 | ``` 27 | 28 | - Install Tracy, see 29 | https://github.com/bevyengine/bevy/blob/main/docs/profiling.md for details on 30 | picking the correct version to install. As of July 2025, you need Tracy 31 | Profiler `0.12.2`, which you can obtain from [The official 32 | site](https://github.com/wolfpld/tracy). Alternatively, you can use the 33 | zig-built version, which makes it much easier to build c binaries across 34 | platforms, see https://github.com/allyourcodebase/tracy 35 | - Once built, run the Tracy Profiler (`tracy-profiler`), and hit the `Connect` 36 | button so it's listening/ready to receive real time data from your game 37 | - Build your game. You can use either dev or release, both work, though we 38 | recommend release since you'll still get symbol resolution and your profiling 39 | numbers will reflect what you're actually shipping in addition to being 40 | _much_ faster than a dev build. 41 | - Run your game, you should see real time data streaming into the Tracy 42 | profiler GUI. 43 | - For a complete example of this in action, see our [Bevy Boids 44 | example](https://github.com/bytemeadow/godot-bevy/tree/main/examples/boids-perf-test) 45 | 46 | ## Notes 47 | 48 | If you see the following warning: 49 | 50 | ```rust 51 | warning: unexpected `cfg` condition value: `trace_tracy` 52 | ``` 53 | 54 | after upgrading to Godot Bevy `0.9`, add the following to your Cargo.toml file 55 | 56 | ```toml 57 | [lints.rust.unexpected_cfgs] 58 | level = "warn" 59 | check-cfg = ['cfg(feature, values("trace_tracy"))'] 60 | ``` 61 | -------------------------------------------------------------------------------- /book/src/scene-tree/custom-nodes/automatic-markers.md: -------------------------------------------------------------------------------- 1 | # Automatic Markers 2 | 3 | godot-bevy **automatically** creates marker components for all built-in Godot node types: 4 | 5 | ```rust 6 | // These markers are created automatically: 7 | // Sprite2DMarker, CharacterBody2DMarker, Area2DMarker, etc. 8 | 9 | fn update_sprites(sprites: Query<&GodotNodeHandle, With>) { 10 | // Works automatically for any Sprite2D in your scene 11 | } 12 | ``` 13 | 14 | ### Custom Godot Nodes 15 | 16 | Custom nodes defined in Rust or GDScript **do NOT** receive automatic markers for their custom type, 17 | though they DO inherit markers from their base class (e.g., `Node2DMarker` if they extend Node2D). 18 | This is by design—custom nodes should use the `BevyBundle` macro for explicit component control. 19 | 20 | ```rust 21 | // ❌ PlayerMarker is NOT automatically created 22 | fn update_players(players: Query<&GodotNodeHandle, With>) { 23 | // PlayerMarker doesn't exist unless you create it 24 | } 25 | 26 | // ✅ But you CAN use the base class marker 27 | fn update_player_base(players: Query<&GodotNodeHandle, With>) { 28 | // This works but includes ALL CharacterBody2D nodes, not just Players 29 | } 30 | 31 | // ✅ Use BevyBundle for custom components 32 | #[derive(GodotClass, BevyBundle)] 33 | #[class(base=CharacterBody2D)] 34 | #[bevy_bundle((Player), (Health), (Speed))] 35 | pub struct PlayerNode { 36 | base: Base, 37 | } 38 | ``` 39 | -------------------------------------------------------------------------------- /book/src/scene-tree/custom-nodes/index.md: -------------------------------------------------------------------------------- 1 | # Custom Nodes 2 | 3 | This section explains how to work with custom Godot nodes in godot-bevy and 4 | the important distinction between automatic markers for built-in Godot types versus custom nodes. 5 | 6 | ## Summary 7 | 8 | - Built-in Godot types get automatic markers (e.g., `Sprite2DMarker`) 9 | - Custom nodes do NOT get automatic markers for their type, but DO inherit base class markers 10 | - Use `BevyBundle` to define components for custom nodes 11 | - Prefer semantic components over generic markers 12 | - Combine base class markers with custom components for powerful queries 13 | 14 | This design gives you full control over your ECS architecture while maintaining performance and clarity. 15 | -------------------------------------------------------------------------------- /book/src/scene-tree/index.md: -------------------------------------------------------------------------------- 1 | # Scene Tree 2 | 3 | - [Initialization and Timing](timing.md) 4 | - [Querying with Node Type Markers](querying.md) 5 | - [Custom Nodes](custom-nodes/index.md) -------------------------------------------------------------------------------- /book/src/threading/index.md: -------------------------------------------------------------------------------- 1 | # Thread Safety and Godot APIs 2 | 3 | Some Godot APIs are not thread-safe and and must be called exclusively from the main thread. This creates an important constraint when working with Bevy's multi-threaded ECS, where systems typically run in parallel across multiple threads. For additional details, see [Thread-safe APIs — Godot Engine](https://docs.godotengine.org/en/stable/tutorials/performance/thread_safe_apis.html). 4 | 5 | ## The Main Thread Requirement 6 | 7 | Any system that interacts with Godot APIs—such as calling methods on `Node`, accessing scene tree properties, or manipulating UI elements—must run on the main thread. This includes: 8 | 9 | - Scene tree operations (`add_child`, `queue_free`, etc.) 10 | - Transform modifications on Godot nodes 11 | - UI updates (setting text, visibility, etc.) 12 | - Audio playback controls 13 | - Input handling via Godot's `Input` singleton 14 | - File I/O operations through Godot's resource system 15 | 16 | ## The `#[main_thread_system]` Macro 17 | 18 | The `#[main_thread_system]` attribute macro provides a clean way to mark systems that require main thread execution: 19 | 20 | ```rust 21 | use godot_bevy::prelude::*; 22 | 23 | #[main_thread_system] 24 | fn update_ui_labels( 25 | mut query: Query<&mut GodotNodeHandle, With>, 26 | stats: Res, 27 | ) { 28 | for mut handle in query.iter_mut() { 29 | if let Some(mut label) = handle.try_get::