Entities
Entities are unique identifiers that group components together. An entity is just an ID - it has no data of its own.
Entity Type
#![allow(unused)] fn main() { pub use freecs::Entity; }
Entity is a lightweight handle containing a generation and an index. Generations prevent dangling references - if an entity is despawned and its slot reused, the old Entity handle will no longer match.
Spawning Entities
Basic Spawning
Spawn entities with spawn_entities, specifying component flags and count:
#![allow(unused)] fn main() { let entity = world.spawn_entities( LOCAL_TRANSFORM | GLOBAL_TRANSFORM | RENDER_MESH | MATERIAL_REF, 1, )[0]; }
Then set component values:
#![allow(unused)] fn main() { world.core.set_local_transform(entity, LocalTransform { translation: Vec3::new(0.0, 1.0, 0.0), rotation: Quat::identity(), scale: Vec3::new(1.0, 1.0, 1.0), }); world.core.set_render_mesh(entity, RenderMesh { name: "cube".to_string(), id: None, }); world.core.set_material_ref(entity, MaterialRef::new("Default")); }
Batch Spawning
Spawn multiple entities at once:
#![allow(unused)] fn main() { let entities = world.spawn_entities(LOCAL_TRANSFORM | GLOBAL_TRANSFORM, 100); for (index, entity) in entities.iter().enumerate() { world.core.set_local_transform(*entity, LocalTransform { translation: Vec3::new(index as f32 * 2.0, 0.0, 0.0), ..Default::default() }); } }
Helper Functions
Nightshade provides convenience functions for common entities:
#![allow(unused)] fn main() { // Primitives spawn_cube_at(world, Vec3::new(0.0, 1.0, 0.0)); spawn_sphere_at(world, Vec3::new(2.0, 1.0, 0.0)); spawn_plane_at(world, Vec3::zeros()); spawn_cylinder_at(world, Vec3::new(4.0, 1.0, 0.0)); spawn_cone_at(world, Vec3::new(6.0, 1.0, 0.0)); spawn_torus_at(world, Vec3::new(8.0, 1.0, 0.0)); // Camera let camera = spawn_camera(world, Vec3::new(0.0, 5.0, 10.0), "Main Camera".to_string()); world.resources.active_camera = Some(camera); // Sun light let sun = spawn_sun(world); // First-person player with character controller let (player_entity, camera_entity) = spawn_first_person_player(world, Vec3::new(0.0, 2.0, 0.0)); }
Loading Models
Load glTF/GLB models:
#![allow(unused)] fn main() { use nightshade::ecs::prefab::*; let model_bytes = include_bytes!("../assets/character.glb"); let result = import_gltf_from_bytes(model_bytes)?; for (name, (rgba_data, width, height)) in result.textures { world.queue_command(WorldCommand::LoadTexture { name, rgba_data, width, height, }); } for (name, mesh) in result.meshes { mesh_cache_insert(&mut world.resources.mesh_cache, name, mesh); } for prefab in result.prefabs { spawn_prefab_with_animations( world, &prefab, &result.animations, Vec3::new(0.0, 0.0, 0.0), ); } }
Despawning Entities
#![allow(unused)] fn main() { // Despawn specific entities world.despawn_entities(&[entity]); // Despawn entity and all children recursively despawn_recursive_immediate(world, entity); // Deferred despawn via command queue world.queue_command(WorldCommand::DespawnRecursive { entity }); }
Adding Components After Spawn
Add component flags to an existing entity with add_components:
#![allow(unused)] fn main() { world.core.add_components(entity, AUDIO_SOURCE); world.core.set_audio_source(entity, AudioSource::new("music").playing()); world.core.add_components(camera, AUDIO_LISTENER); world.core.set_audio_listener(camera, AudioListener); }
This is useful when you need to augment entities created by helper functions (like spawn_cube_at) with additional components.
Checking Components
#![allow(unused)] fn main() { if world.core.entity_has_components(entity, RENDER_MESH) { // Entity has a mesh } if world.core.entity_has_components(entity, ANIMATION_PLAYER | SKIN) { // Entity is an animated skinned model } }
Parent-Child Relationships
Spawn an entity as a child of another:
#![allow(unused)] fn main() { let parent = world.spawn_entities(LOCAL_TRANSFORM | GLOBAL_TRANSFORM, 1)[0]; let child = world.spawn_entities(LOCAL_TRANSFORM | GLOBAL_TRANSFORM | PARENT, 1)[0]; world.core.set_parent(child, Parent(Some(parent))); world.core.set_local_transform(child, LocalTransform { translation: Vec3::new(0.0, 1.0, 0.0), ..Default::default() }); }
See Transform Hierarchy for details on parent-child transforms.