use lyra_ecs::{query::Entities, relation::{ChildOf, RelationOriginComponent}, Bundle, Entity}; use lyra_reflect::Reflect; use crate::{SceneGraph, lyra_engine}; /// A node inside of the Scene #[derive(Clone, PartialEq, Eq, Reflect)] pub struct SceneNode { #[reflect(skip)] parent: Option, #[reflect(skip)] entity: Entity } impl SceneNode { pub fn new(parent: Option, entity: Entity) -> Self { Self { parent, entity, } } /// If this node has a parent, retrieves the parent node from the SceneGraph. pub fn parent(&self, graph: &SceneGraph) -> Option { if let Some(parent) = self.parent { let v = graph.world.view_one::<&RelationOriginComponent>(parent); let p_parent = if let Some(pp) = v.get() { Some(pp.target()) } else { None }; Some(SceneNode::new(p_parent, parent)) } else { None } } pub fn parent_entity(&self) -> Option { self.parent } pub fn children(&self, graph: &SceneGraph) -> Vec { let v = graph.world.view::() .relates_to::(self.entity); v.into_iter().map(|(e, _)| SceneNode::new(Some(self.entity), e)).collect() } pub fn entity(&self) -> Entity { self.entity } /// Add a child node to this node. /// /// The spawned entity backing the scene node will have a `ChildOf` relation targeting /// the provided parent node, the `SceneNodeFlag` component is also added to the entity. pub fn add_node(&self, graph: &mut SceneGraph, bundle: B) -> SceneNode { graph.add_node_under(self, bundle) } } #[cfg(test)] mod tests { use lyra_ecs::{query::{filter::{Has, Not}, Entities}, relation::{ChildOf, RelationOriginComponent}}; use lyra_math::{Transform, Vec3}; use crate::{tests::FakeMesh, WorldTransform, SceneGraph}; #[test] fn node_world_transform() { let mut scene = SceneGraph::new(); let a = scene.add_node((WorldTransform::default(), Transform::from_translation(Vec3::new(10.0, 10.0, 10.0)), FakeMesh)); assert!(a.parent(&scene).unwrap() == scene.root_node); let b = a.add_node(&mut scene, (WorldTransform::default(), Transform::from_translation(Vec3::new(50.0, 50.0, 50.0)), FakeMesh)); assert!(b.parent(&scene).unwrap() == a); // update global transforms let view = scene.world.view::<(Entities, &mut WorldTransform, &Transform, Not>>)>(); crate::system_update_world_transforms(&scene.world, view).unwrap(); let tran = scene.world.view_one::<&WorldTransform>(b.entity).get().unwrap(); assert_eq!(**tran, Transform::from_translation(Vec3::new(60.0, 60.0, 60.0))); } }