mirror of
https://github.com/bevyengine/bevy
synced 2024-09-20 06:22:01 +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};
|
||||
|
||||
pub fn run_on_hierarchy<T>(
|
||||
|
|
Loading…
Reference in a new issue