Files
g4borg 325e278af1 Scaffold bevy plugin with bevy-0.19 and bevy-upgrade skills
Add plugin skeleton with versioned skill directories, TODO SKILL.md
scaffolds with goals for skill-creator, and copy over bevy-skill-research
reports from spacecraft into docs/workpad/research/.
2026-07-07 17:52:00 +02:00

71 lines
2.9 KiB
Markdown

# Bevy Skill Research: Hierarchy & Relationships
> **Bevy version**: 0.18, with 0.19 notes
> **Date**: 2026-07-07
## ChildOf Replaces Parent (Bevy 0.16+)
- `Parent` renamed to **`ChildOf(pub Entity)`** — "entities with ChildOf are children, not parents"
- `Deref` removed; use **`child_of.parent()`** to get the parent Entity
- `ChildOf` implements `Relationship`; `Children` implements `RelationshipTarget` — they auto-sync via hooks
- Adding `ChildOf(parent)` to child auto-inserts `Children` on parent; removing it auto-updates parent
- Despawning a parent **auto-despawns all descendants** (was `despawn_recursive`, now just `despawn()`)
## Spawning Children
```rust
// Insert ChildOf directly
commands.spawn(ChildOf(parent));
// Inline child on parent
commands.entity(parent).with_child((SpriteBundle::default(), ChildOf(parent)));
// Multiple children via closure
commands.spawn_empty().with_children(|spawner: &mut ChildSpawnerCommands| {
spawner.spawn(MyComponent(255));
let parent = spawner.target_entity(); // was parent_entity()
});
// Add existing entities as children
commands.entity(parent).add_child(child);
commands.entity(parent).add_children(&[child1, child2]);
commands.entity(parent).insert_children(index, &[child1, child2]);
```
## Querying Hierarchy
- **`Children`** derefs to `[Entity]`, implements `IntoIterator`
- Correct iteration: **`for child in &children`** or **`children.into_iter()`**
- Wrong: ~~`children.iter().copied()`~~ — unnecessary, `IntoIterator` yields `Entity` directly
- Methods: `len()`, `is_empty()`, `contains()`, `first()`, `last()`, `sort_by()`
- Query extensions (0.16+): `query.related::<ChildOf>(entity)`, `query.relationship_sources::<Children>(entity)`
## Detaching vs Despawning (0.18 Renames)
| Old name (≤0.17) | New name (0.18+) | Effect |
|-------------------|------------------|--------|
| `remove_children` | **`detach_children`** | Detach only, do NOT despawn |
| `clear_children` | **`detach_all_children`** | Detach all, do NOT despawn |
| `remove_child` | **`detach_child`** | Detach one, do NOT despawn |
To actually despawn children: `despawn_related::<Children>()`
## Transform Propagation
- `GlobalTransform` is auto-propagated through `ChildOf` hierarchy
- Child `Transform` is relative to parent; `GlobalTransform` is computed world-space
- Propagation runs in **`PostUpdate`** — reading `GlobalTransform` in `Update` gives stale (last-frame) values
## Common Mistakes
| Mistake | Correct |
|---------|---------|
| `Parent` component | `ChildOf(entity)` |
| `children.iter().copied()` | `children.into_iter()` or `for child in &children` |
| `*child_of` (deref) | `child_of.parent()` |
| `despawn_recursive()` | `despawn()` (auto-recursive now) |
| `parent_entity()` in spawner | `target_entity()` |
| `clear_children()` | `detach_all_children()` (0.18+) |
| `remove_children()` | `detach_children()` (0.18+) |
| Reading GlobalTransform in Update | Read in PostUpdate, or accept one-frame lag |