Nodes from Components and Bundles
Often, we want to make Godot nodes from Rust ECS types. The GodotNode
derive macro supports two types:
- Component:
#[derive(Component, GodotNode)]
- Bundle:
#[derive(Bundle, GodotNode)]
Both generate a Godot class you can place in the editor and auto‑insert the corresponding ECS data when the scene is scanned.
See the GodotNode
Rust docs for full syntax and options:
https://docs.rs/godot-bevy/latest/godot_bevy/prelude/derive.GodotNode.html
.
Configuring the Node
You can configure the Godot node's base type and class name with the godot_node
struct-level attribute:
#![allow(unused)] fn main() { #[derive(GodotNode, ...)] #[godot_node(base(Area2D), class_name(Gem2D))] pub struct Gem; }
Component + GodotNode → Node
Use the following method to create a Godot node from a single component. Use when you want to expose a single component to the editor.
Gem marker component:
#![allow(unused)] fn main() { #[derive(Component, GodotNode, Default, Debug, Clone)] #[godot_node(base(Area2D), class_name(Gem2D))] pub struct Gem; }
Door with an exported property:
#![allow(unused)] fn main() { #[derive(Component, GodotNode, Default, Debug, Clone)] #[godot_node(base(Area2D), class_name(Door2D))] pub struct Door { #[godot_export(default(LevelId::Level1))] pub level_id: LevelId, } }
Each derive generates a corresponding Godot class (e.g., Gem2D
, Door2D
) and inserts the component when the node is discovered. Fields marked with #[godot_export]
become Godot editor properties.
Bundle + GodotNode → Node
Sometimes a single component isn’t the right abstraction for your editor node. When you want one node to represent an entity with multiple components, derive on a Bevy Bundle
:
#![allow(unused)] fn main() { #[derive(Bundle, GodotNode)] #[godot_node(base(CharacterBody2D), class_name(Player2D))] pub struct PlayerBundle { // Inserted as Default::default(), no Godot properties pub player: Player, // Tuple/newtype → property name is the bundle field name #[export_fields(value(export_type(f32), default(250.0)))] pub speed: Speed, #[export_fields(value(export_type(f32), default(-400.0)))] pub jump_velocity: JumpVelocity, // Custom default pulled from ProjectSettings #[export_fields(value(export_type(f32), default(godot::classes::ProjectSettings::singleton() .get_setting("physics/2d/default_gravity") .try_to::<f32>() .unwrap_or(980.0))))] pub gravity: Gravity, } }
What #[export_fields]
does:
- Selects which component data is exported to the Godot editor
- Sets the Godot property type with
export_type(Type)
- Optionally provides a default with
default(expr)
- Optionally converts Godot → Bevy with
transform_with(path::to::fn)
when building the bundle
Property naming rules:
- Struct field entries export using the Bevy field name
- Tuple/newtype entry (value(...)) exports using the bundle field name
- Renaming is not supported; duplicate property names across the bundle are a compile error
Construction rules:
- Components without
#[export_fields]
are constructed withDefault::default()
- For struct components, only the exported fields are set; the rest come from
..Default::default()
- Nested bundles are allowed and will be flattened by Bevy on insertion; only top‑level fields can export properties
This derive generates a Godot class (Player2D
above) and an autosync registration so the bundle is inserted automatically for matching nodes.