use bevy hierarchy system

This commit is contained in:
TotallyNot 2025-11-03 18:54:07 +01:00
parent 35413b563c
commit cfe2631578
Signed by: pyrite
GPG key ID: 7F1BA9170CD35D15
15 changed files with 246 additions and 643 deletions

View file

@ -1,6 +1,6 @@
use std::borrow::Cow;
use bevy_ecs::{entity::Entity, world::World};
use bevy_ecs::{prelude::*, relationship::RelatedSpawner};
use strum::Display;
use crate::{
@ -186,8 +186,8 @@ impl ArmourDto {
.collect()
}
pub fn spawn(self, world: &mut World) -> Entity {
let mut commands = world.spawn(draw_id());
pub fn spawn(self, spawner: &mut RelatedSpawner<'_, ChildOf>) -> Entity {
let mut commands = spawner.spawn(draw_id());
commands.insert((
Name(self.name.to_string()),

View file

@ -52,19 +52,6 @@ pub struct PlayerDto {
impl PlayerDto {
pub fn spawn(self, world: &mut World) -> EntityWorldMut<'_> {
let primary = self.weapons.primary.map(|p| p.spawn(world));
let secondary = self.weapons.secondary.map(|s| s.spawn(world));
let melee = self.weapons.melee.map(|m| m.spawn(world));
let temporary = self.weapons.temporary.map(|m| m.spawn(world));
let fists = WeaponDto::FISTS.spawn(world);
let kick = WeaponDto::KITCHEN_KNIFE.spawn(world);
let head = self.armour.helmet.map(|a| a.spawn(world));
let torso = self.armour.body.map(|a| a.spawn(world));
let legs = self.armour.pants.map(|a| a.spawn(world));
let hands = self.armour.gloves.map(|a| a.spawn(world));
let feet = self.armour.boots.map(|a| a.spawn(world));
let mut commands = world.spawn(draw_id());
commands.insert((
@ -85,22 +72,48 @@ impl PlayerDto {
faction,
});
commands.insert(Weapons {
primary,
secondary,
melee,
temporary,
kick,
fists,
let mut weapons = None;
commands.with_children(|spawner| {
let primary = self.weapons.primary.map(|p| p.spawn(spawner));
let secondary = self.weapons.secondary.map(|s| s.spawn(spawner));
let melee = self.weapons.melee.map(|m| m.spawn(spawner));
let temporary = self.weapons.temporary.map(|m| m.spawn(spawner));
let fists = WeaponDto::FISTS.spawn(spawner);
let kick = WeaponDto::KICK.spawn(spawner);
weapons = Some(Weapons {
primary,
secondary,
melee,
temporary,
kick,
fists,
});
});
if let Some(weapons) = weapons {
commands.insert(weapons);
}
let mut armour = None;
commands.with_children(|spawner| {
let head = self.armour.helmet.map(|a| a.spawn(spawner));
let torso = self.armour.body.map(|a| a.spawn(spawner));
let legs = self.armour.pants.map(|a| a.spawn(spawner));
let hands = self.armour.gloves.map(|a| a.spawn(spawner));
let feet = self.armour.boots.map(|a| a.spawn(spawner));
armour = Some(PlayerArmour {
torso,
head,
legs,
feet,
hands,
})
});
commands.insert(PlayerArmour {
torso,
head,
legs,
feet,
hands,
});
if let Some(armour) = armour {
commands.insert(armour);
}
commands
}

View file

@ -1,6 +1,6 @@
use std::borrow::Cow;
use bevy_ecs::prelude::*;
use bevy_ecs::{prelude::*, relationship::RelatedSpawner};
use crate::{
bundle::{
@ -252,8 +252,8 @@ impl WeaponDto {
})
}
pub fn spawn(self, world: &mut World) -> Entity {
let mut commands = world.spawn(draw_id());
pub fn spawn(self, spawner: &mut RelatedSpawner<'_, ChildOf>) -> Entity {
let mut commands = spawner.spawn(draw_id());
let verb = match self.kind {
WeaponSlot::Primary | WeaponSlot::Secondary => WeaponVerb::Fired,

View file

@ -1,178 +0,0 @@
use bevy_ecs::{
prelude::*,
system::{Command, EntityCommands},
};
#[derive(Component, Debug, Clone, Copy)]
pub struct Parent(Entity);
impl Parent {
pub fn get(&self) -> Entity {
self.0
}
}
#[derive(Component, Debug, Clone, Default)]
pub struct Children(Vec<Entity>);
impl Children {
pub fn get(&self) -> &[Entity] {
&self.0
}
}
struct AddChild {
parent: Entity,
child: Entity,
}
impl Command for AddChild {
fn apply(self, world: &mut World) {
let mut parent = world.entity_mut(self.parent);
if let Some(mut children) = parent.get_mut::<Children>() {
children.0.push(self.child);
} else {
parent.insert(Children(vec![self.child]));
}
}
}
struct AddChildren {
parent: Entity,
children: Vec<Entity>,
}
impl Command for AddChildren {
fn apply(mut self, world: &mut World) {
let mut parent = world.entity_mut(self.parent);
if let Some(mut children) = parent.get_mut::<Children>() {
children.0.append(&mut self.children);
} else {
parent.insert(Children(self.children));
}
}
}
struct RemoveChild {
parent: Entity,
child: Entity,
}
impl Command for RemoveChild {
fn apply(self, world: &mut World) {
let mut parent = world.entity_mut(self.parent);
let mut children = parent
.get_mut::<Children>()
.expect("Parent component has no children");
children.0.retain(|child| *child != self.child);
}
}
pub trait HierarchyBuilder {
fn add_child(&mut self, child: Entity) -> &mut Self;
fn add_children(&mut self, children: impl AsRef<[Entity]>) -> &mut Self;
fn remove_child(&mut self, child: Entity) -> &mut Self;
fn set_parent(&mut self, parent: Entity) -> &mut Self;
}
impl<'a> HierarchyBuilder for EntityCommands<'a> {
fn add_child(&mut self, child: Entity) -> &mut Self {
let parent = self.id();
self.commands().queue(AddChild { parent, child });
self.commands().entity(child).insert(Parent(parent));
self
}
fn add_children(&mut self, children: impl AsRef<[Entity]>) -> &mut Self {
let children = children.as_ref();
let parent = self.id();
self.commands().queue(AddChildren {
parent,
children: children.to_owned(),
});
self.commands().insert_batch(
children
.iter()
.map(|e| (*e, Parent(parent)))
.collect::<Vec<_>>(),
);
self
}
fn remove_child(&mut self, child: Entity) -> &mut Self {
let parent = self.id();
self.commands().queue(RemoveChild { parent, child });
self.commands().entity(child).remove::<Parent>();
self
}
fn set_parent(&mut self, parent: Entity) -> &mut Self {
let child = self.id();
self.commands().queue(AddChild { parent, child });
self.commands().entity(child).insert(Parent(parent));
self
}
}
impl<'w> HierarchyBuilder for EntityWorldMut<'w> {
fn add_child(&mut self, child: Entity) -> &mut Self {
let parent_id = self.id();
unsafe {
self.world_mut()
.entity_mut(child)
.insert(Parent(parent_id))
.update_location();
}
if let Some(mut children) = self.get_mut::<Children>() {
children.0.push(child);
self
} else {
self.insert(Children(vec![child]))
}
}
fn add_children(&mut self, children: impl AsRef<[Entity]>) -> &mut Self {
let parent_id = self.id();
unsafe {
for child in children.as_ref() {
self.world_mut()
.entity_mut(*child)
.insert(Parent(parent_id))
.update_location();
}
}
if let Some(mut old_children) = self.get_mut::<Children>() {
old_children.0.append(&mut children.as_ref().to_owned());
self
} else {
self.insert(Children(children.as_ref().to_owned()))
}
}
fn remove_child(&mut self, child: Entity) -> &mut Self {
unsafe {
self.world_mut()
.entity_mut(child)
.remove::<Parent>()
.update_location();
}
if let Some(mut children) = self.get_mut::<Children>() {
children.0.retain(|c| *c != child);
}
self
}
fn set_parent(&mut self, parent: Entity) -> &mut Self {
let child_id = self.id();
unsafe {
self.world_mut()
.entity_mut(parent)
.add_child(child_id)
.update_location()
}
self
}
}

View file

@ -1,3 +1,2 @@
pub mod bundle;
pub mod dto;
// pub mod hierarchy;