mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
entity archetypes
(for organization and compile time speedups)
This commit is contained in:
parent
7a386b8b46
commit
e0753c8ace
4 changed files with 317 additions and 0 deletions
191
examples/entity_builder_comparison.rs
Normal file
191
examples/entity_builder_comparison.rs
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy::ecs::*;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
AppBuilder::new().add_defaults().setup_world(setup).run();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn create_entities_insert_vec(world: &mut World, plane_handle: Handle<Mesh>, cube_handle: Handle<Mesh>) {
|
||||||
|
// plane
|
||||||
|
world.insert(
|
||||||
|
(),
|
||||||
|
vec![(
|
||||||
|
plane_handle.clone(),
|
||||||
|
Material::new(Albedo::Color(math::vec4(0.1, 0.2, 0.1, 1.0))),
|
||||||
|
LocalToWorld::identity(),
|
||||||
|
Translation::new(0.0, 0.0, 0.0),
|
||||||
|
)],
|
||||||
|
);
|
||||||
|
|
||||||
|
// cube
|
||||||
|
world.insert(
|
||||||
|
(),
|
||||||
|
vec![(
|
||||||
|
cube_handle,
|
||||||
|
Material::new(Albedo::Color(math::vec4(0.5, 0.3, 0.3, 1.0))),
|
||||||
|
LocalToWorld::identity(),
|
||||||
|
Translation::new(0.0, 0.0, 1.0),
|
||||||
|
)],
|
||||||
|
);
|
||||||
|
|
||||||
|
// light
|
||||||
|
world.insert(
|
||||||
|
(),
|
||||||
|
vec![(
|
||||||
|
Light {
|
||||||
|
color: wgpu::Color {
|
||||||
|
r: 0.8,
|
||||||
|
g: 0.8,
|
||||||
|
b: 0.5,
|
||||||
|
a: 1.0,
|
||||||
|
},
|
||||||
|
fov: f32::to_radians(60.0),
|
||||||
|
depth: 0.1..50.0,
|
||||||
|
target_view: None,
|
||||||
|
},
|
||||||
|
LocalToWorld::identity(),
|
||||||
|
Translation::new(4.0, -4.0, 5.0),
|
||||||
|
Rotation::from_euler_angles(0.0, 0.0, 0.0),
|
||||||
|
)],
|
||||||
|
);
|
||||||
|
|
||||||
|
// camera
|
||||||
|
world.insert(
|
||||||
|
(),
|
||||||
|
vec![(
|
||||||
|
Camera::new(CameraType::Projection {
|
||||||
|
fov: std::f32::consts::PI / 4.0,
|
||||||
|
near: 1.0,
|
||||||
|
far: 1000.0,
|
||||||
|
aspect_ratio: 1.0,
|
||||||
|
}),
|
||||||
|
ActiveCamera,
|
||||||
|
LocalToWorld(Mat4::look_at_rh(
|
||||||
|
Vec3::new(3.0, 8.0, 5.0),
|
||||||
|
Vec3::new(0.0, 0.0, 0.0),
|
||||||
|
Vec3::new(0.0, 0.0, 1.0),
|
||||||
|
)),
|
||||||
|
)],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn create_entities_builder_add_component(world: &mut World, plane_handle: Handle<Mesh>, cube_handle: Handle<Mesh>) {
|
||||||
|
world.build()
|
||||||
|
// plane
|
||||||
|
.build_entity()
|
||||||
|
.add(plane_handle.clone())
|
||||||
|
.add(Material::new(Albedo::Color(math::vec4(0.1, 0.2, 0.1, 1.0))))
|
||||||
|
.add(LocalToWorld::identity())
|
||||||
|
.add(Translation::new(0.0, 0.0, 0.0))
|
||||||
|
// cube
|
||||||
|
.build_entity()
|
||||||
|
.add(cube_handle)
|
||||||
|
.add(Material::new(Albedo::Color(math::vec4(0.5, 0.3, 0.3, 1.0))))
|
||||||
|
.add(LocalToWorld::identity())
|
||||||
|
.add(Translation::new(0.0, 0.0, 1.0))
|
||||||
|
// light
|
||||||
|
.build_entity()
|
||||||
|
.add(Light {
|
||||||
|
color: wgpu::Color {
|
||||||
|
r: 0.8,
|
||||||
|
g: 0.8,
|
||||||
|
b: 0.5,
|
||||||
|
a: 1.0,
|
||||||
|
},
|
||||||
|
fov: f32::to_radians(60.0),
|
||||||
|
depth: 0.1..50.0,
|
||||||
|
target_view: None,
|
||||||
|
})
|
||||||
|
.add(LocalToWorld::identity())
|
||||||
|
.add(Translation::new(4.0, -4.0, 5.0))
|
||||||
|
.add(Rotation::from_euler_angles(0.0, 0.0, 0.0))
|
||||||
|
// camera
|
||||||
|
.build_entity()
|
||||||
|
.add(Camera::new(CameraType::Projection {
|
||||||
|
fov: std::f32::consts::PI / 4.0,
|
||||||
|
near: 1.0,
|
||||||
|
far: 1000.0,
|
||||||
|
aspect_ratio: 1.0,
|
||||||
|
}))
|
||||||
|
.add(ActiveCamera)
|
||||||
|
.add(LocalToWorld(Mat4::look_at_rh(
|
||||||
|
Vec3::new(3.0, 8.0, 5.0),
|
||||||
|
Vec3::new(0.0, 0.0, 0.0),
|
||||||
|
Vec3::new(0.0, 0.0, 1.0),
|
||||||
|
)))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_entities_builder_archetype(world: &mut World, plane_handle: Handle<Mesh>, cube_handle: Handle<Mesh>) {
|
||||||
|
world.build()
|
||||||
|
// plane
|
||||||
|
.build_archetype(Object3dEntity {
|
||||||
|
mesh: plane_handle.clone(),
|
||||||
|
material: Material::new(Albedo::Color(math::vec4(0.1, 0.2, 0.1, 1.0))),
|
||||||
|
local_to_world: LocalToWorld::identity(),
|
||||||
|
translation: Translation::new(0.0, 0.0, 0.0),
|
||||||
|
})
|
||||||
|
// cube
|
||||||
|
.build_archetype(Object3dEntity {
|
||||||
|
mesh: cube_handle,
|
||||||
|
material: Material::new(Albedo::Color(math::vec4(0.5, 0.3, 0.3, 1.0))),
|
||||||
|
local_to_world: LocalToWorld::identity(),
|
||||||
|
translation: Translation::new(0.0, 0.0, 1.0),
|
||||||
|
})
|
||||||
|
// light
|
||||||
|
.build_archetype(LightEntity {
|
||||||
|
light: Light {
|
||||||
|
color: wgpu::Color {
|
||||||
|
r: 0.8,
|
||||||
|
g: 0.8,
|
||||||
|
b: 0.5,
|
||||||
|
a: 1.0,
|
||||||
|
},
|
||||||
|
fov: f32::to_radians(60.0),
|
||||||
|
depth: 0.1..50.0,
|
||||||
|
target_view: None,
|
||||||
|
},
|
||||||
|
local_to_world: LocalToWorld::identity(),
|
||||||
|
translation: Translation::new(4.0, -4.0, 5.0),
|
||||||
|
rotation: Rotation::from_euler_angles(0.0, 0.0, 0.0),
|
||||||
|
})
|
||||||
|
// camera
|
||||||
|
.build_archetype(CameraEntity {
|
||||||
|
camera: Camera::new(CameraType::Projection {
|
||||||
|
fov: std::f32::consts::PI / 4.0,
|
||||||
|
near: 1.0,
|
||||||
|
far: 1000.0,
|
||||||
|
aspect_ratio: 1.0,
|
||||||
|
}),
|
||||||
|
active_camera: ActiveCamera,
|
||||||
|
local_to_world: LocalToWorld(Mat4::look_at_rh(
|
||||||
|
Vec3::new(3.0, 8.0, 5.0),
|
||||||
|
Vec3::new(0.0, 0.0, 0.0),
|
||||||
|
Vec3::new(0.0, 0.0, 1.0),
|
||||||
|
)),
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup(world: &mut World) {
|
||||||
|
let cube = Mesh::load(MeshType::Cube);
|
||||||
|
let plane = Mesh::load(MeshType::Plane { size: 10.0 });
|
||||||
|
|
||||||
|
let (cube_handle, plane_handle) = {
|
||||||
|
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh>>().unwrap();
|
||||||
|
(mesh_storage.add(cube), mesh_storage.add(plane))
|
||||||
|
};
|
||||||
|
|
||||||
|
// no-archetype precompile: 1.24 sec
|
||||||
|
// archetype precompile: 1.07 sec
|
||||||
|
// create_entities_insert_vec(world, plane_handle, cube_handle);
|
||||||
|
|
||||||
|
// no-archetype precompile: .93
|
||||||
|
// noarchetype precompile: .93
|
||||||
|
// create_entities_builder_add_component(world, plane_handle, cube_handle);
|
||||||
|
|
||||||
|
// archetype precompile: 0.65
|
||||||
|
create_entities_builder_archetype(world, plane_handle, cube_handle);
|
||||||
|
}
|
65
src/ecs/archetypes.rs
Normal file
65
src/ecs/archetypes.rs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
use crate::prelude::*;
|
||||||
|
use legion::prelude::*;
|
||||||
|
|
||||||
|
|
||||||
|
// builder macro that makes defaults easy? Object3dBuilder { Option<Material> } impl Builder for Object3dBuilder { }
|
||||||
|
pub trait EntityArchetype {
|
||||||
|
fn insert(self, world: &mut World) -> Entity;
|
||||||
|
// add_components appears to be missing from World. it will be less efficient without that
|
||||||
|
// fn add_components(self, world: &mut World);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Object3dEntity {
|
||||||
|
pub mesh: Handle<Mesh>,
|
||||||
|
pub material: Material,
|
||||||
|
pub local_to_world: LocalToWorld,
|
||||||
|
pub translation: Translation,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: make this a macro
|
||||||
|
impl EntityArchetype for Object3dEntity {
|
||||||
|
fn insert(self, world: &mut World) -> Entity {
|
||||||
|
*world.insert((), vec![(
|
||||||
|
self.mesh,
|
||||||
|
self.material,
|
||||||
|
self.local_to_world,
|
||||||
|
self.translation,
|
||||||
|
)]).first().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct LightEntity {
|
||||||
|
pub light: Light,
|
||||||
|
pub local_to_world: LocalToWorld,
|
||||||
|
pub translation: Translation,
|
||||||
|
pub rotation: Rotation,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: make this a macro
|
||||||
|
impl EntityArchetype for LightEntity {
|
||||||
|
fn insert(self, world: &mut World) -> Entity {
|
||||||
|
*world.insert((), vec![(
|
||||||
|
self.light,
|
||||||
|
self.local_to_world,
|
||||||
|
self.translation,
|
||||||
|
self.rotation,
|
||||||
|
)]).first().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CameraEntity {
|
||||||
|
pub camera: Camera,
|
||||||
|
pub active_camera: ActiveCamera,
|
||||||
|
pub local_to_world: LocalToWorld,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: make this a macro
|
||||||
|
impl EntityArchetype for CameraEntity {
|
||||||
|
fn insert(self, world: &mut World) -> Entity {
|
||||||
|
*world.insert((), vec![(
|
||||||
|
self.camera,
|
||||||
|
self.active_camera,
|
||||||
|
self.local_to_world,
|
||||||
|
)]).first().unwrap()
|
||||||
|
}
|
||||||
|
}
|
55
src/ecs/entity_builder.rs
Normal file
55
src/ecs/entity_builder.rs
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
use crate::ecs::EntityArchetype;
|
||||||
|
use legion::prelude::*;
|
||||||
|
|
||||||
|
pub trait EntityBuilderSource {
|
||||||
|
fn build(&mut self) -> EntityBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EntityBuilderSource for World {
|
||||||
|
fn build(&mut self) -> EntityBuilder {
|
||||||
|
EntityBuilder {
|
||||||
|
world: self,
|
||||||
|
current_entity: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EntityBuilder<'a> {
|
||||||
|
world: &'a mut World,
|
||||||
|
current_entity: Option<Entity>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> EntityBuilder<'a> {
|
||||||
|
pub fn build_entity(mut self) -> Self {
|
||||||
|
let entity = *self.world.insert((), vec![()]).first().unwrap();
|
||||||
|
self.current_entity = Some(entity);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
pub fn build(self) {}
|
||||||
|
|
||||||
|
// note: this is slow and does a full entity copy
|
||||||
|
pub fn add<T>(self, component: T) -> Self
|
||||||
|
where
|
||||||
|
T: legion::storage::Component,
|
||||||
|
{
|
||||||
|
let _ = self
|
||||||
|
.world
|
||||||
|
.add_component(*self.current_entity.as_ref().unwrap(), component);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tag<T>(self, tag: T) -> Self
|
||||||
|
where
|
||||||
|
T: legion::storage::Tag,
|
||||||
|
{
|
||||||
|
let _ = self
|
||||||
|
.world
|
||||||
|
.add_tag(*self.current_entity.as_ref().unwrap(), tag);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_archetype(mut self, entity_archetype: impl EntityArchetype) -> Self {
|
||||||
|
self.current_entity = Some(entity_archetype.insert(self.world));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,9 @@
|
||||||
|
mod entity_builder;
|
||||||
|
mod archetypes;
|
||||||
|
|
||||||
|
pub use entity_builder::*;
|
||||||
|
pub use archetypes::*;
|
||||||
|
|
||||||
use crate::prelude::{Children, Entity, SubWorld, World};
|
use crate::prelude::{Children, Entity, SubWorld, World};
|
||||||
|
|
||||||
pub fn run_on_hierarchy<T>(
|
pub fn run_on_hierarchy<T>(
|
||||||
|
|
Loading…
Reference in a new issue