pub struct WorldRef<'a> { /* private fields */ }
Implementations§
Source§impl<'a> WorldRef<'a>
impl<'a> WorldRef<'a>
pub fn real_world(&self) -> WorldRef<'a>
Sourcepub unsafe fn from_ptr(raw_world: *mut ecs_world_t) -> Self
pub unsafe fn from_ptr(raw_world: *mut ecs_world_t) -> Self
§Safety
Caller must ensure raw_world
points to a valid sys::ecs_world_t
Examples found in repository?
36extern "C" fn callback_group_create(
37 world: *mut sys::ecs_world_t,
38 group_id: u64,
39 _group_by_ctx: *mut c_void,
40) -> *mut c_void {
41 let world_ref = unsafe { WorldRef::from_ptr(world) };
42 println!(
43 "Group created: {:?}",
44 world_ref.world().entity_from_id(group_id).name()
45 );
46
47 println!();
48
49 let mut counter = GROUP_COUNTER.lock().unwrap();
50 *counter += 1;
51
52 // Return data that will be associated with the group
53 let ctx = Box::new(GroupCtx { counter: *counter });
54
55 Box::into_raw(ctx) as *mut std::ffi::c_void // Cast to make sure function type matches
56}
57
58// callbacks need to be extern "C" to be callable from C
59extern "C" fn callback_group_delete(
60 world: *mut sys::ecs_world_t,
61 group_id: u64,
62 _ctx: *mut c_void,
63 _group_by_ctx: *mut c_void,
64) {
65 let world_ref = unsafe { WorldRef::from_ptr(world) };
66 println!(
67 "Group deleted: {:?}",
68 world_ref.world().entity_from_id(group_id).name()
69 );
70
71 // if you have any data associated with the group, you need to free it
72 // or use the callback group_by_ctx where you pass a context to the callback
73}
More examples
29extern "C" fn callback_group_by_relationship(
30 world: *mut sys::ecs_world_t,
31 table: *mut sys::ecs_table_t,
32 id: u64,
33 _group_by_ctx: *mut c_void,
34) -> u64 {
35 // Use sys::ecs_search to find the target for the relationship in the table
36 let mut match_id: sys::ecs_id_t = Default::default();
37 let world = unsafe { WorldRef::from_ptr(world) };
38 let id = IdView::new_from(world, (id, flecs::Wildcard::ID)).id();
39 if unsafe { sys::ecs_search(world.world_ptr_mut(), table, *id, &mut match_id) } != -1 {
40 *IdView::new_from(world, match_id).second_id().id() // First, Second or Third
41 } else {
42 0
43 }
44}
Methods from Deref<Target = World>§
Sourcepub fn info(&self) -> WorldInfo
pub fn info(&self) -> WorldInfo
Get the world’s info. See sys::WorldInfo
for what information you can retrieve.
§Example
use flecs_ecs::prelude::*;
let world = World::new();
world.progress();
let world_info = world.info();
assert!(world_info.delta_time > 0.0);
//assert!(world_info.world_time_total_raw > 0.0); //BUG TODO
//assert!(world_info.systems_ran_frame == 0);
§See also
- C++ API:
world::get_info
Sourcepub fn quit(&self)
pub fn quit(&self)
Signals the application to quit.
After calling this function, the next call to World::progress()
returns false.
§Example
use flecs_ecs::prelude::*;
let world = World::new();
let mut count = 0;
while world.progress() {
count += 1;
if count == 5 {
world.quit();
}
}
assert!(count == 5);
§See also
World::should_quit()
- C++ API:
world::quit
Sourcepub fn should_quit(&self) -> bool
pub fn should_quit(&self) -> bool
Tests if World::quit()
has been called.
§Returns
True if quit has been called, false otherwise.
§Example
use flecs_ecs::prelude::*;
let world = World::new();
assert!(!world.should_quit());
world.quit();
assert!(world.should_quit());
§See also
World::quit()
- C++ API:
world::should_quit
Sourcepub fn on_destroyed(&self, action: ecs_fini_action_t, ctx: *mut c_void)
pub fn on_destroyed(&self, action: ecs_fini_action_t, ctx: *mut c_void)
Sourcepub fn frame_begin(&self, delta_time: f32) -> f32
pub fn frame_begin(&self, delta_time: f32) -> f32
Begins a frame.
When an application does not use World::progress()
to control the main loop, it
can still use Flecs features such as FPS limiting and time measurements processed.
Calls to World::frame_begin
must always be followed by World::frame_end
.
The function accepts a delta_time
parameter, which will get passed to
systems. This value is also used to compute the amount of time the
function needs to sleep to ensure it does not exceed the target_fps
, when
it is set. When 0 is provided for delta_time
, the time will be measured.
§Safety
This function should only be ran from the main thread.
§Arguments
delta_time
: Time elapsed since the last frame.
§Returns
The provided delta_time
, or the measured time if 0 was provided.
§Example
use flecs_ecs::prelude::*;
#[derive(Component)]
struct Position {
x: f32,
y: f32,
}
let world = World::new();
let delta_time = 1.0 / 60.0; // 60 FPS
let entity = world.entity().set(Position { x: 5.0, y: 0.0 });
let sys = world.system::<&Position>().each(|pos| {});
let world_info = world.info();
assert!(world_info.systems_ran_frame == 0);
let delta_time_measured = world.frame_begin(0.0);
world.frame_end();
//TODO
//assert!(world_info.systems_ran_frame == 1);
§See also
World::frame_end()
- C++ API:
world::frame_begin
Sourcepub fn frame_end(&self)
pub fn frame_end(&self)
Ends a frame.
This operation must be called at the end of the frame, and always after
World::frame_begin()
.
§Safety
The function should only be run from the main thread.
§See also
World::frame_begin()
- C++ API:
world::frame_end
Sourcepub fn readonly_begin(&self, multi_threaded: bool) -> bool
pub fn readonly_begin(&self, multi_threaded: bool) -> bool
Begin readonly mode.
When an application does not use World::progress()
to control the main loop,
it can still use Flecs features such as the defer queue. To stage changes, this function
must be called after World::frame_begin()
.
A call to World::readonly_begin()
must be followed by a call to
World::readonly_end()
.
When staging is enabled, modifications to entities are stored to a stage.
This ensures that arrays are not modified while iterating. Modifications are
merged back to the “main stage” when World::readonly_end()
is invoked.
While the world is in staging mode, no structural changes (add/remove/…) can
be made to the world itself. Operations must be executed on a stage instead
(see World::stage()
).
Readonly mode is a stronger version of deferred mode. In deferred mode, ECS operations such as add/remove/set/delete etc. are added to a command queue to be executed later. In readonly mode, operations that could break scheduler logic (such as creating systems, queries) are also disallowed.
Readonly mode itself has a single-threaded and a multi-threaded mode. In single-threaded mode certain mutations on the world are still allowed, for example:
- Entity liveliness operations (such as new,
make_alive
), so that systems are able to create new entities. - Implicit component registration, so that this works from systems.
- Mutations to supporting data structures for the evaluation of uncached queries, so that these can be created on the fly.
These mutations are safe in single-threaded applications, but for multi-threaded applications, the world needs to be entirely immutable. For this purpose, multi-threaded readonly mode exists, which disallows all mutations on the world.
While in readonly mode, applications can still enqueue ECS operations on a
stage. Stages are managed automatically when using the pipeline addon and
World::progress()
, but they can also be configured manually.
Number of stages typically corresponds with number of threads
When an attempt is made to perform an operation on a world in readonly mode, the code will throw an assert saying that the world is in readonly mode.
A call to readonly_begin
must be followed up with readonly_end()
.
When readonly_end()
is called, all enqueued commands from configured
stages are merged back into the world. Calls to readonly_begin()
and
readonly_end()
should always happen from a context where the code has
exclusive access to the world. The functions themselves are not thread safe.
§Safety
This function should only be run from the main thread.
§Returns
Whether the world is currently staged and whether it is in readonly mode.
§Example
use flecs_ecs::prelude::*;
#[derive(Component)]
struct Position { x: i32, y: i32 }
let world = World::new();
let stage = world.stage(0);
world.readonly_begin(false);
assert_eq!(stage.count::<Position>(), 0);
world.readonly_end();
world.readonly_begin(false);
stage.entity().set(Position { x: 10, y: 20 });
stage.entity().set(Position { x: 10, y: 20 });
assert_eq!(stage.count::<Position>(), 0);
world.readonly_end();
assert_eq!(stage.count::<Position>(), 2);
§See also
World::readonly_end()
- C++ API:
world::readonly_begin
Sourcepub fn readonly_end(&self)
pub fn readonly_end(&self)
End readonly mode.
Leaves staging mode. After this operation, the world may be directly mutated again. By default, this operation also merges data back into the world, unless auto-merging was disabled explicitly.
§Safety
This function should only be run from the main thread.
§Returns
Whether the world is currently staged.
§Example
§See also
World::is_readonly()
World::readonly_begin()
- C++ API:
world::readonly_end
Sourcepub fn is_readonly(&self) -> bool
pub fn is_readonly(&self) -> bool
Test whether the current world object is readonly.
This function allows the code to test whether the currently used world object is readonly or whether it allows for writing.
§Returns
True if the world or stage is readonly.
§Example
use flecs_ecs::prelude::*;
let world = World::new();
assert!(!world.is_readonly());
world.readonly_begin(false);
assert!(world.is_readonly());
world.readonly_end();
assert!(!world.is_readonly());
§See also
World::readonly_begin()
World::readonly_end()
- C++ API:
world::is_readonly
Sourcepub fn defer_begin(&self) -> bool
pub fn defer_begin(&self) -> bool
Defers operations until the end of the frame.
When this operation is invoked while iterating, the operations between
World::defer_begin()
and World::defer_end()
are executed at the
end of the frame.
§Safety
This operation is thread safe.
§Returns
Whether the operation was successful.
§Example
use flecs_ecs::prelude::*;
#[derive(Component)]
struct Position {
x: i32,
y: i32,
}
let world = World::new();
world.defer_begin();
let e = world
.entity()
.set(Position { x: 10, y: 20 });
assert!(!e.has::<Position>());
world.defer_end();
assert!(e.has::<Position>());
§See also
World::defer()
World::defer_end()
World::defer_suspend()
World::defer_resume()
World::is_deferred()
- C++ API:
world::defer_begin
Sourcepub fn defer_end(&self) -> bool
pub fn defer_end(&self) -> bool
Ends a block of operations to defer.
This should follow a World::defer_begin()
call.
§Safety
This operation is thread safe.
§Returns
Whether the operation was successful.
§Example
§See also
World::defer()
World::defer_begin()
World::defer_suspend()
World::defer_resume()
World::is_deferred()
- C++ API:
world::defer_end
Sourcepub fn is_deferred(&self) -> bool
pub fn is_deferred(&self) -> bool
Test whether deferring is enabled.
§Returns
Whether deferring is enabled.
§Example
use flecs_ecs::prelude::*;
let world = World::new();
assert!(!world.is_deferred());
world.defer_begin();
assert!(world.is_deferred());
world.defer_end();
assert!(!world.is_deferred());
§See also
World::defer()
World::defer_begin()
World::defer_end()
World::defer_suspend()
World::defer_resume()
- C++ API:
world::is_deferred
Sourcepub fn defer<T>(&self, func: impl FnOnce() -> T) -> T
pub fn defer<T>(&self, func: impl FnOnce() -> T) -> T
Defers all operations executed in the passed-in closure.
§Arguments
func
- The closure to execute.
§Examples
let return_something_if_wanted = world.defer(|| {
// deferred operations here
});
§See also
World::defer_begin()
World::defer_end()
World::defer_suspend()
World::defer_resume()
World::is_deferred()
- C++ API:
world::defer
Sourcepub fn defer_suspend(&self)
pub fn defer_suspend(&self)
Suspends deferring of operations but do flush the queue.
This operation can be used to do an undeferred operation while not flushing the operations in the queue.
An application should invoke World::defer_resume()
before
World::defer_end()
is called. The operation may only be called
when deferring is enabled.
§See also
World::defer()
World::defer_begin()
World::defer_end()
World::defer_resume()
World::is_deferred()
- C++ API:
world::defer_suspend
Sourcepub fn defer_resume(&self)
pub fn defer_resume(&self)
Resumes deferring of operations.
§See also
World::defer()
World::defer_begin()
World::defer_end()
World::defer_suspend()
World::is_deferred()
- C++ API:
world::defer_resume
Sourcepub fn set_stage_count(&self, stages: i32)
pub fn set_stage_count(&self, stages: i32)
Configure world to have N stages.
This initializes N stages, which allows applications to defer operations to multiple isolated defer queues. This is typically used for applications with multiple threads, where each thread gets its own queue, and commands are merged when threads are synchronized.
Note that World::set_threads()
already creates the appropriate number of stages.
The World::set_stage_count()
operation is useful for applications that want to manage
their own stages and/or threads.
§Arguments
stages
: The number of stages.
§Example
use flecs_ecs::prelude::*;
let world = World::new();
world.set_stage_count(2);
world.readonly_begin(false);
let stage1 = world.stage(0);
let e1 = stage1.entity_named("e1");
world.readonly_end();
assert!(e1.id() != 0);
assert_eq!(e1.name(), "e1");
§See also
World::get_stage_count()
World::is_stage()
World::merge()
World::stage()
World::stage_id()
- C++ API:
world::set_stage_count
Sourcepub fn get_stage_count(&self) -> i32
pub fn get_stage_count(&self) -> i32
Get number of configured stages.
Return number of stages set by World::set_stage_count()
.
§Returns
The number of stages used for threading.
§Example
use flecs_ecs::prelude::*;
let world = World::new();
assert_eq!(world.get_stage_count(), 1);
world.set_stage_count(4);
assert_eq!(world.get_stage_count(), 4);
§See also
World::is_stage()
World::merge()
World::set_stage_count()
World::stage()
World::stage_id()
- C++ API:
world::get_stage_count
Sourcepub fn stage_id(&self) -> i32
pub fn stage_id(&self) -> i32
Get current stage id.
The stage id can be used by an application to learn about which stage it is using, which typically corresponds with the worker thread id.
§Returns
The stage id.
§Example
use flecs_ecs::prelude::*;
let world = World::new();
assert_eq!(world.stage_id(), 0);
world.set_stage_count(4);
assert_eq!(world.stage_id(), 0);
let stage = world.stage(3);
assert_eq!(stage.stage_id(), 3);
§See also
World::get_stage_count()
World::is_stage()
World::merge()
World::set_stage_count()
World::stage()
- C++ API:
world::get_stage_id
Sourcepub fn is_stage(&self) -> bool
pub fn is_stage(&self) -> bool
Test if is a stage.
If this function returns false
, it is guaranteed that this is a valid
world object.
§Returns
True if the world is a stage, false if not.
§Example
use flecs_ecs::prelude::*;
let world = World::new();
assert!(!world.is_stage());
let stage = world.stage(0);
assert!(stage.is_stage());
§See also
World::get_stage_count()
World::merge()
World::set_stage_count()
World::stage()
World::stage_id()
- C++ API:
world::is_stage
Sourcepub fn merge(&self)
pub fn merge(&self)
Merge world or stage.
When automatic merging is disabled, an application can call this
operation on either an individual stage, or on the world which will merge
all stages. This operation may only be called when staging is not enabled
(either after World::progress()
or after World::readonly_end()
).
This operation may be called on an already merged stage or world.
§Example
use flecs_ecs::prelude::*;
#[derive(Component)]
struct Position { x: i32, y: i32 }
let world = World::new();
let e = world.entity();
let stage = world.create_async_stage();
e.mut_current_stage(stage).set(Position { x: 10, y: 20 });
assert!(!e.has::<Position>());
stage.merge();
assert!(e.has::<Position>());
§See also
World::get_stage_count()
World::is_stage()
World::set_stage_count()
World::stage()
World::stage_id()
- C++ API:
world::merge
Sourcepub fn stage(&self, stage_id: i32) -> WorldRef<'_>
pub fn stage(&self, stage_id: i32) -> WorldRef<'_>
Get stage-specific world pointer.
Flecs threads can safely invoke the API as long as they have a private context to write to, also referred to as the stage. This function returns a pointer to a stage, disguised as a world pointer.
Note that this function does not(!) create a new world. It simply wraps the
existing world in a thread-specific context, which the API knows how to
unwrap. The reason the stage is returned as an sys::ecs_world_t
is so that it
can be passed transparently to the existing API functions, vs. having to
create a dedicated API for threading.
§Arguments
stage_id
- The index of the stage to retrieve.
§Returns
A thread-specific pointer to the world.
§Example
use flecs_ecs::prelude::*;
let world = World::new();
assert_eq!(world.stage_id(), 0);
world.set_stage_count(4);
assert_eq!(world.stage_id(), 0);
let stage = world.stage(3);
assert_eq!(stage.stage_id(), 3);
§See also
World::get_stage_count()
World::is_stage()
World::merge()
World::set_stage_count()
World::stage_id()
- C++ API:
world::get_stage
Sourcepub fn create_async_stage(&self) -> WorldRef<'_>
pub fn create_async_stage(&self) -> WorldRef<'_>
Create asynchronous stage.
An asynchronous stage can be used to asynchronously queue operations for later merging with the world. An asynchronous stage is similar to a regular stage, except that it does not allow reading from the world.
Asynchronous stages are never merged automatically, and must therefore be
manually merged with the sys::ecs_merge
function. It is not necessary to call defer_begin
or defer_end
before and after enqueuing commands, as an
asynchronous stage unconditionally defers operations.
The application must ensure that no commands are added to the stage while the stage is being merged.
An asynchronous stage must be cleaned up by sys::ecs_async_stage_free
.
§Returns
The stage.
§Example
use flecs_ecs::prelude::*;
#[derive(Component)]
struct Position { x: i32, y: i32 }
let world = World::new();
let e = world.entity();
let stage = world.create_async_stage();
e.mut_current_stage(stage).set(Position { x: 10, y: 20 });
assert!(!e.has::<Position>());
stage.merge();
assert!(e.has::<Position>());
§See also
- C++ API:
world::async_stage
Sourcepub fn get_world(&self) -> WorldRef<'_>
pub fn get_world(&self) -> WorldRef<'_>
Get actual world.
If the current object points to a stage, this operation will return the actual world.
§Returns
The actual world.
§Example
use flecs_ecs::prelude::*;
let world = World::new();
let stage = world.stage(0);
let world_ref = stage.get_world();
assert!(!world_ref.is_stage());
§See also
- C++ API:
world::get_world
Sourcepub fn set_context(&self, ctx: *mut c_void, ctx_free: ecs_ctx_free_t)
pub fn set_context(&self, ctx: *mut c_void, ctx_free: ecs_ctx_free_t)
Set world context.
Set a context value that can be accessed by anyone that has a reference to the world.
§Arguments
ctx
- The world context.ctx_free
- The free function for the context. Can passNone
if no free function is needed.
§Example
use flecs_ecs::prelude::*;
use core::ffi::c_void;
extern "C" fn free_ctx(ctx: *mut c_void) {
unsafe {
Box::from_raw(ctx as *mut i32);
}
}
let world = World::new();
let ctx = Box::leak(Box::new(42));
world.set_context(ctx as *mut i32 as *mut c_void, Some(free_ctx));
assert_eq!(world.context() as *const i32, ctx);
§See also
World::context()
- C++ API:
world::set_ctx
Sourcepub fn context(&self) -> *mut c_void
pub fn context(&self) -> *mut c_void
Get world context.
§Returns
The configured world context.
§Example
See World::set_context
.
§See also
World::set_context()
- C++ API:
world::get_ctx
Sourcepub fn preallocate_entity_count(&self, entity_count: i32)
pub fn preallocate_entity_count(&self, entity_count: i32)
Sourcepub fn set_entity_range(&self, min: impl Into<Entity>, max: impl Into<Entity>)
pub fn set_entity_range(&self, min: impl Into<Entity>, max: impl Into<Entity>)
Set the entity range.
This function limits the range of issued entity IDs between min
and max
.
§Arguments
min
- Minimum entity ID issued.max
- Maximum entity ID issued.
§Example
use flecs_ecs::prelude::*;
let world = World::new();
world.set_entity_range(5000, 0);
let e = world.entity();
assert_eq!(e.id(), 5000);
let e = world.entity();
assert_eq!(e.id(), 5001);
§See also
World::enable_range_check()
- C++ API:
world::set_entity_range
Sourcepub fn enable_range_check(&self, enabled: bool)
pub fn enable_range_check(&self, enabled: bool)
Enforce that operations cannot modify entities outside of the specified range.
This function ensures that only entities within the specified range can be modified. Use this function if specific parts of the code are only allowed to modify a certain set of entities, as could be the case for networked applications.
§Arguments
enabled
- True if the range check should be enabled, false otherwise.
§Example
use flecs_ecs::prelude::*;
let world = World::new();
let e = world.entity();
let e2 = world.entity();
world.set_entity_range(5000, 0);
world.enable_range_check(true);
e.add_id(e2); // panics in debug mode! because e and e2 are outside the range
panic!("in release mode, this does not panic, this is to prevent the test from failing")
§See also
World::set_entity_range()
- C++ API:
world::enable_range_check
Sourcepub fn get_scope(&self) -> Option<EntityView<'_>>
pub fn get_scope(&self) -> Option<EntityView<'_>>
Get the current scope. Get the scope set by set_scope
.
If no scope is set, this operation will return None
.
§Returns
Returns an EntityView
representing the current scope.
If no scope is set, this operation will return None
.
§Example
use flecs_ecs::prelude::*;
let world = World::new();
let e = world.entity_named("scope");
world.set_scope_id(e);
let s = world.get_scope();
assert_eq!(s.unwrap(), e);
§See also
World::set_scope()
World::set_scope_id()
- C++ API:
world::get_scope
Sourcepub fn set_scope_id(&self, id: impl IntoId) -> EntityView<'_>
pub fn set_scope_id(&self, id: impl IntoId) -> EntityView<'_>
Set the current scope. This operation sets the scope of the current stage to the provided entity. As a result new entities will be created in this scope, and lookups will be relative to the provided scope. It is considered good practice to restore the scope to the old value.
This method changes the current scope to the entity represented by the provided id
.
§Arguments
id
- The ID of the scope entity to set.
§Returns
Returns an EntityView
representing the previous set scope.
§Example
use flecs_ecs::prelude::*;
let world = World::new();
let e = world.entity_named("scope");
// previous scope can be used to set the scope back to the original.
let previous_scope = world.set_scope_id(e);
let s = world.get_scope();
assert_eq!(s.unwrap(), e);
§See also
World::get_scope()
World::set_scope()
- C++ API:
world::set_scope
Sourcepub fn set_scope<T: ComponentId>(&self) -> EntityView<'_>
pub fn set_scope<T: ComponentId>(&self) -> EntityView<'_>
Sets the current scope, but allows the scope type to be inferred from the type parameter. This operation sets the scope of the current stage to the provided entity. As a result new entities will be created in this scope, and lookups will be relative to the provided scope. It is considered good practice to restore the scope to the old value.
§Type Parameters
T
- The type that implementsComponentId
.
§Returns
Returns an EntityView
representing the previous set scope.
§Example
use flecs_ecs::prelude::*;
#[derive(Component)]
struct Scope;
let world = World::new();
// previous scope can be used to set the scope back to the original.
let previous_scope = world.set_scope::<Scope>();
let s = world.get_scope();
assert_eq!(s.unwrap(), world.component_id::<Scope>());
§See also
World::get_scope()
World::set_scope_id()
- C++ API:
world::set_scope
Sourcepub fn set_lookup_path(
&self,
search_path: impl Into<Entity>,
) -> *mut ecs_entity_t
pub fn set_lookup_path( &self, search_path: impl Into<Entity>, ) -> *mut ecs_entity_t
Sets the search path for entity lookup operations.
This function configures the search path used for looking up an entity.
§Best Practices
- It’s advisable to restore the previous search path after making temporary changes.
§Default Behavior
- The default search path includes
flecs.core
.
§Overwriting
- Providing a custom search path will overwrite the existing search path.
§Considerations
- If the custom search path doesn’t include
flecs.core
, operations that rely on looking up names fromflecs.core
may fail.
§Arguments
search_path
- The entity to set as the search path.
§Returns
Returns the current search path after the operation.
§See also
World::lookup()
World::lookup_recursive()
World::try_lookup()
World::try_lookup_recursive()
- C++ API:
world::set_lookup_path
- C API:
sys::ecs_set_lookup_path
Sourcepub fn lookup_recursive(&self, name: &str) -> EntityView<'_>
pub fn lookup_recursive(&self, name: &str) -> EntityView<'_>
Lookup an entity by name. The entity is searched recursively recursively traversing up the tree until found.
§Panics
Ensure that the entity exists before using it.
Use the World::try_lookup_recursive()
variant otherwise.
§Arguments
name
- The name of the entity to lookup.
§Returns
The entity
§Example
use flecs_ecs::prelude::*;
#[derive(Component)]
struct Position { x: i32, y: i32 }
let world = World::new();
let a = world.entity().set(Position { x: 10, y: 20 }).with(|| {
world.entity_named("X");
});
let x = world.lookup_recursive("X");
assert!(x.has_id(a));
§See also
World::lookup()
World::set_lookup_path()
World::try_lookup()
World::try_lookup_recursive()
- C++ API:
world::lookup
Examples found in repository?
42fn main() {
43 let world = World::new();
44
45 // Make the ECS aware of the inheritance relationships. Note that IsA
46 // relationship used here is the same as in the prefab example.
47 world.component::<CombatUnit>().is_a::<Unit>();
48 world.component::<MeleeUnit>().is_a::<CombatUnit>();
49 world.component::<RangedUnit>().is_a::<CombatUnit>();
50
51 world.component::<Warrior>().is_a::<MeleeUnit>();
52 world.component::<Wizard>().is_a::<RangedUnit>();
53 world.component::<Marksman>().is_a::<RangedUnit>();
54
55 // Populate store with players and platoons
56 for p in 0..PLAYER_COUNT {
57 let player = if p == 0 {
58 // Give first player a name so we can look it up later
59 world.entity_named("MyPlayer")
60 } else {
61 world.entity()
62 };
63
64 // Add player tag so we can query for all players if we want to
65 player.add::<Player>();
66
67 for _ in 0..PLATOONS_PER_PLAYER {
68 let platoon = world
69 .entity()
70 .add_first::<Player>(player)
71 // Add platoon tag so we can query for all platoons if we want to
72 .add::<Platoon>();
73
74 // Add warriors, wizards and marksmen to the platoon
75 world
76 .entity()
77 .add::<Warrior>()
78 .add_first::<Platoon>(platoon);
79 world
80 .entity()
81 .add::<Marksman>()
82 .add_first::<Platoon>(platoon);
83 world.entity().add::<Wizard>().add_first::<Platoon>(platoon);
84 }
85 }
86
87 // Create a query to find all RangedUnits for a platoon/player. The
88 // equivalent query in the query DSL would look like this:
89 // (Platoon, $Platoon), Player($Platoon, $Player)
90 //
91 // The way to read how this query is evaluated is:
92 // - find all entities with (Platoon, *), store * in _Platoon
93 // - check if _Platoon has (Player, *), store * in _Player
94 let mut query = world
95 .query::<&RangedUnit>()
96 .with::<&Platoon>()
97 .set_second_name("$platoon")
98 .with_first_name::<&Player>("$player")
99 .set_src_name("$platoon")
100 .build();
101
102 // If we would iterate this query it would return all ranged units for all
103 // platoons & for all players. We can limit the results to just a single
104 // platoon or a single player setting a variable beforehand. In this example
105 // we'll just find all platoons & ranged units for a single player.
106
107 let player_var = query.find_var("player").unwrap();
108 let platoon_var = query.find_var("platoon").unwrap();
109
110 // Iterate query, limit the results to units of MyPlayer
111 query
112 .set_var(player_var, world.lookup_recursive("MyPlayer"))
113 .each_iter(|it, index, _| {
114 let unit = it.entity(index);
115 println!(
116 "Unit id: {} of class {} in platoon id: {} for player {}",
117 unit,
118 it.id(0).to_str(),
119 it.get_var(platoon_var),
120 it.get_var(player_var)
121 );
122 });
123
124 // Output:
125 // Unit id: 529 of class Wizard in platoon id: 526 for player MyPlayer
126 // Unit id: 533 of class Wizard in platoon id: 530 for player MyPlayer
127 // Unit id: 537 of class Wizard in platoon id: 534 for player MyPlayer
128 // Unit id: 528 of class Marksman in platoon id: 526 for player MyPlayer
129 // Unit id: 532 of class Marksman in platoon id: 530 for player MyPlayer
130 // Unit id: 536 of class Marksman in platoon id: 534 for player MyPlayer
131
132 // Try removing the set_var call, this will cause the iterator to return
133 // all units in all platoons for all players.
134}
Sourcepub fn lookup(&self, name: &str) -> EntityView<'_>
pub fn lookup(&self, name: &str) -> EntityView<'_>
Lookup entity by name, only the current scope is searched
§Panics
Ensure that the entity exists before using it.
Use the World::try_lookup()
variant otherwise.
§Arguments
name
- The name of the entity to lookup.
§Returns
The entity
§See also
World::lookup_recursive()
World::set_lookup_path()
World::try_lookup()
World::try_lookup_recursive()
- C++ API:
world::lookup
Sourcepub fn try_lookup_recursive(&self, name: &str) -> Option<EntityView<'_>>
pub fn try_lookup_recursive(&self, name: &str) -> Option<EntityView<'_>>
Lookup an entity by name. The entity is searched recursively recursively traversing up the tree until found.
§Arguments
name
- The name of the entity to lookup.
§Returns
The entity if found, otherwise None
.
§See also
World::lookup()
World::lookup_recursive()
World::set_lookup_path()
World::try_lookup()
- C++ API:
world::lookup
Sourcepub fn try_lookup(&self, name: &str) -> Option<EntityView<'_>>
pub fn try_lookup(&self, name: &str) -> Option<EntityView<'_>>
Lookup entity by name, only the current scope is searched
§Arguments
name
- The name of the entity to lookup.
§Returns
The entity if found, otherwise None
.
§See also
World::lookup()
World::lookup_recursive()
World::set_lookup_path()
World::try_lookup_recursive()
- C++ API:
world::lookup
Sourcepub fn set<T: ComponentId + DataComponent + ComponentType<Struct>>(
&self,
component: T,
)
pub fn set<T: ComponentId + DataComponent + ComponentType<Struct>>( &self, component: T, )
Sets a singleton component of type T
on the world.
§Arguments
component
- The singleton component to set on the world.
§See also
- C++ API:
world::set
Examples found in repository?
17fn main() {
18 let world = World::new();
19
20 world.set(Timeout { value: 3.5 });
21
22 world
23 .system::<&mut Timeout>()
24 .each_iter(|it, _index, timeout| {
25 timeout.value -= it.delta_time();
26 });
27
28 world.system_named::<()>("Tick").interval(1.0).run(tick);
29
30 world.system_named::<()>("FastTick").interval(0.5).run(tick);
31
32 // Run the main loop at 60 FPS
33 world.set_target_fps(60.0);
34
35 while world.progress() {
36 if world.map::<&Timeout, _>(|timeout| timeout.value <= 0.0) {
37 println!("Timed out!");
38 break;
39 }
40 }
41
42 // Output:
43 // FastTick
44 // Tick
45 // FastTick
46 // FastTick
47 // Tick
48 // FastTick
49 // FastTick
50 // Tick
51 // FastTick
52 // FastTick
53 // Timed out!
54}
More examples
15fn main() {
16 let world = World::new();
17
18 // Set singleton
19 world.set(Gravity { value: 9.81 });
20
21 // Set Velocity
22 world.entity_named("e1").set(Velocity { x: 0.0, y: 0.0 });
23 world.entity_named("e2").set(Velocity { x: 0.0, y: 1.0 });
24 world.entity_named("e3").set(Velocity { x: 0.0, y: 2.0 });
25
26 // Create query that matches Gravity as singleton
27 let query = world
28 .query::<(&mut Velocity, &Gravity)>()
29 .term_at(1)
30 .singleton()
31 .build();
32
33 // In a query string expression you can use the $ shortcut for singletons:
34 // Velocity, Gravity($)
35
36 query.each_entity(|entity, (velocity, gravity)| {
37 velocity.y += gravity.value;
38 println!("Entity {} has {:?}", entity.path().unwrap(), velocity);
39 });
40
41 // Output:
42 // Entity ::e1 has Velocity { x: 0.0, y: 9.81 }
43 // Entity ::e2 has Velocity { x: 0.0, y: 10.81 }
44 // Entity ::e3 has Velocity { x: 0.0, y: 11.81 }
45}
Sourcepub fn set_second<Second>(&self, first: impl Into<Entity>, second: Second)
pub fn set_second<Second>(&self, first: impl Into<Entity>, second: Second)
Sourcepub fn set_pair<First, Second>(
&self,
data: <(First, Second) as ComponentOrPairId>::CastType,
)
pub fn set_pair<First, Second>( &self, data: <(First, Second) as ComponentOrPairId>::CastType, )
Set singleton pair. This operation sets the pair value, and uses the first non tag / ZST as type. If the entity did not yet have the pair, it will be added, otherwise overridden.
§See also
- C++ API:
world::set
Sourcepub fn modified_id(&self, id: impl Into<Entity>)
pub fn modified_id(&self, id: impl Into<Entity>)
signal that singleton component was modified.
§Arguments
id
- The id of the component that was modified.
§See also
EntityView::modified()
World::modified()
- C++ API:
world::modified
Sourcepub fn modified<T>(&self)where
T: ComponentId,
pub fn modified<T>(&self)where
T: ComponentId,
Signal that singleton component was modified.
§Type Parameters
T
- The type of the component that was modified.
§See also
EntityView::modified()
World::modified_id()
- C++ API:
world::modified
Sourcepub fn try_get<T: GetTupleTypeOperation>(
&self,
callback: impl for<'e> FnOnce(T::ActualType<'e>),
) -> boolwhere
T::OnlyType: ComponentOrPairId,
pub fn try_get<T: GetTupleTypeOperation>(
&self,
callback: impl for<'e> FnOnce(T::ActualType<'e>),
) -> boolwhere
T::OnlyType: ComponentOrPairId,
gets a mutable or immutable singleton component and/or relationship(s) from the world.
Only one singleton component at a time is retrievable, but you can call this function multiple times within the callback.
each component type must be marked &
or &mut
to indicate if it is mutable or not.
use Option
wrapper to indicate if the component is optional.
try_get
assumes when not usingOption
wrapper, that the entity has the component. If it does not, it will not run the callback. If unsure and you still want to have the callback be ran, useOption
wrapper instead.
§Note
- You cannot get single component tags with this function, use
has
functionality instead. - You can only get relationships with a payload, so where one is not a tag / not a zst.
tag relationships, use
has
functionality instead. - This causes the table to lock where the entity belongs to to prevent invalided references, see #Panics. The lock is dropped at the end of the callback.
§Panics
- This will panic if within the callback you do any operation that could invalidate the reference.
This happens when the entity is moved to a different table in memory. Such as adding, removing components or
creating/deleting entities where the entity belongs to the same table (which could cause a table grow operation).
In case you need to do such operations, you can either do it after the get operation or defer the world with
world.defer_begin()
.
§Returns
- If the callback has ran.
§Example
use flecs_ecs::prelude::*;
#[derive(Component)]
struct Tag;
#[derive(Component)]
pub struct Position {
pub x: f32,
pub y: f32,
}
let world = World::new();
world.set(Position { x: 10.0, y: 20.0 });
world.set_pair::<Tag, Position>(Position { x: 30.0, y: 40.0 });
let has_run = world.try_get::<&Position>(|pos| {
assert_eq!(pos.x, 10.0);
});
assert!(has_run);
let has_run = world.try_get::<&mut(Tag,Position)>(|pos| {
assert_eq!(pos.x, 30.0);
});
assert!(has_run);
Sourcepub fn get<T: GetTupleTypeOperation>(
&self,
callback: impl for<'e> FnOnce(T::ActualType<'e>),
)where
T::OnlyType: ComponentOrPairId,
pub fn get<T: GetTupleTypeOperation>(
&self,
callback: impl for<'e> FnOnce(T::ActualType<'e>),
)where
T::OnlyType: ComponentOrPairId,
gets a mutable or immutable singleton component and/or relationship(s) from the world.
Only one singleton component at a time is retrievable, but you can call this function multiple times within the callback.
each component type must be marked &
or &mut
to indicate if it is mutable or not.
use Option
wrapper to indicate if the component is optional.
§Note
- You cannot get single component tags with this function, use
has
functionality instead. - You can only get relationships with a payload, so where one is not a tag / not a zst.
tag relationships, use
has
functionality instead. - This causes the table to lock where the entity belongs to to prevent invalided references, see #Panics. The lock is dropped at the end of the callback.
§Panics
-
This will panic if within the callback you do any operation that could invalidate the reference. This happens when the entity is moved to a different table in memory. Such as adding, removing components or creating/deleting entities where the entity belongs to the same table (which could cause a table grow operation). In case you need to do such operations, you can either do it after the get operation or defer the world with
world.defer_begin()
. -
get
assumes when not usingOption
wrapper, that the entity has the component. This will panic if the entity does not have the component. If unsure, useOption
wrapper ortry_get
function instead.try_get
does not run the callback if the entity does not have the component that isn’t markedOption
.
§Example
use flecs_ecs::prelude::*;
#[derive(Component)] struct Tag;
#[derive(Component)]
pub struct Position {
pub x: f32,
pub y: f32,
}
let world = World::new();
world.set(Position { x: 10.0, y: 20.0 });
world.set_pair::<Tag, Position>(Position { x: 30.0, y: 40.0 });
world.get::<&Position>(|pos| {
assert_eq!(pos.x, 10.0);
});
world.get::<&mut(Tag,Position)>(|pos| {
assert_eq!(pos.x, 30.0);
});
Sourcepub fn cloned<T: ClonedTupleTypeOperation>(&self) -> T::ActualTypewhere
T::OnlyType: ComponentOrPairId,
pub fn cloned<T: ClonedTupleTypeOperation>(&self) -> T::ActualTypewhere
T::OnlyType: ComponentOrPairId,
Clones a singleton component and/or relationship from the world and returns it.
each component type must be marked &
. This helps Rust type checker to determine if it’s a relationship.
use Option
wrapper to indicate if the component is optional.
use ()
tuple format when getting multiple components.
§Note
- You cannot clone component tags with this function.
- You can only clone relationships with a payload, so where one is not a tag / not a zst.
§Panics
- This will panic if the world does not have the singleton component that isn’t marked
Option
.
§Example
use flecs_ecs::prelude::*;
#[derive(Component)] struct Tag;
#[derive(Component, Clone)]
pub struct Position {
pub x: f32,
pub y: f32,
}
#[derive(Component, Clone)]
pub struct Velocity {
pub x: f32,
pub y: f32,
}
let world = World::new();
world.set(Position { x: 10.0, y: 20.0 });
world.set_pair::<Tag, Position>(Position { x: 30.0, y: 40.0 });
let pos = world.cloned::<&Position>();
assert_eq!(pos.x, 10.0);
let tag_pos = world.cloned::<&(Tag, Position)>();
assert_eq!(tag_pos.x, 30.0);
let vel = world.cloned::<Option<&Velocity>>();
assert!(vel.is_none());
Sourcepub fn try_map<T: GetTupleTypeOperation, Return>(
&self,
callback: impl for<'e> FnOnce(T::ActualType<'e>) -> Option<Return>,
) -> Option<Return>where
T::OnlyType: ComponentOrPairId,
pub fn try_map<T: GetTupleTypeOperation, Return>(
&self,
callback: impl for<'e> FnOnce(T::ActualType<'e>) -> Option<Return>,
) -> Option<Return>where
T::OnlyType: ComponentOrPairId,
gets mutable or immutable component(s) and/or relationship(s) from the world in a callback and return a value.
each component type must be marked &
or &mut
to indicate if it is mutable or not.
use Option
wrapper to indicate if the component is optional.
try_map
assumes when not usingOption
wrapper, that the entity has the component. If it does not, it will not run the callback and returnNone
. If unsure and you still want to have the callback be ran, useOption
wrapper instead.
§Note
- You cannot get single component tags with this function, use
has
functionality instead. - You can only get relationships with a payload, so where one is not a tag / not a zst.
tag relationships, use
has
functionality instead. - This causes the table to lock where the entity belongs to to prevent invalided references, see #Panics. The lock is dropped at the end of the callback.
§Panics
- This will panic if within the callback you do any operation that could invalidate the reference.
This happens when the entity is moved to a different table in memory. Such as adding, removing components or
creating/deleting entities where the entity belongs to the same table (which could cause a table grow operation).
In case you need to do such operations, you can either do it after the get operation or defer the world with
world.defer_begin()
.
§Returns
- a
Some(value)
if the callback has ran. Where the type of value is specified inReturn
generic (can be elided).None
if the callback has not ran.
§Example
use flecs_ecs::prelude::*;
#[derive(Component)] struct Tag;
#[derive(Component)]
pub struct Velocity {
pub x: f32,
pub y: f32,
}
#[derive(Component)]
pub struct Position {
pub x: f32,
pub y: f32,
}
let world = World::new();
let entity = world.entity()
.set(Position { x: 10.0, y: 20.0 })
.set_pair::<Tag, Position>(Position { x: 30.0, y: 40.0 });
let pos_x = entity.try_map::<&Position, _>(|(pos)| {
assert_eq!(pos.x, 10.0);
Some(pos.x)
});
assert!(pos_x.is_some());
assert_eq!(pos_x.unwrap(), 10.0);
let is_pos_x_10 = entity.try_map::<(Option<&Velocity>, &Position), _>( |(tag, pos)| {
assert_eq!(pos.x, 10.0);
assert!(tag.is_none());
Some(pos.x == 10.0)
});
assert!(is_pos_x_10.is_some());
assert!(is_pos_x_10.unwrap());
// no return type
let has_run = entity.try_map::<(&mut(Tag,Position), &Position),_>(|(tag_pos_rel, pos)| {
assert_eq!(pos.x, 10.0);
assert_eq!(tag_pos_rel.x, 30.0);
Some(())
});
assert!(has_run.is_some());
Sourcepub fn map<T: GetTupleTypeOperation, Return>(
&self,
callback: impl for<'e> FnOnce(T::ActualType<'e>) -> Return,
) -> Returnwhere
T::OnlyType: ComponentOrPairId,
pub fn map<T: GetTupleTypeOperation, Return>(
&self,
callback: impl for<'e> FnOnce(T::ActualType<'e>) -> Return,
) -> Returnwhere
T::OnlyType: ComponentOrPairId,
gets mutable or immutable singleton component and/or relationship from the world in a callback.
each component type must be marked &
or &mut
to indicate if it is mutable or not.
use Option
wrapper to indicate if the component is optional.
use ()
tuple format when getting multiple components.
§Note
- You cannot get single component tags with this function, use
has
functionality instead. - You can only get relationships with a payload, so where one is not a tag / not a zst.
tag relationships, use
has
functionality instead. - This causes the table to lock where the entity belongs to to prevent invalided references, see #Panics. The lock is dropped at the end of the callback.
§Panics
-
This will panic if within the callback you do any operation that could invalidate the reference. This happens when the entity is moved to a different table in memory. Such as adding, removing components or creating/deleting entities where the entity belongs to the same table (which could cause a table grow operation). In case you need to do such operations, you can either do it after the get operation or defer the world with
world.defer_begin()
. -
get
assumes when not usingOption
wrapper, that the entity has the component. This will panic if the entity does not have the component. If unsure, useOption
wrapper ortry_get
function instead.try_get
does not run the callback if the entity does not have the component that isn’t markedOption
.
§Example
use flecs_ecs::prelude::*;
#[derive(Component)] struct Tag;
#[derive(Component)]
pub struct Velocity {
pub x: f32,
pub y: f32,
}
#[derive(Component)]
pub struct Position {
pub x: f32,
pub y: f32,
}
let world = World::new();
let entity = world.entity()
.set(Position { x: 10.0, y: 20.0 })
.set_pair::<Tag, Position>(Position { x: 30.0, y: 40.0 });
let position_parent = Position { x: 20.0, y: 30.0 };
let pos_actual = entity.map::<&Position, _>(|pos| {
assert_eq!(pos.x, 10.0);
// Calculate actual position
Position {
x: pos.x + position_parent.x,
y: pos.y + position_parent.y,
}
});
let pos_x = entity.map::<(Option<&Velocity>, &Position),_>( |(vel, pos)| {
assert_eq!(pos.x, 10.0);
assert!(vel.is_none());
pos.x
});
assert_eq!(pos_x, 10.0);
let is_x_10 = entity.map::<(&mut(Tag,Position), &Position), _>(|(tag_pos_rel, pos)| {
assert_eq!(pos.x, 10.0);
assert_eq!(tag_pos_rel.x, 30.0);
pos.x == 10.0
});
assert!(is_x_10);
Examples found in repository?
17fn main() {
18 let world = World::new();
19
20 world.set(Timeout { value: 3.5 });
21
22 world
23 .system::<&mut Timeout>()
24 .each_iter(|it, _index, timeout| {
25 timeout.value -= it.delta_time();
26 });
27
28 world.system_named::<()>("Tick").interval(1.0).run(tick);
29
30 world.system_named::<()>("FastTick").interval(0.5).run(tick);
31
32 // Run the main loop at 60 FPS
33 world.set_target_fps(60.0);
34
35 while world.progress() {
36 if world.map::<&Timeout, _>(|timeout| timeout.value <= 0.0) {
37 println!("Timed out!");
38 break;
39 }
40 }
41
42 // Output:
43 // FastTick
44 // Tick
45 // FastTick
46 // FastTick
47 // Tick
48 // FastTick
49 // FastTick
50 // Tick
51 // FastTick
52 // FastTick
53 // Timed out!
54}
Sourcepub fn get_ref<T>(&self) -> CachedRef<'_, T::UnderlyingType>
pub fn get_ref<T>(&self) -> CachedRef<'_, T::UnderlyingType>
Get a reference to a singleton component.
A reference allows for quick and safe access to a component value, and is
a faster alternative to repeatedly calling get
for the same component.
T
: Component for which to get a reference.
Returns: The reference singleton component.
§See also
- C++ API:
world::get_ref
Sourcepub fn singleton<T: ComponentId>(&self) -> EntityView<'_>
pub fn singleton<T: ComponentId>(&self) -> EntityView<'_>
Sourcepub fn target<First>(&self, index: Option<i32>) -> EntityView<'_>where
First: ComponentId,
pub fn target<First>(&self, index: Option<i32>) -> EntityView<'_>where
First: ComponentId,
Gets the target for a given pair from a singleton entity.
This operation returns the target for a given pair. The optional
index
can be used to iterate through targets, in case the entity has
multiple instances for the same relationship.
§Type Parameters
First
- The first element of the pair.
§Arguments
index
- The index (None for the first instance of the relationship).
§See also
World::target_id()
- C++ API:
world::target
Sourcepub fn target_id(
&self,
relationship: impl Into<Entity>,
index: Option<usize>,
) -> EntityView<'_>
pub fn target_id( &self, relationship: impl Into<Entity>, index: Option<usize>, ) -> EntityView<'_>
Retrieves the target for a given pair from a singleton entity.
This operation fetches the target associated with a specific pair. An optional
index
parameter allows iterating through multiple targets if the entity
has more than one instance of the same relationship.
§Arguments
first
- The first element of the pair for which to retrieve the target.index
- The index (0 for the first instance of the relationship).
§See also
World::target()
- C++ API:
world::target
Sourcepub fn has_id(&self, id: impl IntoId) -> bool
pub fn has_id(&self, id: impl IntoId) -> bool
Check if world has the provided id.
§Arguments
id
: The id to check of a pair, entity or component.
§Returns
True if the world has the provided id, false otherwise.
§See also
World::has()
World::has_enum()
- C++ API:
world::has
Sourcepub fn has<T>(&self) -> boolwhere
T: ComponentOrPairId,
pub fn has<T>(&self) -> boolwhere
T: ComponentOrPairId,
Check if world has the provided type (enum,pair,struct).
§Type Parameters
T
- The type to check.
§Returns
True if the world has the provided type, false otherwise.
§See also
World::has_enum()
World::has_id()
- C++ API:
world::has
Sourcepub fn has_enum<T>(&self, constant: T) -> bool
pub fn has_enum<T>(&self, constant: T) -> bool
Check if world has the provided enum constant.
§Type Parameters
T
- The enum type.
§Arguments
constant
- The enum constant to check.
§Returns
True if the world has the provided constant, false otherwise.
§See also
World::has()
World::has_id()
- C++ API:
world::has
Sourcepub fn add_id<T>(&self, id: T) -> EntityView<'_>where
T: IntoId,
pub fn add_id<T>(&self, id: T) -> EntityView<'_>where
T: IntoId,
Sourcepub fn add<T: ComponentOrPairId>(&self) -> EntityView<'_>
pub fn add<T: ComponentOrPairId>(&self) -> EntityView<'_>
Sourcepub fn add_enum<T: ComponentId + ComponentType<Enum> + EnumComponentInfo>(
&self,
enum_value: T,
) -> EntityView<'_>
pub fn add_enum<T: ComponentId + ComponentType<Enum> + EnumComponentInfo>( &self, enum_value: T, ) -> EntityView<'_>
Sourcepub fn add_second<Second: ComponentId + TagComponent>(
&self,
first: impl Into<Entity>,
) -> EntityView<'_>
pub fn add_second<Second: ComponentId + TagComponent>( &self, first: impl Into<Entity>, ) -> EntityView<'_>
Sourcepub fn add_first<First: ComponentId + TagComponent>(
&self,
second: impl Into<Entity>,
) -> EntityView<'_>
pub fn add_first<First: ComponentId + TagComponent>( &self, second: impl Into<Entity>, ) -> EntityView<'_>
Sourcepub fn add_pair_enum<First, Second>(&self, enum_value: Second) -> EntityView<'_>
pub fn add_pair_enum<First, Second>(&self, enum_value: Second) -> EntityView<'_>
Sourcepub fn remove_id<T>(&self, id: T) -> EntityView<'_>where
T: IntoId,
pub fn remove_id<T>(&self, id: T) -> EntityView<'_>where
T: IntoId,
Sourcepub fn remove<T: ComponentOrPairId>(&self)
pub fn remove<T: ComponentOrPairId>(&self)
Sourcepub fn remove_enum_tag<First, Second>(&self, enum_value: Second)
pub fn remove_enum_tag<First, Second>(&self, enum_value: Second)
Sourcepub fn remove_second<Second: ComponentId>(&self, first: impl Into<Entity>)
pub fn remove_second<Second: ComponentId>(&self, first: impl Into<Entity>)
Sourcepub fn remove_first<First: ComponentId>(&self, second: impl Into<Entity>)
pub fn remove_first<First: ComponentId>(&self, second: impl Into<Entity>)
Sourcepub fn each_child(&self, callback: impl FnMut(EntityView<'_>))
pub fn each_child(&self, callback: impl FnMut(EntityView<'_>))
Sourcepub fn set_alias_component<T: ComponentId>(&self, alias: &str) -> EntityView<'_>
pub fn set_alias_component<T: ComponentId>(&self, alias: &str) -> EntityView<'_>
Sourcepub fn set_alias_entity_by_name(
&self,
name: &str,
alias: &str,
) -> EntityView<'_>
pub fn set_alias_entity_by_name( &self, name: &str, alias: &str, ) -> EntityView<'_>
Sourcepub fn set_alias_entity(&self, entity: impl Into<Entity>, alias: &str)
pub fn set_alias_entity(&self, entity: impl Into<Entity>, alias: &str)
Sourcepub fn count<T: ComponentOrPairId>(&self) -> i32
pub fn count<T: ComponentOrPairId>(&self) -> i32
Count entities with the provided component.
§Type Parameters
T
- The component to count.
§Returns
The number of entities with the provided component.
§See also
- C++ API:
world::count
Examples found in repository?
17fn main() {
18 let world = World::new();
19
20 // This example shows how to annotate systems that delete entities, in a way
21 // that allows the scheduler to correctly insert sync points. See the
22 // sync_point example for more details on sync points.
23 //
24 // While annotating a system for a delete operation follows the same
25 // design as other operations, one key difference is that a system often
26 // does not know which components a to be deleted entity has. This makes it
27 // impossible to annotate the system in advance for specific components.
28 //
29 // To ensure the scheduler is still able to insert the correct sync points,
30 // a system can use a wildcard to indicate that any component could be
31 // modified by the system, which forces the scheduler to insert a sync.
32
33 // Basic move system.
34 world
35 .system_named::<(&mut Position, &Velocity)>("Move")
36 .each(|(p, v)| {
37 p.x += v.x;
38 p.y += v.y;
39 });
40
41 // Delete entities when p.x >= 3. Add wildcard annotation to indicate any
42 // component could be written by the system. Position itself is added as
43 // const, since inside the system we're only reading it.
44 world
45 .system_named::<&Position>("DeleteEntity")
46 .write::<flecs::Wildcard>()
47 .each_entity(|e, p| {
48 if p.x >= 3.0 {
49 println!("Delete entity {}", e.name());
50 e.destruct();
51 }
52 });
53
54 // Print resulting Position. Note that this system will never print entities
55 // that have been deleted by the previous system.
56 world
57 .system_named::<&Position>("PrintPosition")
58 .each_entity(|e, p| {
59 println!("{}: {{ {}, {} }}", e.name(), p.x, p.y);
60 });
61
62 // Create a few test entities for a Position, Velocity query
63 world
64 .entity_named("e1")
65 .set(Position { x: 0.0, y: 0.0 })
66 .set(Velocity { x: 1.0, y: 2.0 });
67
68 world
69 .entity_named("e2")
70 .set(Position { x: 1.0, y: 2.0 })
71 .set(Velocity { x: 1.0, y: 2.0 });
72
73 // Run systems. Debug logging enables us to see the generated schedule.
74 // NOTE flecs C / flecs_ecs_sys needs to be build in debug mode to see the logging.
75 // use the feature flag "sys_build_debug" to enable debug build of flecs C.
76
77 set_log_level(1);
78
79 while world.progress() {
80 if world.count::<Position>() == 0 {
81 break; // No more entities left with Position
82 }
83 }
84 set_log_level(-1);
85
86 // world
87 // .get::<Snap>()
88 // .test("system_sync_point_delete".to_string()));
89
90 // Output:
91 // info: pipeline rebuild
92 // info: | schedule: threading: 0, staging: 1:
93 // info: | | system Move
94 // info: | | system DeleteEntity
95 // info: | | merge
96 // info: | schedule: threading: 0, staging: 1:
97 // info: | | system PrintPosition
98 // info: | | merge
99 // e1: { 1, 2 }
100 // e2: { 2, 4 }
101 // Delete entity e2
102 // e1: { 2, 4 }
103 // Delete entity e1
104
105 // Removing the wildcard annotation from the DeleteEntity system will
106 // remove the first sync point.
107
108 // Note how after both entities are deleted, all three systems will be de-activated and not ran by the scheduler
109}
Sourcepub fn count_second<Second: ComponentId>(&self, first: impl Into<Entity>) -> i32
pub fn count_second<Second: ComponentId>(&self, first: impl Into<Entity>) -> i32
Sourcepub fn count_first<First: ComponentId>(&self, second: impl Into<Entity>) -> i32
pub fn count_first<First: ComponentId>(&self, second: impl Into<Entity>) -> i32
Sourcepub fn count_enum<T: ComponentId + ComponentType<Enum> + EnumComponentInfo>(
&self,
enum_value: T,
) -> i32
pub fn count_enum<T: ComponentId + ComponentType<Enum> + EnumComponentInfo>( &self, enum_value: T, ) -> i32
Sourcepub fn count_enum_tag_pair<First, Second>(&self, enum_value: Second) -> i32
pub fn count_enum_tag_pair<First, Second>(&self, enum_value: Second) -> i32
Sourcepub fn run_in_scope_with_id(
&self,
parent_id: impl Into<Entity>,
func: impl FnMut(),
)
pub fn run_in_scope_with_id( &self, parent_id: impl Into<Entity>, func: impl FnMut(), )
Sourcepub fn run_in_scope_with<T: ComponentId>(&self, func: impl FnMut())
pub fn run_in_scope_with<T: ComponentId>(&self, func: impl FnMut())
Sourcepub fn scope<T: ComponentId>(&self, f: impl FnMut(&World))
pub fn scope<T: ComponentId>(&self, f: impl FnMut(&World))
Sourcepub fn scope_name(&self, name: &str, f: impl FnMut(&World))
pub fn scope_name(&self, name: &str, f: impl FnMut(&World))
Sourcepub fn with<T: ComponentOrPairId>(&self, func: impl FnMut())
pub fn with<T: ComponentOrPairId>(&self, func: impl FnMut())
Sourcepub fn with_second<Second: ComponentId>(
&self,
first: impl Into<Entity>,
func: impl FnMut(),
)
pub fn with_second<Second: ComponentId>( &self, first: impl Into<Entity>, func: impl FnMut(), )
Sourcepub fn with_first<First: ComponentId>(
&self,
second: impl Into<Entity>,
func: impl FnMut(),
)
pub fn with_first<First: ComponentId>( &self, second: impl Into<Entity>, func: impl FnMut(), )
Sourcepub fn with_enum_pair<First, Second>(
&self,
enum_value: Second,
func: impl FnMut(),
)
pub fn with_enum_pair<First, Second>( &self, enum_value: Second, func: impl FnMut(), )
Sourcepub fn delete_with_id(&self, id: impl IntoId)
pub fn delete_with_id(&self, id: impl IntoId)
Sourcepub fn delete_entities_with<T: ComponentOrPairId>(&self)
pub fn delete_entities_with<T: ComponentOrPairId>(&self)
Sourcepub fn delete_with_second<Second: ComponentId>(&self, first: impl Into<Entity>)
pub fn delete_with_second<Second: ComponentId>(&self, first: impl Into<Entity>)
Sourcepub fn delete_entities_with_second_id<First: ComponentId>(
&self,
second: impl Into<Entity>,
)
pub fn delete_entities_with_second_id<First: ComponentId>( &self, second: impl Into<Entity>, )
Sourcepub fn delete_with_enum<T: ComponentId + ComponentType<Enum> + EnumComponentInfo>(
&self,
enum_value: T,
)
pub fn delete_with_enum<T: ComponentId + ComponentType<Enum> + EnumComponentInfo>( &self, enum_value: T, )
Sourcepub fn delete_with_enum_pair<First, Second>(&self, enum_value: Second)
pub fn delete_with_enum_pair<First, Second>(&self, enum_value: Second)
Sourcepub fn remove_all_id(&self, id: impl IntoId)
pub fn remove_all_id(&self, id: impl IntoId)
Sourcepub fn remove_all<T: ComponentOrPairId>(&self)
pub fn remove_all<T: ComponentOrPairId>(&self)
Sourcepub fn remove_all_second<Second: ComponentId>(&self, first: impl Into<Entity>)
pub fn remove_all_second<Second: ComponentId>(&self, first: impl Into<Entity>)
Sourcepub fn remove_all_first<First: ComponentId>(&self, second: impl Into<Entity>)
pub fn remove_all_first<First: ComponentId>(&self, second: impl Into<Entity>)
Sourcepub fn remove_all_enum<T: ComponentId + ComponentType<Enum> + EnumComponentInfo>(
&self,
enum_value: T,
)
pub fn remove_all_enum<T: ComponentId + ComponentType<Enum> + EnumComponentInfo>( &self, enum_value: T, )
Sourcepub fn remove_all_enum_pair<First, Second>(&self, enum_value: Second)
pub fn remove_all_enum_pair<First, Second>(&self, enum_value: Second)
Sourcepub fn is_valid(&self, entity: impl Into<Entity>) -> bool
pub fn is_valid(&self, entity: impl Into<Entity>) -> bool
Checks if the given entity ID is valid. Invalid entities cannot be used with API functions.
§See also
- C++ API:
world::is_valid
Sourcepub fn get_alive(&self, entity: impl Into<Entity>) -> EntityView<'_>
pub fn get_alive(&self, entity: impl Into<Entity>) -> EntityView<'_>
Get alive entity for id.
§Arguments
entity
- The entity to check
§Returns
The entity with the current generation. If the entity is not alive, this
function will return an Entity of 0. Use try_get_alive
if you want to
return an Option<EntityView>
.
§See also
- C++ API:
world::try_get_alive
Examples found in repository?
16fn main() {
17 let world = World::new();
18
19 // System that deletes an entity after a timeout expires
20 world
21 .system::<&mut Timeout>()
22 .each_iter(|it, _index, timeout| {
23 timeout.value -= it.delta_time();
24 if timeout.value <= 0.0 {
25 // Delete the entity
26
27 // To make sure the delete operation is enqueued (see
28 // mutate_entity example for more details) we need to provide it
29 // with a mutable context (stage) using the mut() function. If
30 // we don't provide a mutable context, the operation will be
31 // attempted on the context stored in the flecs::entity object,
32 // which would throw a readonly error.
33
34 // To catch these errors at compile time, replace the type of
35 // to_delete with flecs::entity_view. This class does not have
36 // any methods for mutating the entity, which forces the code to
37 // first call mut().
38
39 // The it.world() function can be used to provide the context:
40 // t.to_delete.mut(it.world()).destruct();
41 //
42 // The current entity can also be used to provide context. This
43 // is useful for functions that accept a flecs::entity:
44 // t.to_delete.mut(it.entity(index)).destruct();
45 //
46 // A shortcut is to use the iterator directly:
47 let world = it.world();
48 let to_delete = world.get_alive(timeout.to_delete);
49 println!("Expire: {} deleted!", to_delete.name());
50 to_delete.destruct();
51 }
52 });
53
54 // System that prints remaining expiry time
55 world.system::<&Timeout>().each_entity(|e, timeout| {
56 let world = e.world();
57 let to_delete = world.get_alive(timeout.to_delete);
58 println!(
59 "PrintExpire: {} has {:.2} seconds left",
60 to_delete.name(),
61 timeout.value
62 );
63 });
64
65 // Observer that triggers when entity is actually deleted
66 world
67 .observer::<flecs::OnRemove, &Tag>()
68 .each_entity(|e, _tag| {
69 println!("Expired: {} actually deleted", e.name());
70 });
71
72 let to_delete = world.entity_named("ToDelete").add::<Tag>();
73
74 world.entity_named("MyEntity").set(Timeout {
75 to_delete: to_delete.id(),
76 value: 2.5,
77 });
78
79 world.set_target_fps(1.0);
80
81 while world.progress() {
82 // If entity is no longer alive, exit
83 if !to_delete.is_alive() {
84 break;
85 }
86
87 println!("Tick...");
88 }
89
90 // Output:
91 // PrintExpire: ToDelete has 2.00 seconds left
92 // Tick...
93 // PrintExpire: ToDelete has 0.98 seconds left
94 // Tick...
95 // Expire: ToDelete deleted!
96 // PrintExpire: ToDelete has -0.03 seconds left
97 // Expired: ToDelete actually deleted
98}
Sourcepub fn try_get_alive(&self, entity: impl Into<Entity>) -> Option<EntityView<'_>>
pub fn try_get_alive(&self, entity: impl Into<Entity>) -> Option<EntityView<'_>>
Sourcepub fn make_alive(&self, entity: impl Into<Entity>) -> EntityView<'_>
pub fn make_alive(&self, entity: impl Into<Entity>) -> EntityView<'_>
Sourcepub fn run_post_frame(&self, action: ecs_fini_action_t, ctx: *mut c_void)
pub fn run_post_frame(&self, action: ecs_fini_action_t, ctx: *mut c_void)
Sourcepub fn entity_from_enum<T>(&self, enum_value: T) -> EntityView<'_>
pub fn entity_from_enum<T>(&self, enum_value: T) -> EntityView<'_>
Sourcepub fn entity_from_named<'a, T: ComponentId>(
&'a self,
name: &str,
) -> EntityView<'a>
pub fn entity_from_named<'a, T: ComponentId>( &'a self, name: &str, ) -> EntityView<'a>
Sourcepub fn entity_from<T: ComponentId>(&self) -> EntityView<'_>
pub fn entity_from<T: ComponentId>(&self) -> EntityView<'_>
Sourcepub fn entity_named(&self, name: &str) -> EntityView<'_>
pub fn entity_named(&self, name: &str) -> EntityView<'_>
Create an entity that’s associated with a name.
The name does an extra allocation if it’s bigger than 24 bytes. To avoid this, use entity_named_cstr
.
length of 24 bytes: "hi this is 24 bytes long"
Named entities can be looked up with the lookup functions. Entity names
may be scoped, where each element in the name is separated by “::”.
For example: “Foo::Bar
”. If parts of the hierarchy in the scoped name do
not yet exist, they will be automatically created.
§Example
use flecs_ecs::prelude::*;
let world = World::new();
let entity = world.entity_named("Foo");
assert_eq!(entity.get_name(), Some("Foo"));
§See also
World::entity()
World::entity_named_cstr()
- C++ API:
world::entity
Examples found in repository?
11fn main() {
12 let world = World::new();
13 // Create a few test entities for a Position query
14 world.entity_named("e1").set(Position { x: 10.0, y: 20.0 });
15
16 world.entity_named("e2").set(Position { x: 20.0, y: 30.0 });
17
18 // Create a simple query for component Position
19 let query = world.new_query::<&Position>();
20
21 let entity: Option<EntityView> = query.find(|pos| (pos.x - 20.0).abs() < f32::EPSILON);
22
23 if let Some(entity) = entity {
24 println!("Entity found: {:?}", entity.path().unwrap());
25 } else {
26 println!("Entity not found");
27 }
28
29 // Output:
30 // Entity found: "::e2"
31}
More examples
18fn main() {
19 let world = World::new();
20
21 // Create existing entities with Position component
22 world.entity_named("e1").set(Position { x: 10.0, y: 20.0 });
23 world.entity_named("e2").set(Position { x: 20.0, y: 30.0 });
24
25 // Create an observer for three events
26 world
27 .observer::<flecs::OnSet, &Position>()
28 .yield_existing()
29 .each_iter(|it, index, pos| {
30 println!(
31 " - {}: {}: {}: {{ {}, {} }}",
32 it.event().name(),
33 it.event_id().to_str(),
34 it.entity(index),
35 pos.x,
36 pos.y
37 );
38 });
39
40 // Output:
41 // - OnSet: Position: e1: { 10, 20 }
42 // - OnSet: Position: e2: { 20, 30 }
43}
14fn main() {
15 let world = World::new();
16
17 world
18 .component::<Position>()
19 .on_add(|entity, _pos| {
20 println!("added Position to {:?}", entity.name());
21 })
22 .on_remove(|entity, pos| {
23 println!("removed {:?} from {:?}", pos, entity.name());
24 })
25 .on_set(|entity, pos| {
26 println!("set {:?} for {:?}", pos, entity.name());
27 });
28
29 let entity = world.entity_named("Bob");
30
31 entity.set(Position { x: 10.0, y: 20.0 });
32
33 // This operation changes the entity's archetype, which invokes a move
34 // add is used for adding tags.
35 entity.add::<Tag>();
36
37 entity.destruct();
38
39 // Output:
40 // added Position { x: 0.0, y: 0.0 } to "Bob"
41 // set Position { x: 10.0, y: 20.0 } for "Bob"
42 // removed Position { x: 10.0, y: 20.0 } from "Bob"
43}
14fn main() {
15 let world = World::new();
16
17 // Create an observer for the custom event
18 world
19 .observer::<MyEvent, &Position>()
20 .each_iter(|it, index, _pos| {
21 println!(
22 " - {}: {}: {}",
23 it.event().name(),
24 it.event_id().to_str(),
25 it.entity(index)
26 );
27 });
28
29 // The observer query can be matched against the entity, so make sure it
30 // has the Position component before emitting the event. This does not
31 // trigger the observer yet.
32 let entity = world.entity_named("e1").set(Position { x: 10.0, y: 20.0 });
33
34 // Emit the custom event. This triggers the observer.
35 world
36 .event()
37 .add::<Position>()
38 .entity(entity)
39 .emit(&MyEvent);
40
41 // Output:
42 // - MyEvent: Position: e1
43}
21fn main() {
22 let world = World::new();
23
24 // Create observer for custom event
25 world
26 .observer::<flecs::OnSet, (&Position, &Velocity)>()
27 .each_iter(|it, index, (pos, vel)| {
28 println!(
29 " - {}: {}: {}: p: {{ {}, {} }}, v: {{ {}, {} }}",
30 it.event().name(),
31 it.event_id().to_str(),
32 it.entity(index).name(),
33 pos.x,
34 pos.y,
35 vel.x,
36 vel.y
37 );
38 });
39
40 // Create entity, set Position (emits EcsOnSet, does not yet match observer)
41 let entity = world.entity_named("e").set(Position { x: 10.0, y: 20.0 });
42
43 // Set Velocity (emits EcsOnSet, matches observer)
44 entity.set(Velocity { x: 1.0, y: 2.0 });
45
46 // Output:
47 // - OnSet: Velocity: e: p: { 10, 20 }, v: { 1, 2 }
48}
17fn main() {
18 let world = World::new();
19
20 // Create a query that matches edible components
21 let query = world.new_query::<&(EatsAmount, flecs::Wildcard)>();
22
23 // Create a few entities that match the query
24 world
25 .entity_named("Bob")
26 .set_pair::<EatsAmount, Apples>(EatsAmount { amount: 10 })
27 .set_pair::<EatsAmount, Pears>(EatsAmount { amount: 5 });
28
29 world
30 .entity_named("Alice")
31 .set_pair::<EatsAmount, Apples>(EatsAmount { amount: 4 });
32
33 // Iterate the query with a flecs::iter. This makes it possible to inspect
34 // the pair that we are currently matched with.
35 query.each_iter(|it, index, eats| {
36 let entity = it.entity(index);
37 let pair = it.pair(0).unwrap();
38 let food = pair.second_id();
39
40 println!("{} eats {} {}", entity, eats.amount, food);
41 });
42
43 // Output:
44 // Alice eats 4 Apples
45 // Bob eats 10 Apples
46 // Bob eats 5 Pears
47}
- examples/flecs/queries/query_singleton.rs
- examples/flecs/systems/system_basics.rs
- examples/flecs/queries/query_world_query.rs
- examples/flecs/prefabs/prefab_typed.rs
- examples/flecs/prefabs/prefab_hierarchy.rs
- examples/flecs/systems/system_pipeline.rs
- examples/flecs/observers/observer_monitor.rs
- examples/flecs/queries/query_with.rs
- examples/flecs/observers/observer_propagate.rs
- examples/flecs/systems/system_custom_runner.rs
- examples/flecs/queries/query_without.rs
- examples/flecs/entities/entity_iterate_components.rs
- examples/flecs/prefabs/prefab_basics.rs
- examples/flecs/queries/query_component_inheritance.rs
- examples/flecs/prefabs/prefab_nested.rs
- examples/flecs/observers/observer_basics.rs
- examples/flecs/prefabs/prefab_slots.rs
- examples/flecs/relationships/relationships_union.rs
- examples/flecs/observers/observer_entity_event.rs
- examples/flecs/entities/entity_basics.rs
- examples/flecs/hello_world.rs
- examples/flecs/entities/entity_hierarchy.rs
- examples/flecs/queries/query_variables.rs
- examples/flecs/queries/query_basics.rs
- examples/flecs/prefabs/prefab_override.rs
- examples/flecs/systems/system_mutate_entity.rs
- examples/flecs/prefabs/prefab_variant.rs
- examples/flecs/queries/query_hierarchy.rs
- examples/flecs/relationships/relationships_basics.rs
- examples/flecs/queries/query_cyclic_variables.rs
- examples/flecs/queries/query_facts.rs
- examples/flecs/queries/query_run_iter.rs
- examples/flecs/queries/query_instancing.rs
- examples/flecs/systems/system_sync_point.rs
- examples/flecs/entities/entity_prefab.rs
- examples/flecs/systems/system_mutate_entity_handle.rs
- examples/flecs/queries/query_transitive_queries.rs
- examples/flecs/systems/system_sync_point_delete.rs
- examples/flecs/queries/query_setting_variables.rs
- examples/flecs/queries/query_change_tracking.rs
Sourcepub fn entity_named_cstr(&self, name: &CStr) -> EntityView<'_>
pub fn entity_named_cstr(&self, name: &CStr) -> EntityView<'_>
Create an entity that’s associated with a name. The name must be a valid C str. No extra allocation is done.
Named entities can be looked up with the lookup functions. Entity names
may be scoped, where each element in the name is separated by “::”.
For example: “Foo::Bar
”. If parts of the hierarchy in the scoped name do
not yet exist, they will be automatically created.
§Example
use flecs_ecs::prelude::*;
let world = World::new();
let entity = world.entity_named("Foo");
assert_eq!(entity.get_name(), Some("Foo"));
§See also
World::entity()
World::entity_named()
- C++ API:
world::entity
Sourcepub fn entity(&self) -> EntityView<'_>
pub fn entity(&self) -> EntityView<'_>
Create a new entity.
§See also
World::entity_named()
World::entity_named_cstr()
- C++ API:
world::entity
Examples found in repository?
7fn main() {
8 let world = World::new();
9
10 // Register TradesWith as symmetric relationship. Symmetric relationships
11 // go both ways, adding (R, B) to A will also add (R, A) to B.
12 world.component::<TradesWith>().add::<flecs::Symmetric>();
13
14 // Create two players
15 let player_1 = world.entity();
16 let player_2 = world.entity();
17
18 // Add (TradesWith, player_2) to player_1. This also adds
19 // (TradesWith, player_1) to player_2.
20 player_1.add_first::<TradesWith>(player_2);
21
22 // Log platoon of unit
23 println!(
24 "Player 1 trades with Player 2: {}",
25 player_1.has_first::<TradesWith>(player_2)
26 ); // true
27 println!(
28 "Player 2 trades with Player 1: {}",
29 player_2.has_first::<TradesWith>(player_1)
30 ); // true
31
32 // Output:
33 // Player 1 trades with Player 2: true
34 // Player 2 trades with Player 1: true
35}
More examples
15fn main() {
16 let world = World::new();
17
18 // Create three custom phases. Note that the phases have the Phase tag,
19 // which is necessary for the builtin pipeline to discover which systems it
20 // should run.
21
22 let update = world.entity().add::<flecs::pipeline::Phase>();
23
24 let physics = world
25 .entity()
26 .add::<flecs::pipeline::Phase>()
27 .depends_on_id(update);
28
29 let collisions = world
30 .entity()
31 .add::<flecs::pipeline::Phase>()
32 .depends_on_id(physics);
33
34 // Create 3 dummy systems.
35 world
36 .system_named::<()>("CollisionSystem")
37 .kind_id(collisions)
38 .run(sys);
39
40 world
41 .system_named::<()>("PhysicsSystem")
42 .kind_id(physics)
43 .run(sys);
44
45 world
46 .system_named::<()>("GameSystem")
47 .kind_id(update)
48 .run(sys);
49
50 // Run pipeline
51 world.progress();
52
53 // Output:
54 // system GameSystem
55 // system PhysicsSystem
56 // system CollisionSystem
57}
15fn main() {
16 let world = World::new();
17
18 // Create two custom phases that branch off of EcsOnUpdate. Note that the
19 // phases have the Phase tag, which is necessary for the builtin pipeline
20 // to discover which systems it should run.
21 let physics = world
22 .entity()
23 .add::<flecs::pipeline::Phase>()
24 .depends_on::<flecs::pipeline::OnUpdate>();
25
26 let collisions = world
27 .entity()
28 .add::<flecs::pipeline::Phase>()
29 .depends_on_id(physics);
30
31 // Create 3 dummy systems.
32 world
33 .system_named::<()>("CollisionSystem")
34 .kind_id(collisions)
35 .run(sys);
36
37 world
38 .system_named::<()>("PhysicsSystem")
39 .kind_id(physics)
40 .run(sys);
41
42 world
43 .system_named::<()>("GameSystem")
44 .kind::<flecs::pipeline::OnUpdate>()
45 .run(sys);
46
47 // Run pipeline
48 world.progress();
49
50 // Output:
51 // system GameSystem
52 // system PhysicsSystem
53 // system CollisionSystem
54}
8fn main() {
9 let world = World::new();
10
11 // Register Platoon as exclusive relationship. This ensures that an entity
12 // can only belong to a single Platoon.
13 world.component::<Platoon>().add::<flecs::Exclusive>();
14
15 // Create two platoons
16 let platoon_1 = world.entity();
17 let platoon_2 = world.entity();
18
19 // Create a unit
20 let unit = world.entity();
21
22 // Add unit to platoon 1
23 unit.add_first::<Platoon>(platoon_1);
24
25 // Log platoon of unit
26 println!(
27 "Unit in platoon 1: {}",
28 unit.has_first::<Platoon>(platoon_1)
29 ); // true
30 println!(
31 "Unit in platoon 2: {}",
32 unit.has_first::<Platoon>(platoon_2)
33 ); // false
34
35 println!();
36
37 // Add unit to platoon 2. Because Platoon is an exclusive relationship, this
38 // both removes (Platoon, platoon_1) and adds (Platoon, platoon_2) in a
39 // single operation.
40 unit.add_first::<Platoon>(platoon_2);
41
42 // Log platoon of unit
43 println!(
44 "Unit in platoon 1: {}",
45 unit.has_first::<Platoon>(platoon_1)
46 ); // false
47 println!(
48 "Unit in platoon 2: {}",
49 unit.has_first::<Platoon>(platoon_2)
50 ); // true
51
52 // Output:
53 // Unit in platoon 1: true
54 // Unit in platoon 2: false
55 //
56 // Unit in platoon 1: false
57 // Unit in platoon 2: true
58}
43fn main() {
44 let world = World::new();
45
46 // Applications can pass context data to a system. A common use case where this
47 // comes in handy is when a system needs to iterate more than one query. The
48 // following example shows how to pass a custom query into a system for a simple
49 // collision detection example.
50
51 let mut query_collide = world.new_query::<(&Position, &Radius)>();
52
53 let sys = world
54 .system::<(&Position, &Radius)>()
55 .set_context(&mut query_collide as *mut Query<(&Position, &Radius)> as *mut c_void)
56 .each_iter(|mut it, index, (p1, r1)| {
57 let query = unsafe { it.context::<Query<(&Position, &Radius)>>() };
58 let e1 = it.entity(index);
59
60 query.each_entity(|e2, (p2, r2)| {
61 if e1 == *e2 {
62 // don't collide with self
63 return;
64 }
65
66 if e1 > *e2 {
67 // Simple trick to prevent collisions from being detected
68 // twice with the entities reversed.
69 return;
70 }
71
72 // Check for collision
73 let d_sqr = distance_sqr(p1, p2);
74 let r_sqr = sqr(r1.value + r2.value);
75 if r_sqr > d_sqr {
76 println!("{} and {} collided!", e1, e2);
77 }
78 });
79 });
80
81 // Create a few test entities
82 for _ in 0..10 {
83 world
84 .entity()
85 .set(Position {
86 x: rand(50),
87 y: rand(50),
88 })
89 .set(Radius {
90 value: rand(10) + 1.0,
91 });
92 }
93
94 // Run the system
95 sys.run();
96
97 // Output:
98 // 532 and 539 collided!
99 // 532 and 540 collided!
100 // 534 and 538 collided!
101 // 536 and 537 collided!
102 // 536 and 540 collided!
103 // 537 and 540 collided!
104}
26fn main() {
27 let world = World::new();
28
29 world.component::<First>();
30 world.component::<Second>();
31 world.component::<Third>();
32
33 let query = world.query::<&Position>().group_by::<Group>().build();
34
35 world
36 .entity()
37 .add::<(Group, Third)>()
38 .set(Position { x: 1.0, y: 1.0 });
39 world
40 .entity()
41 .add::<(Group, Second)>()
42 .set(Position { x: 2.0, y: 2.0 });
43 world
44 .entity()
45 .add::<(Group, First)>()
46 .set(Position { x: 3.0, y: 3.0 });
47
48 world
49 .entity()
50 .add::<(Group, Third)>()
51 .set(Position { x: 4.0, y: 4.0 })
52 .add::<Tag>();
53 world
54 .entity()
55 .add::<(Group, Second)>()
56 .set(Position { x: 5.0, y: 5.0 })
57 .add::<Tag>();
58 world
59 .entity()
60 .add::<(Group, First)>()
61 .set(Position { x: 6.0, y: 6.0 })
62 .add::<Tag>();
63
64 println!();
65
66 query.run_iter(|it, pos| {
67 let group = world.entity_from_id(it.group_id());
68 println!(
69 "Group: {:?} - Table: [{:?}]",
70 group.path().unwrap(),
71 it.archetype()
72 );
73
74 for i in it.iter() {
75 println!(" [{:?}]", pos[i]);
76 }
77
78 println!();
79 });
80
81 // Output:
82 // Group: "::First" - Table: [Position, (Group,First)]
83 // [Position { x: 3.0, y: 3.0 }]
84 //
85 // Group: "::First" - Table: [Position, Tag, (Group,First)]
86 // [Position { x: 6.0, y: 6.0 }]
87 //
88 // Group: "::Second" - Table: [Position, (Group,Second)]
89 // [Position { x: 2.0, y: 2.0 }]
90 //
91 // Group: "::Second" - Table: [Position, Tag, (Group,Second)]
92 // [Position { x: 5.0, y: 5.0 }]
93 //
94 // Group: "::Third" - Table: [Position, (Group,Third)]
95 // [Position { x: 1.0, y: 1.0 }]
96 //
97 // Group: "::Third" - Table: [Position, Tag, (Group,Third)]
98 // [Position { x: 4.0, y: 4.0 }]
99}
- examples/flecs/queries/query_sorting.rs
- examples/flecs/queries/query_chaining_queries.rs
- examples/flecs/relationships/relationships_component_data.rs
- examples/flecs/queries/query_group_by_custom.rs
- examples/flecs/queries/query_group_iter.rs
- examples/flecs/relationships/relationships_enum.rs
- examples/flecs/queries/query_group_by_callbacks.rs
- examples/flecs/queries/query_setting_variables.rs
Sourcepub fn entity_null(&self) -> EntityView<'_>
pub fn entity_null(&self) -> EntityView<'_>
Sourcepub fn entity_from_id(&self, id: impl Into<Entity>) -> EntityView<'_>
pub fn entity_from_id(&self, id: impl Into<Entity>) -> EntityView<'_>
Create a new entity with the provided id.
§Arguments
id
- The id to use for the new entity.
§See also
- C++ API:
world::entity
Examples found in repository?
36extern "C" fn callback_group_create(
37 world: *mut sys::ecs_world_t,
38 group_id: u64,
39 _group_by_ctx: *mut c_void,
40) -> *mut c_void {
41 let world_ref = unsafe { WorldRef::from_ptr(world) };
42 println!(
43 "Group created: {:?}",
44 world_ref.world().entity_from_id(group_id).name()
45 );
46
47 println!();
48
49 let mut counter = GROUP_COUNTER.lock().unwrap();
50 *counter += 1;
51
52 // Return data that will be associated with the group
53 let ctx = Box::new(GroupCtx { counter: *counter });
54
55 Box::into_raw(ctx) as *mut std::ffi::c_void // Cast to make sure function type matches
56}
57
58// callbacks need to be extern "C" to be callable from C
59extern "C" fn callback_group_delete(
60 world: *mut sys::ecs_world_t,
61 group_id: u64,
62 _ctx: *mut c_void,
63 _group_by_ctx: *mut c_void,
64) {
65 let world_ref = unsafe { WorldRef::from_ptr(world) };
66 println!(
67 "Group deleted: {:?}",
68 world_ref.world().entity_from_id(group_id).name()
69 );
70
71 // if you have any data associated with the group, you need to free it
72 // or use the callback group_by_ctx where you pass a context to the callback
73}
74
75fn main() {
76 let world = World::new();
77
78 // Register components in order so that id for First is lower than Third
79 world.component::<First>();
80 world.component::<Second>();
81 world.component::<Third>();
82
83 // Grouped query
84 let query = world
85 .query::<(&Position,)>()
86 .group_by::<Group>()
87 // Callback invoked when a new group is created
88 .on_group_create(Some(callback_group_create))
89 // Callback invoked when a group is deleted
90 .on_group_delete(Some(callback_group_delete))
91 .build();
92
93 // Create entities in 6 different tables with 3 group ids
94 world
95 .entity()
96 .add::<(Group, Third)>()
97 .set(Position { x: 1.0, y: 1.0 });
98 world
99 .entity()
100 .add::<(Group, Second)>()
101 .set(Position { x: 2.0, y: 2.0 });
102 world
103 .entity()
104 .add::<(Group, First)>()
105 .set(Position { x: 3.0, y: 3.0 });
106
107 world
108 .entity()
109 .add::<(Group, Third)>()
110 .set(Position { x: 4.0, y: 4.0 })
111 .add::<Tag>();
112 world
113 .entity()
114 .add::<(Group, Second)>()
115 .set(Position { x: 5.0, y: 5.0 })
116 .add::<Tag>();
117 world
118 .entity()
119 .add::<(Group, First)>()
120 .set(Position { x: 6.0, y: 6.0 })
121 .add::<Tag>();
122
123 println!();
124
125 // The query cache now looks like this:
126 // - group First:
127 // - table [Position, (Group, First)]
128 // - table [Position, Tag, (Group, First)]
129 //
130 // - group Second:
131 // - table [Position, (Group, Second)]
132 // - table [Position, Tag, (Group, Second)]
133 //
134 // - group Third:
135 // - table [Position, (Group, Third)]
136 // - table [Position, Tag, (Group, Third)]
137 //
138
139 query.run_iter(|it, (pos,)| {
140 let group = world.entity_from_id(it.group_id());
141 let ctx = unsafe { &*(query.group_context(group) as *mut GroupCtx) };
142 println!(
143 "Group: {:?} - Table: [{:?}] - Counter: {}",
144 group.path().unwrap(),
145 it.archetype(),
146 ctx.counter
147 );
148
149 for i in it.iter() {
150 println!(" [{:?}]", pos[i]);
151 }
152
153 println!();
154 });
155
156 // Deleting the query will call the on_group_deleted callback
157 query.destruct();
158
159 // Output:
160 // Group created: "Third"
161 // Group created: "Second"
162 // Group created: "First"
163 //
164 // Group: "::First" - Table: [Position, (Group,First)] - Counter: 3
165 // [Position { x: 3.0, y: 3.0 }]
166 //
167 // Group: "::First" - Table: [Position, Tag, (Group,First)] - Counter: 3
168 // [Position { x: 6.0, y: 6.0 }]
169 //
170 // Group: "::Second" - Table: [Position, (Group,Second)] - Counter: 2
171 // [Position { x: 2.0, y: 2.0 }]
172 //
173 // Group: "::Second" - Table: [Position, Tag, (Group,Second)] - Counter: 2
174 // [Position { x: 5.0, y: 5.0 }]
175 //
176 // Group: "::Third" - Table: [Position, (Group,Third)] - Counter: 1
177 // [Position { x: 1.0, y: 1.0 }]
178 //
179 // Group: "::Third" - Table: [Position, Tag, (Group,Third)] - Counter: 1
180 // [Position { x: 4.0, y: 4.0 }]
181 //
182 // Group deleted: "Second"
183 // Group deleted: "First"
184 // Group deleted: "Third"
185}
More examples
26fn main() {
27 let world = World::new();
28
29 world.component::<First>();
30 world.component::<Second>();
31 world.component::<Third>();
32
33 let query = world.query::<&Position>().group_by::<Group>().build();
34
35 world
36 .entity()
37 .add::<(Group, Third)>()
38 .set(Position { x: 1.0, y: 1.0 });
39 world
40 .entity()
41 .add::<(Group, Second)>()
42 .set(Position { x: 2.0, y: 2.0 });
43 world
44 .entity()
45 .add::<(Group, First)>()
46 .set(Position { x: 3.0, y: 3.0 });
47
48 world
49 .entity()
50 .add::<(Group, Third)>()
51 .set(Position { x: 4.0, y: 4.0 })
52 .add::<Tag>();
53 world
54 .entity()
55 .add::<(Group, Second)>()
56 .set(Position { x: 5.0, y: 5.0 })
57 .add::<Tag>();
58 world
59 .entity()
60 .add::<(Group, First)>()
61 .set(Position { x: 6.0, y: 6.0 })
62 .add::<Tag>();
63
64 println!();
65
66 query.run_iter(|it, pos| {
67 let group = world.entity_from_id(it.group_id());
68 println!(
69 "Group: {:?} - Table: [{:?}]",
70 group.path().unwrap(),
71 it.archetype()
72 );
73
74 for i in it.iter() {
75 println!(" [{:?}]", pos[i]);
76 }
77
78 println!();
79 });
80
81 // Output:
82 // Group: "::First" - Table: [Position, (Group,First)]
83 // [Position { x: 3.0, y: 3.0 }]
84 //
85 // Group: "::First" - Table: [Position, Tag, (Group,First)]
86 // [Position { x: 6.0, y: 6.0 }]
87 //
88 // Group: "::Second" - Table: [Position, (Group,Second)]
89 // [Position { x: 2.0, y: 2.0 }]
90 //
91 // Group: "::Second" - Table: [Position, Tag, (Group,Second)]
92 // [Position { x: 5.0, y: 5.0 }]
93 //
94 // Group: "::Third" - Table: [Position, (Group,Third)]
95 // [Position { x: 1.0, y: 1.0 }]
96 //
97 // Group: "::Third" - Table: [Position, Tag, (Group,Third)]
98 // [Position { x: 4.0, y: 4.0 }]
99}
46fn main() {
47 let world = World::new();
48
49 // Register components in order so that id for First is lower than Third
50 world.component::<First>();
51 world.component::<Second>();
52 world.component::<Third>();
53
54 // Grouped query
55 let query = world
56 .query::<&Position>()
57 .group_by_fn::<Group>(Some(callback_group_by_relationship))
58 .build();
59
60 // Create entities in 6 different tables with 3 group ids
61 world
62 .entity()
63 .add::<(Group, Third)>()
64 .set(Position { x: 1.0, y: 1.0 });
65 world
66 .entity()
67 .add::<(Group, Second)>()
68 .set(Position { x: 2.0, y: 2.0 });
69 world
70 .entity()
71 .add::<(Group, First)>()
72 .set(Position { x: 3.0, y: 3.0 });
73
74 world
75 .entity()
76 .add::<(Group, Third)>()
77 .set(Position { x: 4.0, y: 4.0 })
78 .add::<Tag>();
79 world
80 .entity()
81 .add::<(Group, Second)>()
82 .set(Position { x: 5.0, y: 5.0 })
83 .add::<Tag>();
84 world
85 .entity()
86 .add::<(Group, First)>()
87 .set(Position { x: 6.0, y: 6.0 })
88 .add::<Tag>();
89
90 println!();
91
92 // The query cache now looks like this:
93 // - group First:
94 // - table [Position, (Group, First)]
95 // - table [Position, Tag, (Group, First)]
96 //
97 // - group Second:
98 // - table [Position, (Group, Second)]
99 // - table [Position, Tag, (Group, Second)]
100 //
101 // - group Third:
102 // - table [Position, (Group, Third)]
103 // - table [Position, Tag, (Group, Third)]
104 //
105
106 query.run_iter(|it, pos| {
107 let group = world.entity_from_id(it.group_id());
108 println!(
109 "Group: {:?} - Table: [{:?}]",
110 group.path().unwrap(),
111 it.archetype()
112 );
113
114 for i in it.iter() {
115 println!(" [{:?}]", pos[i]);
116 }
117
118 println!();
119 });
120
121 // Output:
122 // Group: "::First" - Table: [Position, (Group,First)]
123 // [Position { x: 3.0, y: 3.0 }]
124 //
125 // Group: "::First" - Table: [Position, Tag, (Group,First)]
126 // [Position { x: 6.0, y: 6.0 }]
127 //
128 // Group: "::Second" - Table: [Position, (Group,Second)]
129 // [Position { x: 2.0, y: 2.0 }]
130 //
131 // Group: "::Second" - Table: [Position, Tag, (Group,Second)]
132 // [Position { x: 5.0, y: 5.0 }]
133 //
134 // Group: "::Third" - Table: [Position, (Group,Third)]
135 // [Position { x: 1.0, y: 1.0 }]
136 //
137 // Group: "::Third" - Table: [Position, Tag, (Group,Third)]
138 // [Position { x: 4.0, y: 4.0 }]
139}
52fn main() {
53 let world = World::new();
54
55 // Create npc's in world cell 0_0
56 world
57 .entity()
58 .add::<(WorldCell, Cell_0_0)>()
59 .add::<Merchant>()
60 .add::<Npc>();
61 world
62 .entity()
63 .add::<(WorldCell, Cell_0_0)>()
64 .add::<Merchant>()
65 .add::<Npc>();
66
67 // Create npc's in world cell 0_1
68 world
69 .entity()
70 .add::<(WorldCell, Cell_0_1)>()
71 .add::<Beggar>()
72 .add::<Npc>();
73 world
74 .entity()
75 .add::<(WorldCell, Cell_0_1)>()
76 .add::<Soldier>()
77 .add::<Npc>();
78
79 // Create npc's in world cell 1_0
80 world
81 .entity()
82 .add::<(WorldCell, Cell_1_0)>()
83 .add::<Mage>()
84 .add::<Npc>();
85 world
86 .entity()
87 .add::<(WorldCell, Cell_1_0)>()
88 .add::<Beggar>()
89 .add::<Npc>();
90
91 // Create npc's in world cell 1_1
92 world
93 .entity()
94 .add::<(WorldCell, Cell_1_1)>()
95 .add::<Soldier>()
96 .add::<Npc>();
97
98 let mut query = world
99 .query::<()>()
100 .with::<&Npc>()
101 .group_by::<WorldCell>()
102 .build();
103
104 // Iterate all tables
105 println!("All tables");
106
107 query.run(|mut iter| {
108 while iter.next() {
109 let group = world.entity_from_id(iter.group_id());
110 println!(
111 "group: {:?} - Table [{}]",
112 group.path().unwrap(),
113 iter.table().unwrap().to_string().unwrap()
114 );
115 }
116 });
117
118 println!();
119
120 println!("Tables for cell 1_0:");
121
122 query.set_group::<Cell_1_0>().run(|mut iter| {
123 while iter.next() {
124 let world = iter.world();
125 let group = world.entity_from_id(iter.group_id());
126 println!(
127 "group: {:?} - Table [{}]",
128 group.path().unwrap(),
129 iter.table().unwrap().to_string().unwrap()
130 );
131 }
132 });
133
134 // Output:
135 // All tables
136 // group: "::Cell_0_0" - Table [Merchant, Npc, (WorldCell,Cell_0_0)]
137 // group: "::Cell_0_1" - Table [Npc, Beggar, (WorldCell,Cell_0_1)]
138 // group: "::Cell_0_1" - Table [Npc, Soldier, (WorldCell,Cell_0_1)]
139 // group: "::Cell_1_0" - Table [Npc, Mage, (WorldCell,Cell_1_0)]
140 // group: "::Cell_1_0" - Table [Npc, Beggar, (WorldCell,Cell_1_0)]
141 // group: "::Cell_1_1" - Table [Npc, Soldier, (WorldCell,Cell_1_1)]
142
143 // Tables for cell 1_0:
144 // group: "::Cell_1_0" - Table [Npc, Mage, (WorldCell,Cell_1_0)]
145 // group: "::Cell_1_0" - Table [Npc, Beggar, (WorldCell,Cell_1_0)]
146}
Sourcepub fn prefab(&self) -> EntityView<'_>
pub fn prefab(&self) -> EntityView<'_>
Creates a prefab
§Returns
The prefab entity.
§See also
World::prefab_named()
World::prefab_type()
World::prefab_type_named()
- C++ API:
world::prefab
Sourcepub fn prefab_named<'a>(&'a self, name: &str) -> EntityView<'a>
pub fn prefab_named<'a>(&'a self, name: &str) -> EntityView<'a>
Creates a named prefab
§Arguments
name
- The name to use for the new prefab.
§Returns
The prefab entity.
§See also
World::prefab()
World::prefab_type()
World::prefab_type_named()
- C++ API:
world::prefab
Examples found in repository?
7fn main() {
8 let world = World::new();
9
10 // Create a prefab hierarchy.
11 let spaceship = world.prefab_named("SpaceShip");
12 world.prefab_named("Engine").child_of_id(spaceship);
13 world.prefab_named("Cockpit").child_of_id(spaceship);
14
15 // Instantiate the prefab. This also creates an Engine and Cockpit child
16 // for the instance.
17 let inst = world.entity_named("my_spaceship").is_a_id(spaceship);
18
19 // Because of the IsA relationship, the instance now has the Engine and Cockpit
20 // children of the prefab. This means that the instance can look up the Engine
21 // and Cockpit entities.
22 if let Some(inst_engine) = inst.try_lookup_recursive("Engine") {
23 if let Some(inst_cockpit) = inst.try_lookup_recursive("Cockpit") {
24 println!("instance engine: {:?}", inst_engine.path().unwrap());
25 println!("instance cockpit: {:?}", inst_cockpit.path().unwrap());
26 } else {
27 println!("entity lookup failed");
28 }
29 }
30
31 // Output:
32 // instance engine: "::my_spaceship::Engine"
33 // instance cockpit: "::my_spaceship::Cockpit"
34}
More examples
28fn main() {
29 let world = World::new();
30
31 // Add the traits to mark the component to be inherited
32 world
33 .component::<Defence>()
34 .add_trait::<(flecs::OnInstantiate, flecs::Inherit)>();
35
36 // Create a prefab with Position and Velocity components
37 let spaceship = world.prefab_named("Prefab").set(Defence { value: 50.0 });
38
39 // Create a prefab instance
40 let inst = world.entity_named("my_spaceship").is_a_id(spaceship);
41
42 // Because of the IsA relationship, the instance now shares the Defense
43 // component with the prefab, and can be retrieved as a regular component:
44 inst.try_get::<&Defence>(|d_inst| {
45 println!("{:?}", d_inst);
46 // Because the component is shared, changing the value on the prefab will
47 // also change the value for the instance:
48 // this is safe during a table lock because it also has the component and won't cause the table to move.
49 spaceship.set(Defence { value: 100.0 });
50 println!("after set: {:?}", d_inst);
51 });
52
53 // Prefab components can be iterated like regular components:
54 world.each_entity::<&Defence>(|entity, d| {
55 println!("{}: defence: {}", entity.path().unwrap(), d.value);
56 });
57
58 // Output:
59 // Defence { value: 50.0 }
60 // after set: Defence { value: 100.0 }
61 // ::my_spaceship: 100
62}
23fn main() {
24 let world = World::new();
25
26 // Creates a wheel prefab
27 let wheel = world.prefab_named("Wheel");
28 wheel.set(TirePressure { value: 32.0 });
29
30 // Create a Car prefab with four wheels. Note how we're using the scope
31 // method, which has the same effect as adding the (ChildOf, Car) pair.
32 let car = world.prefab_named("Car");
33 car.run_in_scope(|| {
34 world.prefab_named("FrontLeft").is_a_id(wheel);
35
36 world.prefab_named("FrontRight").is_a_id(wheel);
37
38 world.prefab_named("BackLeft").is_a_id(wheel);
39
40 world.prefab_named("BackRight").is_a_id(wheel);
41 });
42
43 // Create a prefab instance.
44 let inst_car = world.entity_named("my_car");
45 inst_car.is_a_id(car);
46
47 // Lookup one of the wheels
48 if let Some(inst) = inst_car.try_lookup_recursive("FrontLeft") {
49 // The type shows that the child has a private copy of the TirePressure
50 // component, and an IsA relationship to the Wheel prefab.
51 println!("{:?}", inst.archetype());
52
53 // Get the TirePressure component & print its value
54 inst.try_get::<Option<&TirePressure>>(|p| {
55 if let Some(p) = p {
56 println!("pressure: {}", p.value);
57 }
58 });
59 } else {
60 println!("entity lookup failed");
61 }
62
63 // Output:
64 // TirePressure, (Identifier,Name), (ChildOf,my_car), (IsA,Wheel)
65 // pressure: 32
66}
27fn main() {
28 let world = World::new();
29
30 // Create the same prefab hierarchy as from the hierarchy example, but now
31 // with the SlotOf relationship.
32 let spaceship = world.prefab_named("SpaceShip");
33 let engine = world
34 .prefab_named("Engine")
35 .child_of_id(spaceship)
36 .slot_of_id(spaceship);
37
38 let cockpit = world
39 .prefab_named("Cockpit")
40 .child_of_id(spaceship)
41 .slot_of_id(spaceship);
42
43 // Add an additional child to the Cockpit prefab to demonstrate how
44 // slots can be different from the parent. This slot could have been
45 // added to the Cockpit prefab, but instead we register it on the top
46 // level SpaceShip prefab.
47
48 let pilot_seat = world
49 .prefab_named("PilotSeat")
50 .child_of_id(cockpit)
51 .slot_of_id(spaceship);
52
53 // Create a prefab instance.
54 let inst = world.entity_named("my_spaceship").is_a_id(spaceship);
55
56 // Get the instantiated entities for the prefab slots
57 let inst_engine = inst.target_id(engine, 0).unwrap();
58 let inst_cockpit = inst.target_id(cockpit, 0).unwrap();
59 let inst_seat = inst.target_id(pilot_seat, 0).unwrap();
60
61 println!("instance engine: {}", inst_engine.path().unwrap());
62
63 println!("instance cockpit: {}", inst_cockpit.path().unwrap());
64
65 println!("instance seat: {}", inst_seat.path().unwrap());
66
67 // Output:
68 // instance engine: ::my_spaceship::Engine
69 // instance cockpit: ::my_spaceship::Cockpit
70 // instance seat: ::my_spaceship::Cockpit::PilotSeat
71}
36fn main() {
37 let world = World::new();
38
39 // Add the traits to mark the components to be inherited
40 world
41 .component::<Defence>()
42 .add_trait::<(flecs::OnInstantiate, flecs::Inherit)>();
43 world
44 .component::<Attack>()
45 .add_trait::<(flecs::OnInstantiate, flecs::Inherit)>();
46
47 // Attack and Damage are properties that can be shared across many
48 // spaceships. This saves memory, and speeds up prefab creation as we don't
49 // have to copy the values of Attack and Defense to private components.
50 let spaceship = world
51 .prefab_named("SpaceShip")
52 .set(Attack { value: 75.0 })
53 .set(Defence { value: 100.0 })
54 .set(Damage { value: 50.0 });
55
56 // Create a prefab instance.
57 let inst = world.entity_named("my_spaceship").is_a_id(spaceship);
58
59 // The entity will now have a private copy of the Damage component, but not
60 // of the Attack and Defense components. We can see this when we look at the
61 // type of the instance:
62 println!("{}", inst.archetype());
63
64 // Even though Attack was not automatically overridden, we can always
65 // override it manually afterwards by adding it:
66 inst.override_type::<Attack>();
67
68 // The Attack component now shows up in the entity type:
69 println!("{}", inst.archetype());
70
71 // We can get all components on the instance, regardless of whether they
72 // are overridden or not. Note that the overridden components (Attack and
73 // Damage) are initialized with the values from the prefab component:
74 inst.try_get::<(&Attack, &Defence, &Damage)>(|(attack, defence, damage)| {
75 println!("attack: {}", attack.value);
76 println!("defence: {}", defence.value);
77 println!("damage: {}", damage.value);
78 });
79
80 // Output:
81 // Damage, (Identifier,Name), (IsA,SpaceShip)
82 // Attack, Damage, (Identifier,Name), (IsA,SpaceShip)
83 // attack: 75
84 // defence: 100
85 // damage: 50
86}
34fn main() {
35 let world = World::new();
36
37 // Create a base prefab for SpaceShips.
38 let spaceship = world
39 .prefab_named("SpaceShip")
40 .set(ImpulseSpeed { value: 50.0 })
41 .set(Defence { value: 25.0 });
42
43 // Create a Freighter variant which inherits from SpaceShip
44 let freighter = world
45 .prefab_named("Freighter")
46 .is_a_id(spaceship)
47 .set(FreightCapacity { value: 100.0 })
48 .set(Defence { value: 50.0 });
49
50 // Create a MammotFreighter variant which inherits from Freighter
51 let mammoth_freighter = world
52 .prefab_named("MammothFreighter")
53 .is_a_id(freighter)
54 .set(FreightCapacity { value: 500.0 });
55
56 // Create a Frigate variant which inherits from SpaceShip
57 world
58 .prefab_named("Frigate")
59 .is_a_id(spaceship)
60 .set(Attack { value: 100.0 })
61 .set(Defence { value: 75.0 })
62 .set(ImpulseSpeed { value: 125.0 });
63
64 // Create an instance of the MammothFreighter. This entity will inherit the
65 // ImpulseSpeed from SpaceShip, Defence from Freighter and FreightCapacity
66 // from MammothFreighter.
67 let inst = world
68 .entity_named("my_freighter")
69 .is_a_id(mammoth_freighter);
70
71 // Add a private Position component.
72 inst.set(Position { x: 10.0, y: 20.0 });
73
74 // Instances can override inherited components to give them a private copy
75 // of the component. This freighter got an armor upgrade:
76 inst.set(Defence { value: 100.0 });
77
78 // Queries can match components from multiple levels of inheritance
79 world.each_entity::<(&Position, &ImpulseSpeed, &Defence, &FreightCapacity)>(
80 |e, (p, s, d, c)| {
81 println!("{}:", e.name());
82 println!(" - position: {}, {}", p.x, p.y);
83 println!(" - impulse speed: {}", s.value);
84 println!(" - defense: {}", d.value);
85 println!(" - capacity: {}", c.value);
86 },
87 );
88
89 // Output:
90 // my_freighter:
91 // - position: 10, 20
92 // - impulse speed: 50
93 // - defense: 100
94 // - capacity: 500
95}
Sourcepub fn prefab_type<T: ComponentId + TagComponent>(&self) -> EntityView<'_>
pub fn prefab_type<T: ComponentId + TagComponent>(&self) -> EntityView<'_>
Creates a prefab that’s associated with a type
§Type Parameters
T
- The component type to associate with the new prefab.
§Returns
The prefab entity.
§See also
World::prefab()
World::prefab_named()
World::prefab_type_named()
- C++ API:
world::prefab
Examples found in repository?
30fn main() {
31 let world = World::new();
32
33 // Associate types with prefabs
34 world.prefab_type::<Turret>();
35
36 world
37 .prefab_type::<Base>()
38 .child_of::<Turret>()
39 .slot_of::<Turret>();
40
41 world
42 .prefab_type::<Head>()
43 .child_of::<Turret>()
44 .slot_of::<Turret>();
45
46 world.prefab_type::<Railgun>().is_a::<Turret>();
47 world
48 .prefab_type::<Beam>()
49 .slot_of::<Railgun>()
50 .child_of::<Railgun>();
51
52 // Create prefab instance.
53 let inst = world.entity_named("my_railgun").is_a::<Railgun>();
54
55 // Get entities for slots
56 let inst_base = inst.target::<Base>(0).unwrap();
57 let inst_head = inst.target::<Head>(0).unwrap();
58 let inst_beam = inst.target::<Beam>(0).unwrap();
59
60 println!("instance base: {}", inst_base.path().unwrap());
61 println!("instance head: {}", inst_head.path().unwrap());
62 println!("instance beam: {}", inst_beam.path().unwrap());
63
64 // Output:
65 // instance base: ::my_railgun::Base
66 // instance head: ::my_railgun::Head
67 // instance beam: ::my_railgun::Beam
68}
Sourcepub fn prefab_type_named<'a, T: ComponentId + TagComponent>(
&'a self,
name: &str,
) -> EntityView<'a>
pub fn prefab_type_named<'a, T: ComponentId + TagComponent>( &'a self, name: &str, ) -> EntityView<'a>
Creates a named prefab that’s associated with a type
§Type Parameters
T
- The component type to associate with the new prefab.
§Arguments
name
- The name to use for the new prefab.
§Returns
The prefab entity.
§See also
World::prefab()
World::prefab_named()
World::prefab_type()
- C++ API:
world::prefab
pub fn component_id<T: ComponentId>(&self) -> Entity
pub fn relationship_id<First: ComponentId, Second: ComponentId>(&self) -> Id
Sourcepub fn id_from<T: ComponentOrPairId>(&self) -> IdView<'_>
pub fn id_from<T: ComponentOrPairId>(&self) -> IdView<'_>
Get the id view of component / pair
§Type Parameters
T
- The component type.
§Returns
The id of the component.
§See also
- C++ API:
world::id
- C++ API:
world::pair
Examples found in repository?
35fn main() {
36 let world = World::new();
37
38 // When one element of a pair is a component and the other element is a tag,
39 // the pair assumes the type of the component.
40 let e1 = world
41 .entity()
42 .set_pair::<Requires, Gigawatts>(Requires { amount: 1.21 });
43
44 let require = e1.try_get::<Option<&(Requires, Gigawatts)>>(|req| {
45 if let Some((req)) = req {
46 println!("e1: requires: {}", req.amount);
47 } else {
48 println!("e1: does not have a relationship with Requires, Gigawatts");
49 }
50 });
51
52 // The component can be either the first or second part of a pair:
53 let e2 = world
54 .entity()
55 .set_pair::<Gigawatts, Requires>(Requires { amount: 1.5 });
56
57 let require = e2.try_get::<Option<&(Gigawatts, Requires)>>(|req| {
58 if let Some((req)) = req {
59 println!("e2: requires: {}", req.amount);
60 } else {
61 println!("e2: does not have a relationship with Gigawatts, Requires");
62 }
63 });
64
65 // Note that <Requires, Gigawatts> and <Gigawatts, Requires> are two
66 // different pairs, and can be added to an entity at the same time.
67
68 // If both parts of a pair are components, the pair assumes the type of
69 // the first element:
70 let e3 = world
71 .entity()
72 .set_pair::<Expires, Position>(Expires { timeout: 0.5 });
73
74 let expires = e3.try_get::<&(Expires, Position)>(|expires| {
75 println!("expires: {}", expires.timeout);
76 });
77
78 println!(
79 "{}",
80 world
81 .id_from::<(Requires, Gigawatts)>()
82 .type_id()
83 .path()
84 .unwrap()
85 );
86 println!(
87 "{}",
88 world
89 .id_from::<(Gigawatts, Requires)>()
90 .type_id()
91 .path()
92 .unwrap()
93 );
94 println!(
95 "{}",
96 world
97 .id_from::<(Expires, Position)>()
98 .type_id()
99 .path()
100 .unwrap()
101 );
102
103 // When querying for a relationship component, add the pair type as template
104 // argument to the builder:
105 let query = world.query::<&(Requires, Gigawatts)>().build();
106
107 query.each_entity(|entity, requires| {
108 println!("requires: {} gigawatts", requires.amount);
109 });
110
111 // Output:
112 // e1: requires: 1.21
113 // e1: requires: 1.5
114 // expires: 0.5
115 // ::Requires
116 // ::Requires
117 // ::Expires
118 // requires: 1.21 gigawatts
119}
Sourcepub fn id_from_id<Id>(&self, id: Id) -> IdView<'_>where
Id: IntoId,
pub fn id_from_id<Id>(&self, id: Id) -> IdView<'_>where
Id: IntoId,
Sourcepub fn component<T: ComponentId>(&self) -> Component<'_, T::UnderlyingType>
pub fn component<T: ComponentId>(&self) -> Component<'_, T::UnderlyingType>
Find or register component.
§Type Parameters
T
- The component type.
§Returns
The found or registered component.
§See also
- C++ API:
world::component
Examples found in repository?
14fn main() {
15 let world = World::new();
16
17 world
18 .component::<Position>()
19 .on_add(|entity, _pos| {
20 println!("added Position to {:?}", entity.name());
21 })
22 .on_remove(|entity, pos| {
23 println!("removed {:?} from {:?}", pos, entity.name());
24 })
25 .on_set(|entity, pos| {
26 println!("set {:?} for {:?}", pos, entity.name());
27 });
28
29 let entity = world.entity_named("Bob");
30
31 entity.set(Position { x: 10.0, y: 20.0 });
32
33 // This operation changes the entity's archetype, which invokes a move
34 // add is used for adding tags.
35 entity.add::<Tag>();
36
37 entity.destruct();
38
39 // Output:
40 // added Position { x: 0.0, y: 0.0 } to "Bob"
41 // set Position { x: 10.0, y: 20.0 } for "Bob"
42 // removed Position { x: 10.0, y: 20.0 } from "Bob"
43}
More examples
7fn main() {
8 let world = World::new();
9
10 // Register TradesWith as symmetric relationship. Symmetric relationships
11 // go both ways, adding (R, B) to A will also add (R, A) to B.
12 world.component::<TradesWith>().add::<flecs::Symmetric>();
13
14 // Create two players
15 let player_1 = world.entity();
16 let player_2 = world.entity();
17
18 // Add (TradesWith, player_2) to player_1. This also adds
19 // (TradesWith, player_1) to player_2.
20 player_1.add_first::<TradesWith>(player_2);
21
22 // Log platoon of unit
23 println!(
24 "Player 1 trades with Player 2: {}",
25 player_1.has_first::<TradesWith>(player_2)
26 ); // true
27 println!(
28 "Player 2 trades with Player 1: {}",
29 player_2.has_first::<TradesWith>(player_1)
30 ); // true
31
32 // Output:
33 // Player 1 trades with Player 2: true
34 // Player 2 trades with Player 1: true
35}
63fn main() {
64 let world = World::new();
65
66 let bob = world
67 .entity_named("Bob")
68 .set(Position { x: 10.0, y: 20.0 })
69 .set(Velocity { x: 1.0, y: 1.0 })
70 .add::<Human>()
71 .add::<(Eats, Apples)>();
72
73 println!("Bob's components:");
74 iterate_components(bob);
75
76 println!();
77
78 // We can use the same function to iterate the components of a component
79 println!("Position's components:");
80 iterate_components(world.component::<Position>().entity());
81
82 // Output:
83 // Bob's components:
84 // [Position, Velocity, Human, (Identifier,Name), (Eats,Apples)]
85 //
86 // 0: Position
87 // 1: Velocity
88 // 2: Human
89 // 3: (Identifier,Name)
90 // 4: (Eats,Apples)
91 //
92 // 0: entity: Position
93 // 1: entity: Velocity
94 // 2: entity: Human
95 // 3: rel: Identifier, target: Name
96 // 4: rel: Eats, target: Apples
97 //
98 // Position's components:
99 // [Component, (Identifier,Name), (Identifier,Symbol)
100 //
101 // 0: Component
102 // 1: (Identifier,Name)
103 // 2: (Identifier,Symbol)
104 // 3: (ChildOf,entity_iterate_components.common)
105
106 // 0: entity: Component
107 // 1: rel: Identifier, target: Name
108 // 2: rel: Identifier, target: Symbol
109 // 3: rel: ChildOf, target: common
110}
8fn main() {
9 let world = World::new();
10
11 // Register Platoon as exclusive relationship. This ensures that an entity
12 // can only belong to a single Platoon.
13 world.component::<Platoon>().add::<flecs::Exclusive>();
14
15 // Create two platoons
16 let platoon_1 = world.entity();
17 let platoon_2 = world.entity();
18
19 // Create a unit
20 let unit = world.entity();
21
22 // Add unit to platoon 1
23 unit.add_first::<Platoon>(platoon_1);
24
25 // Log platoon of unit
26 println!(
27 "Unit in platoon 1: {}",
28 unit.has_first::<Platoon>(platoon_1)
29 ); // true
30 println!(
31 "Unit in platoon 2: {}",
32 unit.has_first::<Platoon>(platoon_2)
33 ); // false
34
35 println!();
36
37 // Add unit to platoon 2. Because Platoon is an exclusive relationship, this
38 // both removes (Platoon, platoon_1) and adds (Platoon, platoon_2) in a
39 // single operation.
40 unit.add_first::<Platoon>(platoon_2);
41
42 // Log platoon of unit
43 println!(
44 "Unit in platoon 1: {}",
45 unit.has_first::<Platoon>(platoon_1)
46 ); // false
47 println!(
48 "Unit in platoon 2: {}",
49 unit.has_first::<Platoon>(platoon_2)
50 ); // true
51
52 // Output:
53 // Unit in platoon 1: true
54 // Unit in platoon 2: false
55 //
56 // Unit in platoon 1: false
57 // Unit in platoon 2: true
58}
28fn main() {
29 let world = World::new();
30
31 // Add the traits to mark the component to be inherited
32 world
33 .component::<Defence>()
34 .add_trait::<(flecs::OnInstantiate, flecs::Inherit)>();
35
36 // Create a prefab with Position and Velocity components
37 let spaceship = world.prefab_named("Prefab").set(Defence { value: 50.0 });
38
39 // Create a prefab instance
40 let inst = world.entity_named("my_spaceship").is_a_id(spaceship);
41
42 // Because of the IsA relationship, the instance now shares the Defense
43 // component with the prefab, and can be retrieved as a regular component:
44 inst.try_get::<&Defence>(|d_inst| {
45 println!("{:?}", d_inst);
46 // Because the component is shared, changing the value on the prefab will
47 // also change the value for the instance:
48 // this is safe during a table lock because it also has the component and won't cause the table to move.
49 spaceship.set(Defence { value: 100.0 });
50 println!("after set: {:?}", d_inst);
51 });
52
53 // Prefab components can be iterated like regular components:
54 world.each_entity::<&Defence>(|entity, d| {
55 println!("{}: defence: {}", entity.path().unwrap(), d.value);
56 });
57
58 // Output:
59 // Defence { value: 50.0 }
60 // after set: Defence { value: 100.0 }
61 // ::my_spaceship: 100
62}
30fn main() {
31 let world = World::new();
32
33 // Make the ECS aware of the inheritance relationships. Note that IsA
34 // relationship used here is the same as in the prefab example.
35 world.component::<CombatUnit>().is_a::<Unit>();
36 world.component::<MeleeUnit>().is_a::<CombatUnit>();
37 world.component::<RangedUnit>().is_a::<CombatUnit>();
38
39 world.component::<Warrior>().is_a::<MeleeUnit>();
40 world.component::<Wizard>().is_a::<RangedUnit>();
41 world.component::<Marksman>().is_a::<RangedUnit>();
42 world.component::<BuilderX>().is_a::<Unit>();
43
44 // Create a few units
45 world.entity_named("warrior_1").add::<Warrior>();
46 world.entity_named("warrior_2").add::<Warrior>();
47
48 world.entity_named("marksman_1").add::<Marksman>();
49 world.entity_named("marksman_2").add::<Marksman>();
50
51 world.entity_named("wizard_1").add::<Wizard>();
52 world.entity_named("wizard_2").add::<Wizard>();
53
54 world.entity_named("builder_1").add::<BuilderX>();
55 world.entity_named("builder_2").add::<BuilderX>();
56
57 // Create a rule to find all ranged units
58 let r = world.query::<&RangedUnit>().build();
59
60 // Iterate the rule
61 r.each_entity(|e, rangedunit| {
62 println!("Unit {} found", e.name());
63 });
64
65 // Output:
66 // Unit wizard_1 found
67 // Unit wizard_2 found
68 // Unit marksman_1 found
69 // Unit marksman_2 found
70}
- examples/flecs/relationships/relationships_union.rs
- examples/flecs/queries/query_group_by.rs
- examples/flecs/prefabs/prefab_override.rs
- examples/flecs/queries/query_group_by_custom.rs
- examples/flecs/queries/query_instancing.rs
- examples/flecs/entities/entity_prefab.rs
- examples/flecs/queries/query_transitive_queries.rs
- examples/flecs/queries/query_group_by_callbacks.rs
- examples/flecs/queries/query_setting_variables.rs
- examples/flecs/queries/query_change_tracking.rs
Sourcepub fn component_named<'a, T: ComponentId>(
&'a self,
name: &str,
) -> Component<'a, T::UnderlyingType>
pub fn component_named<'a, T: ComponentId>( &'a self, name: &str, ) -> Component<'a, T::UnderlyingType>
Sourcepub fn component_untyped<T: ComponentId>(&self) -> UntypedComponent<'_>
pub fn component_untyped<T: ComponentId>(&self) -> UntypedComponent<'_>
Sourcepub fn component_untyped_id(
&self,
id: impl Into<Entity>,
) -> UntypedComponent<'_>
pub fn component_untyped_id( &self, id: impl Into<Entity>, ) -> UntypedComponent<'_>
Sourcepub fn to_entity<T: ComponentId + ComponentType<Enum> + EnumComponentInfo>(
&self,
enum_value: T,
) -> EntityView<'_>
pub fn to_entity<T: ComponentId + ComponentType<Enum> + EnumComponentInfo>( &self, enum_value: T, ) -> EntityView<'_>
Sourcepub unsafe fn event_id(&self, event: impl Into<Entity>) -> EventBuilder<'_, ()>
pub unsafe fn event_id(&self, event: impl Into<Entity>) -> EventBuilder<'_, ()>
Create a new event builder (untyped) from entity id which represents an event
§Safety
Caller must ensure that event
is a ZST or that a pointer to the associated type is set on the builder
§Arguments
event
- The event id
§Returns
A new (untyped) event builder.
§See also
EntityView::emit()
EntityView::enqueue()
World::event()
- C++ API:
world::event
Sourcepub fn event<T: ComponentId>(&self) -> EventBuilder<'_, T>
pub fn event<T: ComponentId>(&self) -> EventBuilder<'_, T>
Create a new event.
§Type Parameters
T
- The event type.
§Returns
A new (typed) event builder.
§See also
EntityView::emit()
EntityView::enqueue()
World::event_id()
- C++ API:
world::event
Examples found in repository?
14fn main() {
15 let world = World::new();
16
17 // Create an observer for the custom event
18 world
19 .observer::<MyEvent, &Position>()
20 .each_iter(|it, index, _pos| {
21 println!(
22 " - {}: {}: {}",
23 it.event().name(),
24 it.event_id().to_str(),
25 it.entity(index)
26 );
27 });
28
29 // The observer query can be matched against the entity, so make sure it
30 // has the Position component before emitting the event. This does not
31 // trigger the observer yet.
32 let entity = world.entity_named("e1").set(Position { x: 10.0, y: 20.0 });
33
34 // Emit the custom event. This triggers the observer.
35 world
36 .event()
37 .add::<Position>()
38 .entity(entity)
39 .emit(&MyEvent);
40
41 // Output:
42 // - MyEvent: Position: e1
43}
Sourcepub fn new_observer<'a>(&'a self, e: EntityView<'a>) -> Observer<'a>
pub fn new_observer<'a>(&'a self, e: EntityView<'a>) -> Observer<'a>
Sourcepub fn observer<Event: ComponentId, Components>(
&self,
) -> ObserverBuilder<'_, Event, Components>where
Components: QueryTuple,
pub fn observer<Event: ComponentId, Components>(
&self,
) -> ObserverBuilder<'_, Event, Components>where
Components: QueryTuple,
Create a new observer.
§Type Parameters
Components
- The components to match on.
§Returns
Observer builder.
§See also
World::new_observer()
World::observer_id()
World::observer_named()
- C++ API:
world::observer
Examples found in repository?
18fn main() {
19 let world = World::new();
20
21 // Create existing entities with Position component
22 world.entity_named("e1").set(Position { x: 10.0, y: 20.0 });
23 world.entity_named("e2").set(Position { x: 20.0, y: 30.0 });
24
25 // Create an observer for three events
26 world
27 .observer::<flecs::OnSet, &Position>()
28 .yield_existing()
29 .each_iter(|it, index, pos| {
30 println!(
31 " - {}: {}: {}: {{ {}, {} }}",
32 it.event().name(),
33 it.event_id().to_str(),
34 it.entity(index),
35 pos.x,
36 pos.y
37 );
38 });
39
40 // Output:
41 // - OnSet: Position: e1: { 10, 20 }
42 // - OnSet: Position: e2: { 20, 30 }
43}
More examples
14fn main() {
15 let world = World::new();
16
17 // Create an observer for the custom event
18 world
19 .observer::<MyEvent, &Position>()
20 .each_iter(|it, index, _pos| {
21 println!(
22 " - {}: {}: {}",
23 it.event().name(),
24 it.event_id().to_str(),
25 it.entity(index)
26 );
27 });
28
29 // The observer query can be matched against the entity, so make sure it
30 // has the Position component before emitting the event. This does not
31 // trigger the observer yet.
32 let entity = world.entity_named("e1").set(Position { x: 10.0, y: 20.0 });
33
34 // Emit the custom event. This triggers the observer.
35 world
36 .event()
37 .add::<Position>()
38 .entity(entity)
39 .emit(&MyEvent);
40
41 // Output:
42 // - MyEvent: Position: e1
43}
21fn main() {
22 let world = World::new();
23
24 // Create observer for custom event
25 world
26 .observer::<flecs::OnSet, (&Position, &Velocity)>()
27 .each_iter(|it, index, (pos, vel)| {
28 println!(
29 " - {}: {}: {}: p: {{ {}, {} }}, v: {{ {}, {} }}",
30 it.event().name(),
31 it.event_id().to_str(),
32 it.entity(index).name(),
33 pos.x,
34 pos.y,
35 vel.x,
36 vel.y
37 );
38 });
39
40 // Create entity, set Position (emits EcsOnSet, does not yet match observer)
41 let entity = world.entity_named("e").set(Position { x: 10.0, y: 20.0 });
42
43 // Set Velocity (emits EcsOnSet, matches observer)
44 entity.set(Velocity { x: 1.0, y: 2.0 });
45
46 // Output:
47 // - OnSet: Velocity: e: p: { 10, 20 }, v: { 1, 2 }
48}
26fn main() {
27 let world = World::new();
28
29 // Create observer for custom event
30 world
31 .observer::<flecs::Monitor, (&Position, &Velocity)>()
32 .each_iter(|it, index, (_pos, _vel)| {
33 if it.event() == flecs::OnAdd::ID {
34 println!(
35 " - Enter: {}: {}",
36 it.event_id().to_str(),
37 it.entity(index).name()
38 );
39 } else if it.event() == flecs::OnRemove::ID {
40 println!(
41 " - Leave: {}: {}",
42 it.event_id().to_str(),
43 it.entity(index).name()
44 );
45 }
46 });
47
48 // Create entity
49 let entity = world.entity_named("e");
50
51 // This does not yet trigger the monitor, as the entity does not yet match.
52 entity.set(Position { x: 10.0, y: 20.0 });
53
54 // This triggers the monitor with EcsOnAdd, as the entity now matches.
55 entity.set(Velocity { x: 1.0, y: 2.0 });
56
57 // This triggers the monitor with EcsOnRemove, as the entity no longer matches.
58 entity.remove::<Position>();
59
60 // Output:
61 // - Enter: Velocity: e
62 // - Leave: Position: e
63}
22fn main() {
23 let world = World::new();
24
25 // Create observer that listens for events from both self and parent
26 world
27 .observer::<flecs::OnSet, (&Position, &Position)>()
28 .term_at(1)
29 .parent()
30 .each_iter(|it, index, (pos_self, pos_parent)| {
31 println!(
32 " - {}: {}: {}: self: {{ {}, {} }}, parent: {{ {}, {} }}",
33 it.event().name(),
34 it.event_id().to_str(),
35 it.entity(index).name(),
36 pos_self.x,
37 pos_self.y,
38 pos_parent.x,
39 pos_parent.y
40 );
41 });
42
43 // Create entity and parent
44 let parent = world.entity_named("p");
45 let entity = world.entity_named("e").child_of_id(parent);
46
47 // Set Position on entity. This doesn't trigger the observer yet, since the
48 // parent doesn't have Position yet.
49 entity.set(Position { x: 10.0, y: 20.0 });
50
51 // Set Position on parent. This event will be propagated and trigger the
52 // observer, as the observer query now matches.
53 parent.set(Position { x: 1.0, y: 2.0 });
54
55 // Output:
56 // - OnSet: Position: e: self: { 10, 20 }, parent: { 1, 2 }
57}
11fn main() {
12 let world = World::new();
13
14 // Create an observer for three events
15 world
16 .observer::<flecs::OnAdd, &Position>()
17 .add_event::<flecs::OnRemove>() //or .add_event_id(OnRemove::ID)
18 .add_event::<flecs::OnSet>()
19 .each_iter(|it, index, pos| {
20 if it.event() == flecs::OnAdd::ID {
21 // No assumptions about the component value should be made here. If
22 // a ctor for the component was registered it will be called before
23 // the EcsOnAdd event, but a value assigned by set won't be visible.
24 println!(" - OnAdd: {}: {}", it.event_id().to_str(), it.entity(index));
25 } else {
26 println!(
27 " - {}: {}: {}: with {:?}",
28 it.event().name(),
29 it.event_id().to_str(),
30 it.entity(index),
31 pos
32 );
33 }
34 });
35
36 // Create entity, set Position (emits EcsOnAdd and EcsOnSet)
37 let entity = world.entity_named("e1").set(Position { x: 10.0, y: 20.0 });
38
39 // Remove Position (emits EcsOnRemove)
40 entity.remove::<Position>();
41
42 // Remove Position again (no event emitted)
43 entity.remove::<Position>();
44
45 // Output:
46 // - OnAdd: Position: e1
47 // - OnSet: Position: e1: with Position { x: 10.0, y: 20.0 }
48 // - OnRemove: Position: e1: with Position { x: 10.0, y: 20.0 }
49}
pub fn observer_id<Components>(
&self,
event: impl Into<Entity>,
) -> ObserverBuilder<'_, (), Components>where
Components: QueryTuple,
Sourcepub fn observer_named<'a, Event: ComponentId, Components>(
&'a self,
name: &str,
) -> ObserverBuilder<'a, Event, Components>where
Components: QueryTuple,
pub fn observer_named<'a, Event: ComponentId, Components>(
&'a self,
name: &str,
) -> ObserverBuilder<'a, Event, Components>where
Components: QueryTuple,
Create a new named observer.
§Type Parameters
Components
- The components to match on.
§Arguments
name
- The name of the observer.
§Returns
Observer builder.
§See also
World::new_observer()
World::observer()
World::observer_id()
- C++ API:
world::observer
Sourcepub fn new_query<Components>(&self) -> Query<Components>where
Components: QueryTuple,
pub fn new_query<Components>(&self) -> Query<Components>where
Components: QueryTuple,
Create a new uncached Query
.
§Type Parameters
Components
- The components to match on.
§See also
World::new_query()
World::new_query_named()
World::query()
World::query_named()
- C++ API:
world::query
Examples found in repository?
11fn main() {
12 let world = World::new();
13 // Create a few test entities for a Position query
14 world.entity_named("e1").set(Position { x: 10.0, y: 20.0 });
15
16 world.entity_named("e2").set(Position { x: 20.0, y: 30.0 });
17
18 // Create a simple query for component Position
19 let query = world.new_query::<&Position>();
20
21 let entity: Option<EntityView> = query.find(|pos| (pos.x - 20.0).abs() < f32::EPSILON);
22
23 if let Some(entity) = entity {
24 println!("Entity found: {:?}", entity.path().unwrap());
25 } else {
26 println!("Entity not found");
27 }
28
29 // Output:
30 // Entity found: "::e2"
31}
More examples
17fn main() {
18 let world = World::new();
19
20 // Create a query that matches edible components
21 let query = world.new_query::<&(EatsAmount, flecs::Wildcard)>();
22
23 // Create a few entities that match the query
24 world
25 .entity_named("Bob")
26 .set_pair::<EatsAmount, Apples>(EatsAmount { amount: 10 })
27 .set_pair::<EatsAmount, Pears>(EatsAmount { amount: 5 });
28
29 world
30 .entity_named("Alice")
31 .set_pair::<EatsAmount, Apples>(EatsAmount { amount: 4 });
32
33 // Iterate the query with a flecs::iter. This makes it possible to inspect
34 // the pair that we are currently matched with.
35 query.each_iter(|it, index, eats| {
36 let entity = it.entity(index);
37 let pair = it.pair(0).unwrap();
38 let food = pair.second_id();
39
40 println!("{} eats {} {}", entity, eats.amount, food);
41 });
42
43 // Output:
44 // Alice eats 4 Apples
45 // Bob eats 10 Apples
46 // Bob eats 5 Pears
47}
43fn main() {
44 let world = World::new();
45
46 // Applications can pass context data to a system. A common use case where this
47 // comes in handy is when a system needs to iterate more than one query. The
48 // following example shows how to pass a custom query into a system for a simple
49 // collision detection example.
50
51 let mut query_collide = world.new_query::<(&Position, &Radius)>();
52
53 let sys = world
54 .system::<(&Position, &Radius)>()
55 .set_context(&mut query_collide as *mut Query<(&Position, &Radius)> as *mut c_void)
56 .each_iter(|mut it, index, (p1, r1)| {
57 let query = unsafe { it.context::<Query<(&Position, &Radius)>>() };
58 let e1 = it.entity(index);
59
60 query.each_entity(|e2, (p2, r2)| {
61 if e1 == *e2 {
62 // don't collide with self
63 return;
64 }
65
66 if e1 > *e2 {
67 // Simple trick to prevent collisions from being detected
68 // twice with the entities reversed.
69 return;
70 }
71
72 // Check for collision
73 let d_sqr = distance_sqr(p1, p2);
74 let r_sqr = sqr(r1.value + r2.value);
75 if r_sqr > d_sqr {
76 println!("{} and {} collided!", e1, e2);
77 }
78 });
79 });
80
81 // Create a few test entities
82 for _ in 0..10 {
83 world
84 .entity()
85 .set(Position {
86 x: rand(50),
87 y: rand(50),
88 })
89 .set(Radius {
90 value: rand(10) + 1.0,
91 });
92 }
93
94 // Run the system
95 sys.run();
96
97 // Output:
98 // 532 and 539 collided!
99 // 532 and 540 collided!
100 // 534 and 538 collided!
101 // 536 and 537 collided!
102 // 536 and 540 collided!
103 // 537 and 540 collided!
104}
17fn main() {
18 let world = World::new();
19
20 // Create a query for Position, Velocity. Queries are the fastest way to
21 // iterate entities as they cache results.
22 let query = world.new_query::<(&mut Position, &Velocity)>();
23
24 // Create a few test entities for a Position, Velocity query
25 world
26 .entity_named("e1")
27 .set(Position { x: 10.0, y: 20.0 })
28 .set(Velocity { x: 1.0, y: 2.0 });
29
30 world
31 .entity_named("e2")
32 .set(Position { x: 10.0, y: 20.0 })
33 .set(Velocity { x: 3.0, y: 4.0 });
34
35 // This entity will not match as it does not have Position, Velocity
36 world.entity_named("e3").set(Position { x: 10.0, y: 20.0 });
37
38 // The next lines show the different ways in which a query can be iterated.
39
40 // `The each_entity()` function iterates each entity individually and accepts an
41 // entity argument plus arguments for each query component:
42 query.each_entity(|e, (pos, vel)| {
43 pos.x += vel.x;
44 pos.y += vel.y;
45 println!("{}: [{:?}]", e.name(), pos);
46 });
47
48 // There's an equivalent function that does not include the entity argument
49 query.each(|(pos, vel)| {
50 pos.x += vel.x;
51 pos.y += vel.y;
52 println!("[{:?}]", pos);
53 });
54
55 // Iter is a bit more verbose, but allows for more control over how entities
56 // are iterated as it provides multiple entities in the same callback.
57 // There's also an `iter_only` function that only provides the iterator.
58 query.run_iter(|it, (pos, vel)| {
59 for i in it.iter() {
60 pos[i].x += vel[i].x;
61 pos[i].y += vel[i].y;
62 println!("[{:?}]", pos[i]);
63 }
64 });
65
66 // Output:
67 // e1: [Position { x: 11.0, y: 22.0 }]
68 // e2: [Position { x: 13.0, y: 24.0 }]
69 // [Position { x: 12.0, y: 24.0 }]
70 // [Position { x: 16.0, y: 28.0 }]
71 // [Position { x: 13.0, y: 26.0 }]
72 // [Position { x: 19.0, y: 32.0 }]
73}
17fn main() {
18 let world = World::new();
19
20 let sun = world
21 .entity_named("Sun")
22 .set_pair::<Position, WorldX>(Position::default())
23 .set_pair::<Position, Local>(Position { x: 1.0, y: 1.0 });
24
25 world
26 .entity_named("Mercury")
27 .child_of_id(sun)
28 .set_pair::<Position, WorldX>(Position::default())
29 .set_pair::<Position, Local>(Position { x: 1.0, y: 1.0 });
30
31 world
32 .entity_named("Venus")
33 .child_of_id(sun)
34 .set_pair::<Position, WorldX>(Position::default())
35 .set_pair::<Position, Local>(Position { x: 2.0, y: 2.0 });
36
37 let earth = world
38 .entity_named("Earth")
39 .child_of_id(sun)
40 .set_pair::<Position, WorldX>(Position::default())
41 .set_pair::<Position, Local>(Position { x: 3.0, y: 3.0 });
42
43 world
44 .entity_named("Moon")
45 .child_of_id(earth)
46 .set_pair::<Position, WorldX>(Position::default())
47 .set_pair::<Position, Local>(Position { x: 0.1, y: 0.1 });
48
49 let query = world
50 .query::<(
51 &(Position, Local),
52 Option<&(Position, WorldX)>,
53 &mut (Position, WorldX),
54 )>()
55 .term_at(1)
56 .parent()
57 .cascade()
58 .build();
59
60 query.run_iter(|it, (local, parent_world, world)| {
61 for i in it.iter() {
62 world[i].x = local[i].x;
63 world[i].y = local[i].y;
64 if parent_world.is_some() {
65 let parent_world = parent_world.unwrap();
66 world[i].x += parent_world[i].x;
67 world[i].y += parent_world[i].y;
68 }
69 }
70 });
71
72 world
73 .new_query::<&(Position, WorldX)>()
74 .each_entity(|entity, position| {
75 println!(
76 "Entity {} is at ({}, {})",
77 entity.name(),
78 position.x,
79 position.y
80 );
81 });
82
83 // Output:
84 // Entity Sun is at (1, 1)
85 // Entity Mercury is at (2, 2)
86 // Entity Venus is at (3, 3)
87 // Entity Earth is at (4, 4)
88 // Entity Moon is at (4.1, 4.1)
89}
22fn main() {
23 let world = World::new();
24
25 let query = world.new_query::<(&mut Position, &Velocity)>();
26
27 // Create a few test entities for a Position, Velocity query
28 world
29 .entity_named("e1")
30 .set(Position { x: 10.0, y: 20.0 })
31 .set(Velocity { x: 1.0, y: 2.0 });
32
33 world
34 .entity_named("e2")
35 .set(Position { x: 10.0, y: 20.0 })
36 .set(Velocity { x: 3.0, y: 4.0 });
37
38 world
39 .entity_named("e3")
40 .set(Position { x: 10.0, y: 20.0 })
41 .set(Velocity { x: 4.0, y: 5.0 })
42 .set(Mass { value: 50.0 });
43
44 // The iter function provides a flecs::iter object which contains all sorts
45 // of information on the entities currently being iterated.
46 // The function passed to iter is by default called for each table the query
47 // is matched with.
48 query.run_iter(|it, (position, velocity)| {
49 println!();
50 // Print the table & number of entities matched in current callback
51 println!("Table: {:?}", it.archetype());
52 println!(" - number of entities: {}", it.count());
53 println!();
54
55 // Print information about the components being matched
56 for i in 0..it.field_count() {
57 println!(" - term {} : ", i);
58 println!(" - component: {}", it.id(i).to_str());
59 println!(" - type size: {}", it.size(i));
60 }
61
62 println!();
63
64 for i in it.iter() {
65 position[i].x += velocity[i].x;
66 position[i].y += velocity[i].y;
67 println!(" - entity {}: has {:?}", it.entity(i).name(), position[i]);
68 }
69
70 println!();
71 });
72
73 // Output:
74 // Table: Position, Velocity, (Identifier,Name)
75 // - number of entities: 2
76 //
77 // - term 1 :
78 // - component: Position
79 // - type size: 8
80 // - term 2 :
81 // - component: Velocity
82 // - type size: 8
83 //
84 // - entity e1: has Position { x: 11.0, y: 22.0 }
85 // - entity e2: has Position { x: 13.0, y: 24.0 }
86 //
87 //
88 // Table: Position, Velocity, Mass, (Identifier,Name)
89 // - number of entities: 1
90 //
91 // - term 1 :
92 // - component: Position
93 // - type size: 8
94 // - term 2 :
95 // - component: Velocity
96 // - type size: 8
97 //
98 // - entity e3: has Position { x: 14.0, y: 25.0 }
99 //
100}
Sourcepub fn new_query_named<Components>(&self, name: &str) -> Query<Components>where
Components: QueryTuple,
pub fn new_query_named<Components>(&self, name: &str) -> Query<Components>where
Components: QueryTuple,
Create a new named Query
.
§Type Parameters
Components
- The components to match on.
§Arguments
name
- The name of the query.
§Returns
A new query.
§See also
World::new_query()
World::new_query_named()
World::query()
World::query_named()
- C++ API:
world::query
Sourcepub fn query<Components>(&self) -> QueryBuilder<'_, Components>where
Components: QueryTuple,
pub fn query<Components>(&self) -> QueryBuilder<'_, Components>where
Components: QueryTuple,
Create a new QueryBuilder
.
§Type Parameters
Components
- The components to match on.
§Returns
A new query builder.
§See also
World::new_query()
World::new_query_named()
World::query_named()
- C++ API:
world::query_builder
Examples found in repository?
15fn main() {
16 let world = World::new();
17
18 // Set singleton
19 world.set(Gravity { value: 9.81 });
20
21 // Set Velocity
22 world.entity_named("e1").set(Velocity { x: 0.0, y: 0.0 });
23 world.entity_named("e2").set(Velocity { x: 0.0, y: 1.0 });
24 world.entity_named("e3").set(Velocity { x: 0.0, y: 2.0 });
25
26 // Create query that matches Gravity as singleton
27 let query = world
28 .query::<(&mut Velocity, &Gravity)>()
29 .term_at(1)
30 .singleton()
31 .build();
32
33 // In a query string expression you can use the $ shortcut for singletons:
34 // Velocity, Gravity($)
35
36 query.each_entity(|entity, (velocity, gravity)| {
37 velocity.y += gravity.value;
38 println!("Entity {} has {:?}", entity.path().unwrap(), velocity);
39 });
40
41 // Output:
42 // Entity ::e1 has Velocity { x: 0.0, y: 9.81 }
43 // Entity ::e2 has Velocity { x: 0.0, y: 10.81 }
44 // Entity ::e3 has Velocity { x: 0.0, y: 11.81 }
45}
More examples
14fn main() {
15 let world = World::new();
16
17 // Create a query for Position, Npc. By adding the Npc component using the
18 // "with" method, the component is not a part of the query type, and as a
19 // result does not become part of the function signatures of each and iter.
20 // This is useful for things like tags, which because they don't have a
21 // value are less useful to pass to the each/iter functions as argument.
22 let query = world.query::<&Position>().with::<&Npc>().build();
23
24 // Create a few test entities for the Position, Npc query
25 world
26 .entity_named("e1")
27 .set(Position { x: 10.0, y: 20.0 })
28 .add::<Npc>();
29
30 world
31 .entity_named("e2")
32 .set(Position { x: 10.0, y: 20.0 })
33 .add::<Npc>();
34
35 // This entity will not match as it does not have Position, Npc
36 world.entity_named("e3").set(Position { x: 10.0, y: 20.0 });
37
38 // Note how the Npc tag is not part of the each signature
39 query.each_entity(|entity, pos| {
40 println!("Entity {}: {:?}", entity.name(), pos);
41 });
42
43 // Output:
44 // Entity e1: Position { x: 10.0, y: 20.0 }
45 // Entity e2: Position { x: 10.0, y: 20.0 }
46}
14fn main() {
15 let world = World::new();
16
17 // Create a query for Position, !Npc. By adding the Npc component using the
18 // "without" method, the component is not a part of the query type, and as a
19 // result does not become part of the function signatures of each and iter.
20 // This is useful for things like tags, which because they don't have a
21 // value are less useful to pass to the each/iter functions as argument.
22 //
23 // The without method is short for:
24 // .term<Npc>().not_()
25 let query = world.query::<&Position>().without::<&Npc>().build();
26
27 // Create a few test entities for the Position query
28 world.entity_named("e1").set(Position { x: 10.0, y: 20.0 });
29
30 world.entity_named("e2").set(Position { x: 10.0, y: 20.0 });
31
32 // This entity will not match as it has Npc
33 world
34 .entity_named("e3")
35 .set(Position { x: 10.0, y: 20.0 })
36 .add::<Npc>();
37
38 // Note how the Npc tag is not part of the each signature
39 query.each_entity(|entity, pos| {
40 println!("Entity {}: {:?}", entity.name(), pos);
41 });
42
43 // Output:
44 // Entity e1: Position { x: 10.0, y: 20.0 }
45 // Entity e2: Position { x: 10.0, y: 20.0 }
46}
30fn main() {
31 let world = World::new();
32
33 // Make the ECS aware of the inheritance relationships. Note that IsA
34 // relationship used here is the same as in the prefab example.
35 world.component::<CombatUnit>().is_a::<Unit>();
36 world.component::<MeleeUnit>().is_a::<CombatUnit>();
37 world.component::<RangedUnit>().is_a::<CombatUnit>();
38
39 world.component::<Warrior>().is_a::<MeleeUnit>();
40 world.component::<Wizard>().is_a::<RangedUnit>();
41 world.component::<Marksman>().is_a::<RangedUnit>();
42 world.component::<BuilderX>().is_a::<Unit>();
43
44 // Create a few units
45 world.entity_named("warrior_1").add::<Warrior>();
46 world.entity_named("warrior_2").add::<Warrior>();
47
48 world.entity_named("marksman_1").add::<Marksman>();
49 world.entity_named("marksman_2").add::<Marksman>();
50
51 world.entity_named("wizard_1").add::<Wizard>();
52 world.entity_named("wizard_2").add::<Wizard>();
53
54 world.entity_named("builder_1").add::<BuilderX>();
55 world.entity_named("builder_2").add::<BuilderX>();
56
57 // Create a rule to find all ranged units
58 let r = world.query::<&RangedUnit>().build();
59
60 // Iterate the rule
61 r.each_entity(|e, rangedunit| {
62 println!("Unit {} found", e.name());
63 });
64
65 // Output:
66 // Unit wizard_1 found
67 // Unit wizard_2 found
68 // Unit marksman_1 found
69 // Unit marksman_2 found
70}
35fn main() {
36 let world = World::new();
37
38 // Register Movement and Direction as union relationships. This ensures that
39 // an entity can only have one Movement and one Direction.
40 world.component::<Movement>().add::<flecs::Union>();
41 world.component::<Direction>().add::<flecs::Union>();
42
43 // Create a query that subscribes for all entities that have a Direction
44 // and that are walking.
45 let q = world
46 .query::<()>()
47 .with_enum(Movement::Walking)
48 .with_enum_wildcard::<Direction>()
49 .build();
50
51 // Create a few entities with various state combinations
52 world
53 .entity_named("e1")
54 .add_enum(Movement::Walking)
55 .add_enum(Direction::Front);
56
57 world
58 .entity_named("e2")
59 .add_enum(Movement::Running)
60 .add_enum(Direction::Left);
61
62 let e3 = world
63 .entity_named("e3")
64 .add_enum(Movement::Running)
65 .add_enum(Direction::Back);
66
67 // Add Walking to e3. This will remove the Running case
68 e3.add_enum(Movement::Walking);
69
70 // Iterate the query
71 q.each_iter(|it, index, ()| {
72 let entity = it.entity(index);
73
74 // Movement will always be Walking, Direction can be any state
75 println!(
76 "{}: Movement: {:?}, Direction: {:?}",
77 entity.name(),
78 it.pair(0).unwrap().second_id().name(),
79 it.pair(1).unwrap().second_id().name()
80 );
81 });
82
83 // Output:
84 // e3: Movement: Walking, Direction: Back
85 // e1: Movement: Walking, Direction: Front
86}
26fn main() {
27 let world = World::new();
28
29 world.component::<First>();
30 world.component::<Second>();
31 world.component::<Third>();
32
33 let query = world.query::<&Position>().group_by::<Group>().build();
34
35 world
36 .entity()
37 .add::<(Group, Third)>()
38 .set(Position { x: 1.0, y: 1.0 });
39 world
40 .entity()
41 .add::<(Group, Second)>()
42 .set(Position { x: 2.0, y: 2.0 });
43 world
44 .entity()
45 .add::<(Group, First)>()
46 .set(Position { x: 3.0, y: 3.0 });
47
48 world
49 .entity()
50 .add::<(Group, Third)>()
51 .set(Position { x: 4.0, y: 4.0 })
52 .add::<Tag>();
53 world
54 .entity()
55 .add::<(Group, Second)>()
56 .set(Position { x: 5.0, y: 5.0 })
57 .add::<Tag>();
58 world
59 .entity()
60 .add::<(Group, First)>()
61 .set(Position { x: 6.0, y: 6.0 })
62 .add::<Tag>();
63
64 println!();
65
66 query.run_iter(|it, pos| {
67 let group = world.entity_from_id(it.group_id());
68 println!(
69 "Group: {:?} - Table: [{:?}]",
70 group.path().unwrap(),
71 it.archetype()
72 );
73
74 for i in it.iter() {
75 println!(" [{:?}]", pos[i]);
76 }
77
78 println!();
79 });
80
81 // Output:
82 // Group: "::First" - Table: [Position, (Group,First)]
83 // [Position { x: 3.0, y: 3.0 }]
84 //
85 // Group: "::First" - Table: [Position, Tag, (Group,First)]
86 // [Position { x: 6.0, y: 6.0 }]
87 //
88 // Group: "::Second" - Table: [Position, (Group,Second)]
89 // [Position { x: 2.0, y: 2.0 }]
90 //
91 // Group: "::Second" - Table: [Position, Tag, (Group,Second)]
92 // [Position { x: 5.0, y: 5.0 }]
93 //
94 // Group: "::Third" - Table: [Position, (Group,Third)]
95 // [Position { x: 1.0, y: 1.0 }]
96 //
97 // Group: "::Third" - Table: [Position, Tag, (Group,Third)]
98 // [Position { x: 4.0, y: 4.0 }]
99}
- examples/flecs/queries/query_variables.rs
- examples/flecs/queries/query_hierarchy.rs
- examples/flecs/queries/query_sorting.rs
- examples/flecs/queries/query_cyclic_variables.rs
- examples/flecs/queries/query_facts.rs
- examples/flecs/queries/query_chaining_queries.rs
- examples/flecs/relationships/relationships_component_data.rs
- examples/flecs/queries/query_group_by_custom.rs
- examples/flecs/queries/query_group_iter.rs
- examples/flecs/queries/query_instancing.rs
- examples/flecs/relationships/relationships_enum.rs
- examples/flecs/queries/query_transitive_queries.rs
- examples/flecs/queries/query_group_by_callbacks.rs
- examples/flecs/queries/query_setting_variables.rs
- examples/flecs/queries/query_change_tracking.rs
Sourcepub fn query_named<'a, Components>(
&'a self,
name: &str,
) -> QueryBuilder<'a, Components>where
Components: QueryTuple,
pub fn query_named<'a, Components>(
&'a self,
name: &str,
) -> QueryBuilder<'a, Components>where
Components: QueryTuple,
Create a new named QueryBuilder
.
§Type Parameters
Components
- The components to match on.
§Arguments
name
- The name of the query.
§Returns
A new query builder.
§See also
World::new_query()
World::new_query_named()
World::query()
- C++ API:
world::query_builder
Sourcepub fn each<Components>(
&self,
func: impl FnMut(Components::TupleType<'_>),
) -> Query<Components>where
Components: QueryTuple,
pub fn each<Components>(
&self,
func: impl FnMut(Components::TupleType<'_>),
) -> Query<Components>where
Components: QueryTuple,
Create and iterate an uncached query.
This function creates a query and immediately iterates it.
§Returns
The query.
§Type Parameters
Components
: The components to match on.
§See also
QueryAPI::each()
World::each_entity()
- C++ API:
world::each
Sourcepub fn each_entity<Components>(
&self,
func: impl FnMut(EntityView<'_>, Components::TupleType<'_>),
) -> Query<Components>where
Components: QueryTuple,
pub fn each_entity<Components>(
&self,
func: impl FnMut(EntityView<'_>, Components::TupleType<'_>),
) -> Query<Components>where
Components: QueryTuple,
Create and iterate an uncached query.
This function creates a query and immediately iterates it.
§Returns
The query.
§Type Parameters
Components
: The components to match on.
§See also
QueryAPI::each_entity()
World::each()
- C++ API:
world::each
Examples found in repository?
17fn main() {
18 let world = World::new();
19
20 // Create a few test entities for a Position, Velocity query
21 world
22 .entity_named("e1")
23 .set(Position { x: 10.0, y: 20.0 })
24 .set(Velocity { x: 1.0, y: 2.0 });
25
26 world
27 .entity_named("e2")
28 .set(Position { x: 10.0, y: 20.0 })
29 .set(Velocity { x: 3.0, y: 4.0 });
30
31 // This entity will not match as it does not have Position, Velocity
32 world.entity_named("e3").set(Position { x: 10.0, y: 20.0 });
33
34 // Ad hoc queries are bit slower to iterate than flecs::query, but are
35 // faster to create, and in most cases require no allocations. Under the
36 // hood this API uses flecs::query, which can be used directly for more
37 // complex queries.
38
39 world.each_entity::<(&mut Position, &Velocity)>(|entity, (pos, vel)| {
40 pos.x += vel.x;
41 pos.y += vel.y;
42 println!("Entity {}: {:?}", entity.name(), pos);
43 });
44
45 // Output:
46 // Entity e1: Position { x: 11.0, y: 22.0 }
47 // Entity e2: Position { x: 13.0, y: 24.0 }
48}
More examples
28fn main() {
29 let world = World::new();
30
31 // Add the traits to mark the component to be inherited
32 world
33 .component::<Defence>()
34 .add_trait::<(flecs::OnInstantiate, flecs::Inherit)>();
35
36 // Create a prefab with Position and Velocity components
37 let spaceship = world.prefab_named("Prefab").set(Defence { value: 50.0 });
38
39 // Create a prefab instance
40 let inst = world.entity_named("my_spaceship").is_a_id(spaceship);
41
42 // Because of the IsA relationship, the instance now shares the Defense
43 // component with the prefab, and can be retrieved as a regular component:
44 inst.try_get::<&Defence>(|d_inst| {
45 println!("{:?}", d_inst);
46 // Because the component is shared, changing the value on the prefab will
47 // also change the value for the instance:
48 // this is safe during a table lock because it also has the component and won't cause the table to move.
49 spaceship.set(Defence { value: 100.0 });
50 println!("after set: {:?}", d_inst);
51 });
52
53 // Prefab components can be iterated like regular components:
54 world.each_entity::<&Defence>(|entity, d| {
55 println!("{}: defence: {}", entity.path().unwrap(), d.value);
56 });
57
58 // Output:
59 // Defence { value: 50.0 }
60 // after set: Defence { value: 100.0 }
61 // ::my_spaceship: 100
62}
20fn main() {
21 let world = World::new();
22
23 // Create an entity with name Bob
24 let bob = world
25 .entity_named("Bob")
26 // The set operation finds or creates a component, and sets it.
27 // Components are automatically registered with the world
28 .set(Position { x: 10.0, y: 20.0 })
29 // The add operation adds a component without setting a value. This is
30 // useful for tags, or when adding a component with its default value.
31 .add::<Walking>();
32
33 // Get the value for the Position component
34 // - get panics if the component is not present, use try_get for a non-panicking version which does not run the callback.
35 // - or use Option to handle the individual component missing.
36 bob.get::<Option<&Position>>(|pos| {
37 if let Some(pos) = pos {
38 println!("Bob's position: {:?}", pos);
39 }
40 });
41
42 // Overwrite the value of the Position component
43 bob.set(Position { x: 20.0, y: 30.0 });
44
45 // Create another named entity
46 let alice = world
47 .entity_named("Alice")
48 .set(Position { x: 10.0, y: 20.0 });
49
50 // Add a tag after entity is created
51 alice.add::<Walking>();
52
53 // Print all of the components the entity has. This will output:
54 // Position, Walking, (Identifier,Name)
55 println!("[{}]", alice.archetype());
56
57 // Remove tag
58 alice.remove::<Walking>();
59
60 // Iterate all entities with position
61 world.each_entity::<&Position>(|entity, pos| {
62 println!("{} has {:?}", entity.name(), pos);
63 });
64
65 // Output:
66 // Bob's position: Position { x: 10.0, y: 20.0 }
67 // [Position, Walking, (Identifier,Name)]
68 // Alice has Position { x: 10.0, y: 20.0 }
69 // Bob has Position { x: 20.0, y: 30.0 }
70}
34fn main() {
35 let world = World::new();
36
37 // Create a base prefab for SpaceShips.
38 let spaceship = world
39 .prefab_named("SpaceShip")
40 .set(ImpulseSpeed { value: 50.0 })
41 .set(Defence { value: 25.0 });
42
43 // Create a Freighter variant which inherits from SpaceShip
44 let freighter = world
45 .prefab_named("Freighter")
46 .is_a_id(spaceship)
47 .set(FreightCapacity { value: 100.0 })
48 .set(Defence { value: 50.0 });
49
50 // Create a MammotFreighter variant which inherits from Freighter
51 let mammoth_freighter = world
52 .prefab_named("MammothFreighter")
53 .is_a_id(freighter)
54 .set(FreightCapacity { value: 500.0 });
55
56 // Create a Frigate variant which inherits from SpaceShip
57 world
58 .prefab_named("Frigate")
59 .is_a_id(spaceship)
60 .set(Attack { value: 100.0 })
61 .set(Defence { value: 75.0 })
62 .set(ImpulseSpeed { value: 125.0 });
63
64 // Create an instance of the MammothFreighter. This entity will inherit the
65 // ImpulseSpeed from SpaceShip, Defence from Freighter and FreightCapacity
66 // from MammothFreighter.
67 let inst = world
68 .entity_named("my_freighter")
69 .is_a_id(mammoth_freighter);
70
71 // Add a private Position component.
72 inst.set(Position { x: 10.0, y: 20.0 });
73
74 // Instances can override inherited components to give them a private copy
75 // of the component. This freighter got an armor upgrade:
76 inst.set(Defence { value: 100.0 });
77
78 // Queries can match components from multiple levels of inheritance
79 world.each_entity::<(&Position, &ImpulseSpeed, &Defence, &FreightCapacity)>(
80 |e, (p, s, d, c)| {
81 println!("{}:", e.name());
82 println!(" - position: {}, {}", p.x, p.y);
83 println!(" - impulse speed: {}", s.value);
84 println!(" - defense: {}", d.value);
85 println!(" - capacity: {}", c.value);
86 },
87 );
88
89 // Output:
90 // my_freighter:
91 // - position: 10, 20
92 // - impulse speed: 50
93 // - defense: 100
94 // - capacity: 500
95}
34fn main() {
35 let world = World::new();
36
37 // Add the traits to mark the components to be inherited
38 world
39 .component::<Position>()
40 .add_trait::<(flecs::OnInstantiate, flecs::Inherit)>();
41 world
42 .component::<Defence>()
43 .add_trait::<(flecs::OnInstantiate, flecs::Inherit)>();
44 world
45 .component::<ImpulseSpeed>()
46 .add_trait::<(flecs::OnInstantiate, flecs::Inherit)>();
47 world
48 .component::<FreightCapacity>()
49 .add_trait::<(flecs::OnInstantiate, flecs::Inherit)>();
50 world
51 .component::<HasFlt>()
52 .add_trait::<(flecs::OnInstantiate, flecs::Inherit)>();
53
54 // Create a prefab hierarchy.
55 let spaceship = world
56 .prefab_named("Spaceship")
57 // Add components to prefab entity as usual
58 .set(ImpulseSpeed { value: 50.0 })
59 .set(Defence { value: 50.0 })
60 .set(Position { x: 0.0, y: 0.0 })
61 // By default components in an inheritance hierarchy are shared between
62 // entities. The override function ensures that instances have a private
63 // copy of the component.
64 .auto_override::<Position>();
65
66 let freighter = world
67 .prefab_named("Freighter")
68 .is_a_id(spaceship)
69 .set(FreightCapacity { value: 100.0 })
70 .set(Defence { value: 100.0 })
71 .add::<HasFlt>();
72
73 let mammoth_freighter = world
74 .prefab_named("MammothFreighter")
75 .is_a_id(freighter)
76 .set(FreightCapacity { value: 500.0 })
77 .set(Defence { value: 300.0 });
78
79 world
80 .prefab_named("Frigate")
81 .is_a_id(spaceship)
82 .add::<HasFlt>()
83 .set(Attack { value: 100.0 })
84 .set(Defence { value: 75.0 })
85 .set(ImpulseSpeed { value: 125.0 });
86
87 // Create a regular entity from a prefab.
88 // The instance will have a private copy of the Position component, because
89 // of the override in the spaceship entity. All other components are shared.
90 let inst = world
91 .entity_named("my_mammoth_freighter")
92 .is_a_id(mammoth_freighter);
93
94 // Inspect the type of the entity. This outputs:
95 // Position,(Identifier,Name),(IsA,MammothFreighter)
96 println!("Instance type: [{}]", inst.archetype());
97
98 // Even though the instance doesn't have a private copy of ImpulseSpeed, we
99 // can still get it using the regular API (outputs 50)
100 inst.try_get::<&ImpulseSpeed>(|impulse_speed| {
101 println!("ImpulseSpeed: {}", impulse_speed.value);
102 });
103
104 // Prefab components can be iterated just like regular components:
105 world.each_entity::<(&ImpulseSpeed, &mut Position)>(|entity, (impulse_speed, position)| {
106 position.x += impulse_speed.value;
107 println!("Entity {}: {:?}", entity.name(), position);
108 });
109
110 // Output:
111 // Instance type: [Position, (Identifier,Name), (IsA,MammothFreighter)]
112 // ImpulseSpeed: 50
113 // Entity my_mammoth_freighter: Position { x: 50.0, y: 0.0 }
114}
Sourcepub fn system_from<'a>(&'a self, entity: EntityView<'a>) -> System<'a>
Available on crate feature flecs_system
only.
pub fn system_from<'a>(&'a self, entity: EntityView<'a>) -> System<'a>
flecs_system
only.Constructs a System
from an existing entity.
This function upcasts the given entity
to a System
, assuming the entity represents a system.
The purpose is to facilitate the interaction with entities that are specifically systems within the ECS.
§Arguments
entity
- AnEntityView
that represents a system within the world.
§See also
- C++ API:
world::system
Sourcepub fn system<Components>(&self) -> SystemBuilder<'_, Components>where
Components: QueryTuple,
Available on crate feature flecs_system
only.
pub fn system<Components>(&self) -> SystemBuilder<'_, Components>where
Components: QueryTuple,
flecs_system
only.Creates a new SystemBuilder
instance for constructing systems.
This function initializes a SystemBuilder
which is used to create systems that match specific components.
It is a generic method that works with any component types that implement the QueryTuple
trait.
§Type Parameters
Components
: The components to match on. Must implement theQueryTuple
trait.
§See also
World::system_named()
- C++ API:
world::system_builder
Examples found in repository?
17fn main() {
18 let world = World::new();
19
20 world.set(Timeout { value: 3.5 });
21
22 world
23 .system::<&mut Timeout>()
24 .each_iter(|it, _index, timeout| {
25 timeout.value -= it.delta_time();
26 });
27
28 world.system_named::<()>("Tick").interval(1.0).run(tick);
29
30 world.system_named::<()>("FastTick").interval(0.5).run(tick);
31
32 // Run the main loop at 60 FPS
33 world.set_target_fps(60.0);
34
35 while world.progress() {
36 if world.map::<&Timeout, _>(|timeout| timeout.value <= 0.0) {
37 println!("Timed out!");
38 break;
39 }
40 }
41
42 // Output:
43 // FastTick
44 // Tick
45 // FastTick
46 // FastTick
47 // Tick
48 // FastTick
49 // FastTick
50 // Tick
51 // FastTick
52 // FastTick
53 // Timed out!
54}
More examples
15fn main() {
16 let world = World::new();
17
18 // Create a pipeline that matches systems with Physics. Note that this
19 // pipeline does not require the use of phases (see custom_phases) or of the
20 // DependsOn relationship.
21 let pipeline = world
22 .pipeline()
23 .with_id(flecs::system::System::ID)
24 .with::<&Physics>()
25 .build();
26
27 // Configure the world to use the custom pipeline
28 world.set_pipeline_id(pipeline.entity());
29
30 // Create system with Physics tag
31 world.system::<()>().kind::<Physics>().run(|mut it| {
32 while it.next() {
33 println!("System with Physics ran!");
34 }
35 });
36
37 // Create system without Physics tag
38 world.system::<()>().run(|mut it| {
39 while it.next() {
40 println!("System without Physics ran!");
41 }
42 });
43
44 // Runs the pipeline & system
45 world.progress();
46
47 // Output:
48 // System with Physics ran!
49}
17fn main() {
18 let world = World::new();
19
20 // Create a system for Position, Velocity. Systems are like queries (see
21 // queries) with a function that can be ran or scheduled (see pipeline).
22
23 let s = world
24 .system::<(&mut Position, &Velocity)>()
25 .each_entity(|e, (p, v)| {
26 p.x += v.x;
27 p.y += v.y;
28 println!("{}: {{ {}, {} }}", e.name(), p.x, p.y);
29 });
30
31 // Create a few test entities for a Position, Velocity query
32 world
33 .entity_named("e1")
34 .set(Position { x: 10.0, y: 20.0 })
35 .set(Velocity { x: 1.0, y: 2.0 });
36
37 world
38 .entity_named("e2")
39 .set(Position { x: 10.0, y: 20.0 })
40 .set(Velocity { x: 3.0, y: 4.0 });
41
42 // This entity will not match as it does not have Position, Velocity
43 world.entity_named("e3").set(Position { x: 10.0, y: 20.0 });
44
45 // Run the system
46 s.run();
47
48 // Output:
49 // e1: { 11, 22 }
50 // e2: { 13, 24 }
51}
5fn main() {
6 let world = World::new();
7
8 // Create system that prints delta_time. This system doesn't query for any
9 // components which means it won't match any entities, but will still be ran
10 // once for each call to ecs_progress.
11 world.system::<()>().run(|mut it| {
12 while it.next() {
13 println!("delta_time: {}", it.delta_time());
14 }
15 });
16
17 // Call progress with 0.0f for the delta_time parameter. This will cause
18 // ecs_progress to measure the time passed since the last frame. The
19 // delta_time of the first frame is a best guess (16ms).
20 world.progress();
21
22 // The following calls should print a delta_time of approximately 100ms
23
24 let os_sleep = unsafe { flecs_ecs_sys::ecs_os_api.sleep_ }.unwrap();
25
26 unsafe { os_sleep(0, 100 * 1000 * 1000) };
27 world.progress();
28
29 unsafe { os_sleep(0, 100 * 1000 * 1000) };
30
31 world.progress();
32
33 // Output:
34 // delta_time: 0.016666668
35 // delta_time: 0.10155179
36 // delta_time: 0.10091246
37}
17fn main() {
18 let world = World::new();
19
20 // Create a system for moving an entity
21 world
22 .system::<(&mut Position, &Velocity)>()
23 .kind::<flecs::pipeline::OnUpdate>()
24 .each(|(p, v)| {
25 p.x += v.x;
26 p.y += v.y;
27 });
28
29 // Create a system for printing the entity position
30 world
31 .system::<&Position>()
32 .kind::<flecs::pipeline::PostUpdate>()
33 .each_entity(|e, p| {
34 println!("{}: {{ {}, {} }}", e.name(), p.x, p.y);
35 });
36
37 // Create a few test entities for a Position, Velocity query
38 world
39 .entity_named("e1")
40 .set(Position { x: 10.0, y: 20.0 })
41 .set(Velocity { x: 1.0, y: 2.0 });
42
43 world
44 .entity_named("e2")
45 .set(Position { x: 10.0, y: 20.0 })
46 .set(Velocity { x: 3.0, y: 4.0 });
47
48 // Run the default pipeline. This will run all systems ordered by their
49 // phase. Systems within the same phase are ran in declaration order. This
50 // function is usually called in a loop.
51 world.progress();
52
53 // Output:
54 // e1: { 11, 22 }
55 // e2: { 13, 24 }
56}
24fn main() {
25 let world = World::new();
26
27 let system = world
28 .system::<(&mut Position, &Velocity)>()
29 // Forward each result from the run callback to the each callback.
30 .run_each_entity(
31 |mut iter| {
32 println!("Move begin");
33
34 while iter.next() {
35 iter.each();
36 }
37
38 println!("Move end");
39 },
40 |e, (pos, vel)| {
41 pos.x += vel.x;
42 pos.y += vel.y;
43 println!("{}: {{ {}, {} }}", e.name(), pos.x, pos.y);
44 },
45 );
46
47 // Create a few test entities for a Position, Velocity query
48 world
49 .entity_named("e1")
50 .set(Position { x: 10.0, y: 20.0 })
51 .set(Velocity { x: 1.0, y: 2.0 });
52
53 world
54 .entity_named("e2")
55 .set(Position { x: 10.0, y: 20.0 })
56 .set(Velocity { x: 3.0, y: 4.0 });
57
58 // This entity will not match as it does not have Position, Velocity
59 world.entity_named("e3").set(Position { x: 10.0, y: 20.0 });
60
61 // Run the system
62 system.run();
63
64 // Output:
65 // Move begin
66 // e1: {11, 22}
67 // e2: {13, 24}
68 // Move end
69}
Sourcepub fn system_named<'a, Components>(
&'a self,
name: &str,
) -> SystemBuilder<'a, Components>where
Components: QueryTuple,
Available on crate feature flecs_system
only.
pub fn system_named<'a, Components>(
&'a self,
name: &str,
) -> SystemBuilder<'a, Components>where
Components: QueryTuple,
flecs_system
only.Creates a new named SystemBuilder
instance.
Similar to system_builder
, but allows naming the system for easier identification and debugging.
The name does not affect the system’s behavior.
§Arguments
name
- A string slice representing the name of the system.
§Type Parameters
Components
: The components to match on. Must implement theQueryTuple
trait.
§See also
World::system()
- C++ API:
world::system_builder
Examples found in repository?
13fn main() {
14 let world = World::new();
15
16 // Startup system
17 world
18 .system_named::<()>("Startup")
19 .kind::<flecs::pipeline::OnStart>()
20 .run(|mut it| {
21 while it.next() {
22 println!("{}", it.system().name());
23 }
24 });
25
26 // Regular system
27 world.system_named::<()>("Update").run(|mut it| {
28 while it.next() {
29 println!("{}", it.system().name());
30 }
31 });
32
33 // First frame. This runs both the Startup and Update systems
34 world.progress();
35
36 // Second frame. This runs only the Update system
37 world.progress();
38
39 // Output:
40 // Startup
41 // Update
42 // Update
43}
More examples
17fn main() {
18 let world = World::new();
19
20 world.set(Timeout { value: 3.5 });
21
22 world
23 .system::<&mut Timeout>()
24 .each_iter(|it, _index, timeout| {
25 timeout.value -= it.delta_time();
26 });
27
28 world.system_named::<()>("Tick").interval(1.0).run(tick);
29
30 world.system_named::<()>("FastTick").interval(0.5).run(tick);
31
32 // Run the main loop at 60 FPS
33 world.set_target_fps(60.0);
34
35 while world.progress() {
36 if world.map::<&Timeout, _>(|timeout| timeout.value <= 0.0) {
37 println!("Timed out!");
38 break;
39 }
40 }
41
42 // Output:
43 // FastTick
44 // Tick
45 // FastTick
46 // FastTick
47 // Tick
48 // FastTick
49 // FastTick
50 // Tick
51 // FastTick
52 // FastTick
53 // Timed out!
54}
15fn main() {
16 let world = World::new();
17
18 // Create three custom phases. Note that the phases have the Phase tag,
19 // which is necessary for the builtin pipeline to discover which systems it
20 // should run.
21
22 let update = world.entity().add::<flecs::pipeline::Phase>();
23
24 let physics = world
25 .entity()
26 .add::<flecs::pipeline::Phase>()
27 .depends_on_id(update);
28
29 let collisions = world
30 .entity()
31 .add::<flecs::pipeline::Phase>()
32 .depends_on_id(physics);
33
34 // Create 3 dummy systems.
35 world
36 .system_named::<()>("CollisionSystem")
37 .kind_id(collisions)
38 .run(sys);
39
40 world
41 .system_named::<()>("PhysicsSystem")
42 .kind_id(physics)
43 .run(sys);
44
45 world
46 .system_named::<()>("GameSystem")
47 .kind_id(update)
48 .run(sys);
49
50 // Run pipeline
51 world.progress();
52
53 // Output:
54 // system GameSystem
55 // system PhysicsSystem
56 // system CollisionSystem
57}
15fn main() {
16 let world = World::new();
17
18 // Create two custom phases that branch off of EcsOnUpdate. Note that the
19 // phases have the Phase tag, which is necessary for the builtin pipeline
20 // to discover which systems it should run.
21 let physics = world
22 .entity()
23 .add::<flecs::pipeline::Phase>()
24 .depends_on::<flecs::pipeline::OnUpdate>();
25
26 let collisions = world
27 .entity()
28 .add::<flecs::pipeline::Phase>()
29 .depends_on_id(physics);
30
31 // Create 3 dummy systems.
32 world
33 .system_named::<()>("CollisionSystem")
34 .kind_id(collisions)
35 .run(sys);
36
37 world
38 .system_named::<()>("PhysicsSystem")
39 .kind_id(physics)
40 .run(sys);
41
42 world
43 .system_named::<()>("GameSystem")
44 .kind::<flecs::pipeline::OnUpdate>()
45 .run(sys);
46
47 // Run pipeline
48 world.progress();
49
50 // Output:
51 // system GameSystem
52 // system PhysicsSystem
53 // system CollisionSystem
54}
16fn main() {
17 let world = World::new();
18
19 // System that sets velocity using ecs_set for entities with PositionSP.
20 // While systems are progressing, operations like ecs_set are deferred until
21 // it is safe to merge. By default this merge happens at the end of the
22 // frame, but we can annotate systems to give the scheduler more information
23 // about what it's doing, which allows it to insert sync points earlier.
24 //
25 // Note that sync points are never necessary/inserted for systems that write
26 // components provided by their signature, as these writes directly happen
27 // in the ECS storage and are never deferred.
28 //
29 // .inout_none() for PositionSP tells the scheduler that while we
30 // want to match entities with PositionSP, we're not interested in reading or
31 // writing the component value.
32
33 world
34 .system_named::<()>("SetVelocitySP")
35 .with::<&PositionSP>()
36 .set_inout_none()
37 .write::<VelocitySP>() // VelocitySP is written, but shouldn't be matched
38 .each_entity(|e, ()| {
39 e.set(VelocitySP { x: 1.0, y: 2.0 });
40 });
41
42 // This system reads VelocitySP, which causes the insertion of a sync point.
43 world
44 .system_named::<(&mut PositionSP, &VelocitySP)>("Move")
45 .each(|(p, v)| {
46 p.x += v.x;
47 p.y += v.y;
48 });
49
50 // Print resulting PositionSP
51 world
52 .system_named::<&PositionSP>("PrintPositionSP")
53 .each_entity(|e, p| {
54 println!("{}: {{ {}, {} }}", e.name(), p.x, p.y);
55 });
56
57 // Create a few test entities for a PositionSP, VelocitySP query
58 world
59 .entity_named("e1")
60 .set(PositionSP { x: 10.0, y: 20.0 })
61 .set(VelocitySP { x: 1.0, y: 2.0 });
62
63 world
64 .entity_named("e2")
65 .set(PositionSP { x: 10.0, y: 20.0 })
66 .set(VelocitySP { x: 3.0, y: 4.0 });
67
68 // Run systems. Debug logging enables us to see the generated schedule.
69 // NOTE flecs C / flecs_ecs_sys needs to be build in debug mode to see the logging.
70 // use the feature flag "sys_build_debug" to enable debug build of flecs C.
71 set_log_level(1);
72 world.progress();
73 set_log_level(-1);
74
75 // Output:
76 // info: pipeline rebuild
77 // info: | schedule: threading: 0, staging: 1:
78 // info: | | system SetVelocitySP
79 // info: | | merge
80 // info: | schedule: threading: 0, staging: 1:
81 // info: | | system Move
82 // info: | | system PrintPositionSP
83 // info: | | merge
84 // e1: { 11, 22 }
85 // e2: { 11, 22 }
86
87 // The "merge" lines indicate sync points.
88 //
89 // Removing `.write::<VelocitySP>()` from the system will remove the first
90 // sync point from the schedule.
91}
17fn main() {
18 let world = World::new();
19
20 // This example shows how to annotate systems that delete entities, in a way
21 // that allows the scheduler to correctly insert sync points. See the
22 // sync_point example for more details on sync points.
23 //
24 // While annotating a system for a delete operation follows the same
25 // design as other operations, one key difference is that a system often
26 // does not know which components a to be deleted entity has. This makes it
27 // impossible to annotate the system in advance for specific components.
28 //
29 // To ensure the scheduler is still able to insert the correct sync points,
30 // a system can use a wildcard to indicate that any component could be
31 // modified by the system, which forces the scheduler to insert a sync.
32
33 // Basic move system.
34 world
35 .system_named::<(&mut Position, &Velocity)>("Move")
36 .each(|(p, v)| {
37 p.x += v.x;
38 p.y += v.y;
39 });
40
41 // Delete entities when p.x >= 3. Add wildcard annotation to indicate any
42 // component could be written by the system. Position itself is added as
43 // const, since inside the system we're only reading it.
44 world
45 .system_named::<&Position>("DeleteEntity")
46 .write::<flecs::Wildcard>()
47 .each_entity(|e, p| {
48 if p.x >= 3.0 {
49 println!("Delete entity {}", e.name());
50 e.destruct();
51 }
52 });
53
54 // Print resulting Position. Note that this system will never print entities
55 // that have been deleted by the previous system.
56 world
57 .system_named::<&Position>("PrintPosition")
58 .each_entity(|e, p| {
59 println!("{}: {{ {}, {} }}", e.name(), p.x, p.y);
60 });
61
62 // Create a few test entities for a Position, Velocity query
63 world
64 .entity_named("e1")
65 .set(Position { x: 0.0, y: 0.0 })
66 .set(Velocity { x: 1.0, y: 2.0 });
67
68 world
69 .entity_named("e2")
70 .set(Position { x: 1.0, y: 2.0 })
71 .set(Velocity { x: 1.0, y: 2.0 });
72
73 // Run systems. Debug logging enables us to see the generated schedule.
74 // NOTE flecs C / flecs_ecs_sys needs to be build in debug mode to see the logging.
75 // use the feature flag "sys_build_debug" to enable debug build of flecs C.
76
77 set_log_level(1);
78
79 while world.progress() {
80 if world.count::<Position>() == 0 {
81 break; // No more entities left with Position
82 }
83 }
84 set_log_level(-1);
85
86 // world
87 // .get::<Snap>()
88 // .test("system_sync_point_delete".to_string()));
89
90 // Output:
91 // info: pipeline rebuild
92 // info: | schedule: threading: 0, staging: 1:
93 // info: | | system Move
94 // info: | | system DeleteEntity
95 // info: | | merge
96 // info: | schedule: threading: 0, staging: 1:
97 // info: | | system PrintPosition
98 // info: | | merge
99 // e1: { 1, 2 }
100 // e2: { 2, 4 }
101 // Delete entity e2
102 // e1: { 2, 4 }
103 // Delete entity e1
104
105 // Removing the wildcard annotation from the DeleteEntity system will
106 // remove the first sync point.
107
108 // Note how after both entities are deleted, all three systems will be de-activated and not ran by the scheduler
109}
Sourcepub fn system_builder_from_desc<Components>(
&self,
desc: ecs_system_desc_t,
) -> SystemBuilder<'_, Components>where
Components: QueryTuple,
Available on crate feature flecs_system
only.
pub fn system_builder_from_desc<Components>(
&self,
desc: ecs_system_desc_t,
) -> SystemBuilder<'_, Components>where
Components: QueryTuple,
flecs_system
only.Creates a SystemBuilder
from a system description.
This function allows creating a system based on a predefined system description, facilitating more dynamic or configuration-driven system creation.
§Arguments
desc
- A system description that outlines the parameters for the system builder.
§Type Parameters
Components
: The components to match on. Must implement theQueryTuple
trait.
§See also
- C++ API:
world::system_builder
Sourcepub fn pipeline(&self) -> PipelineBuilder<'_, ()>
Available on crate feature flecs_pipeline
only.
pub fn pipeline(&self) -> PipelineBuilder<'_, ()>
flecs_pipeline
only.Create a new Pipeline
.
§See also
World::pipeline_named()
World::pipeline_type()
- C++ API:
world::pipeline
Examples found in repository?
15fn main() {
16 let world = World::new();
17
18 // Create a pipeline that matches systems with Physics. Note that this
19 // pipeline does not require the use of phases (see custom_phases) or of the
20 // DependsOn relationship.
21 let pipeline = world
22 .pipeline()
23 .with_id(flecs::system::System::ID)
24 .with::<&Physics>()
25 .build();
26
27 // Configure the world to use the custom pipeline
28 world.set_pipeline_id(pipeline.entity());
29
30 // Create system with Physics tag
31 world.system::<()>().kind::<Physics>().run(|mut it| {
32 while it.next() {
33 println!("System with Physics ran!");
34 }
35 });
36
37 // Create system without Physics tag
38 world.system::<()>().run(|mut it| {
39 while it.next() {
40 println!("System without Physics ran!");
41 }
42 });
43
44 // Runs the pipeline & system
45 world.progress();
46
47 // Output:
48 // System with Physics ran!
49}
Sourcepub fn pipeline_named<'a>(&'a self, name: &str) -> PipelineBuilder<'a, ()>
Available on crate feature flecs_pipeline
only.
pub fn pipeline_named<'a>(&'a self, name: &str) -> PipelineBuilder<'a, ()>
flecs_pipeline
only.Create a new named Pipeline
.
§Arguments
name
- The name of the pipeline.
§See also
World::pipeline()
World::pipeline_type()
- C++ API:
world::pipeline
Sourcepub fn pipeline_type<Pipeline>(&self) -> PipelineBuilder<'_, ()>where
Pipeline: ComponentType<Struct> + ComponentId,
Available on crate feature flecs_pipeline
only.
pub fn pipeline_type<Pipeline>(&self) -> PipelineBuilder<'_, ()>where
Pipeline: ComponentType<Struct> + ComponentId,
flecs_pipeline
only.Create a new Pipeline
with the provided associated type.
§Type Parameters
Pipeline
- The associated type to use for the pipeline.
§See also
World::pipeline()
World::pipeline_named()
- C++ API:
world::pipeline
Sourcepub fn set_pipeline_id(&self, pipeline: impl Into<Entity>)
Available on crate feature flecs_pipeline
only.
pub fn set_pipeline_id(&self, pipeline: impl Into<Entity>)
flecs_pipeline
only.Set a custom pipeline. This operation sets the pipeline to run when World::progress()
is invoked.
§Arguments
pipeline
- The pipeline to set.
§See also
World::get_pipeline()
World::set_pipeline()
- C++ API:
world::set_pipeline_id
Examples found in repository?
15fn main() {
16 let world = World::new();
17
18 // Create a pipeline that matches systems with Physics. Note that this
19 // pipeline does not require the use of phases (see custom_phases) or of the
20 // DependsOn relationship.
21 let pipeline = world
22 .pipeline()
23 .with_id(flecs::system::System::ID)
24 .with::<&Physics>()
25 .build();
26
27 // Configure the world to use the custom pipeline
28 world.set_pipeline_id(pipeline.entity());
29
30 // Create system with Physics tag
31 world.system::<()>().kind::<Physics>().run(|mut it| {
32 while it.next() {
33 println!("System with Physics ran!");
34 }
35 });
36
37 // Create system without Physics tag
38 world.system::<()>().run(|mut it| {
39 while it.next() {
40 println!("System without Physics ran!");
41 }
42 });
43
44 // Runs the pipeline & system
45 world.progress();
46
47 // Output:
48 // System with Physics ran!
49}
Sourcepub fn set_pipeline<Pipeline>(&self)where
Pipeline: ComponentType<Struct> + ComponentId,
Available on crate feature flecs_pipeline
only.
pub fn set_pipeline<Pipeline>(&self)where
Pipeline: ComponentType<Struct> + ComponentId,
flecs_pipeline
only.Set a custom pipeline by type. This operation sets the pipeline to run when World::progress()
is invoked.
§Type Parameters
Pipeline
- The associated type to use for the pipeline.
§See also
World::get_pipeline()
World::set_pipeline_id()
- C++ API:
world::set_pipeline_id
Sourcepub fn get_pipeline(&self) -> EntityView<'_>
Available on crate feature flecs_pipeline
only.
pub fn get_pipeline(&self) -> EntityView<'_>
flecs_pipeline
only.Get the current pipeline.
§Returns
The current pipeline as an entity.
§See also
World::set_pipeline()
World::set_pipeline_id()
- C++ API:
world::get_pipeline
Sourcepub fn progress(&self) -> bool
Available on crate feature flecs_pipeline
only.
pub fn progress(&self) -> bool
flecs_pipeline
only.Progress world one tick.
Progresses the world by running all enabled and periodic systems on their matching entities.
This is a wrapper around World::progress_time()
. It passes 0.0
as
the delta_time
to automatically measure the time passed since the last
frame. This mode is useful for applications that do not manage time
explicitly and want the system to measure the time automatically.
§Returns
True if the world has been progressed, false if World::quit()
has been called.
§See also
World::progress_time()
- C API:
ecs_progress
- C++ API:
world::progress
Examples found in repository?
13fn main() {
14 let world = World::new();
15
16 // Startup system
17 world
18 .system_named::<()>("Startup")
19 .kind::<flecs::pipeline::OnStart>()
20 .run(|mut it| {
21 while it.next() {
22 println!("{}", it.system().name());
23 }
24 });
25
26 // Regular system
27 world.system_named::<()>("Update").run(|mut it| {
28 while it.next() {
29 println!("{}", it.system().name());
30 }
31 });
32
33 // First frame. This runs both the Startup and Update systems
34 world.progress();
35
36 // Second frame. This runs only the Update system
37 world.progress();
38
39 // Output:
40 // Startup
41 // Update
42 // Update
43}
More examples
17fn main() {
18 let world = World::new();
19
20 world.set(Timeout { value: 3.5 });
21
22 world
23 .system::<&mut Timeout>()
24 .each_iter(|it, _index, timeout| {
25 timeout.value -= it.delta_time();
26 });
27
28 world.system_named::<()>("Tick").interval(1.0).run(tick);
29
30 world.system_named::<()>("FastTick").interval(0.5).run(tick);
31
32 // Run the main loop at 60 FPS
33 world.set_target_fps(60.0);
34
35 while world.progress() {
36 if world.map::<&Timeout, _>(|timeout| timeout.value <= 0.0) {
37 println!("Timed out!");
38 break;
39 }
40 }
41
42 // Output:
43 // FastTick
44 // Tick
45 // FastTick
46 // FastTick
47 // Tick
48 // FastTick
49 // FastTick
50 // Tick
51 // FastTick
52 // FastTick
53 // Timed out!
54}
15fn main() {
16 let world = World::new();
17
18 // Create a pipeline that matches systems with Physics. Note that this
19 // pipeline does not require the use of phases (see custom_phases) or of the
20 // DependsOn relationship.
21 let pipeline = world
22 .pipeline()
23 .with_id(flecs::system::System::ID)
24 .with::<&Physics>()
25 .build();
26
27 // Configure the world to use the custom pipeline
28 world.set_pipeline_id(pipeline.entity());
29
30 // Create system with Physics tag
31 world.system::<()>().kind::<Physics>().run(|mut it| {
32 while it.next() {
33 println!("System with Physics ran!");
34 }
35 });
36
37 // Create system without Physics tag
38 world.system::<()>().run(|mut it| {
39 while it.next() {
40 println!("System without Physics ran!");
41 }
42 });
43
44 // Runs the pipeline & system
45 world.progress();
46
47 // Output:
48 // System with Physics ran!
49}
15fn main() {
16 let world = World::new();
17
18 // Create three custom phases. Note that the phases have the Phase tag,
19 // which is necessary for the builtin pipeline to discover which systems it
20 // should run.
21
22 let update = world.entity().add::<flecs::pipeline::Phase>();
23
24 let physics = world
25 .entity()
26 .add::<flecs::pipeline::Phase>()
27 .depends_on_id(update);
28
29 let collisions = world
30 .entity()
31 .add::<flecs::pipeline::Phase>()
32 .depends_on_id(physics);
33
34 // Create 3 dummy systems.
35 world
36 .system_named::<()>("CollisionSystem")
37 .kind_id(collisions)
38 .run(sys);
39
40 world
41 .system_named::<()>("PhysicsSystem")
42 .kind_id(physics)
43 .run(sys);
44
45 world
46 .system_named::<()>("GameSystem")
47 .kind_id(update)
48 .run(sys);
49
50 // Run pipeline
51 world.progress();
52
53 // Output:
54 // system GameSystem
55 // system PhysicsSystem
56 // system CollisionSystem
57}
15fn main() {
16 let world = World::new();
17
18 // Create two custom phases that branch off of EcsOnUpdate. Note that the
19 // phases have the Phase tag, which is necessary for the builtin pipeline
20 // to discover which systems it should run.
21 let physics = world
22 .entity()
23 .add::<flecs::pipeline::Phase>()
24 .depends_on::<flecs::pipeline::OnUpdate>();
25
26 let collisions = world
27 .entity()
28 .add::<flecs::pipeline::Phase>()
29 .depends_on_id(physics);
30
31 // Create 3 dummy systems.
32 world
33 .system_named::<()>("CollisionSystem")
34 .kind_id(collisions)
35 .run(sys);
36
37 world
38 .system_named::<()>("PhysicsSystem")
39 .kind_id(physics)
40 .run(sys);
41
42 world
43 .system_named::<()>("GameSystem")
44 .kind::<flecs::pipeline::OnUpdate>()
45 .run(sys);
46
47 // Run pipeline
48 world.progress();
49
50 // Output:
51 // system GameSystem
52 // system PhysicsSystem
53 // system CollisionSystem
54}
5fn main() {
6 let world = World::new();
7
8 // Create system that prints delta_time. This system doesn't query for any
9 // components which means it won't match any entities, but will still be ran
10 // once for each call to ecs_progress.
11 world.system::<()>().run(|mut it| {
12 while it.next() {
13 println!("delta_time: {}", it.delta_time());
14 }
15 });
16
17 // Call progress with 0.0f for the delta_time parameter. This will cause
18 // ecs_progress to measure the time passed since the last frame. The
19 // delta_time of the first frame is a best guess (16ms).
20 world.progress();
21
22 // The following calls should print a delta_time of approximately 100ms
23
24 let os_sleep = unsafe { flecs_ecs_sys::ecs_os_api.sleep_ }.unwrap();
25
26 unsafe { os_sleep(0, 100 * 1000 * 1000) };
27 world.progress();
28
29 unsafe { os_sleep(0, 100 * 1000 * 1000) };
30
31 world.progress();
32
33 // Output:
34 // delta_time: 0.016666668
35 // delta_time: 0.10155179
36 // delta_time: 0.10091246
37}
- examples/flecs/systems/system_pipeline.rs
- examples/flecs/systems/system_target_fps.rs
- examples/flecs/hello_world.rs
- examples/flecs/systems/system_mutate_entity.rs
- examples/flecs/systems/system_sync_point.rs
- examples/flecs/systems/system_mutate_entity_handle.rs
- examples/flecs/systems/system_sync_point_delete.rs
Sourcepub fn progress_time(&self, delta_time: f32) -> bool
Available on crate feature flecs_pipeline
only.
pub fn progress_time(&self, delta_time: f32) -> bool
flecs_pipeline
only.Progress world by delta time.
Progresses the world by running all enabled and periodic systems on their matching entities for the specified time since the last frame.
When delta_time
is 0, World::progress_time()
will automatically measure the time passed
since the last frame. For applications not using time management, passing a
non-zero delta_time
(1.0 recommended) skips automatic time measurement to avoid overhead.
§Arguments
delta_time
- The time to progress the world by. Pass 0.0 for automatic time measurement.
§Returns
True if the world has been progressed, false if World::quit()
has been called.
§See also
World::progress()
- C API:
ecs_progress
- C++ API:
world::progress
Sourcepub fn run_pipeline_id(&self, pipeline: impl Into<Entity>)
Available on crate feature flecs_pipeline
only.
pub fn run_pipeline_id(&self, pipeline: impl Into<Entity>)
flecs_pipeline
only.Run pipeline. Runs all systems in the specified pipeline. Can be invoked from multiple threads if staging is disabled, managing staging and, if needed, thread synchronization.
Providing 0 for pipeline id runs the default pipeline (builtin or set via
set_pipeline_id()
). Using World::progress()
auto-invokes this for the
default pipeline. Additional pipelines may be run explicitly.
§Note
Only supports single-threaded applications with a single stage when called from an application.
§Arguments
pipeline
- Pipeline to run.
§See also
World::run_pipeline()
World::run_pipeline_id_time()
World::run_pipeline_time()
- C++ API:
world::run_pipeline
Sourcepub fn run_pipeline_id_time(
&self,
pipeline: impl Into<Entity>,
delta_time: FTime,
)
Available on crate feature flecs_pipeline
only.
pub fn run_pipeline_id_time( &self, pipeline: impl Into<Entity>, delta_time: FTime, )
flecs_pipeline
only.Run pipeline. Runs all systems in the specified pipeline. Can be invoked from multiple threads if staging is disabled, managing staging and, if needed, thread synchronization.
Providing 0 for pipeline id runs the default pipeline (builtin or set via
set_pipeline_id()
). Using World::progress()
auto-invokes this for the
default pipeline. Additional pipelines may be run explicitly.
§Note
Only supports single-threaded applications with a single stage when called from an application.
§Arguments
pipeline
- Pipeline to run.delta_time
- Time to advance the world.
§See also
World::run_pipeline()
World::run_pipeline_id()
World::run_pipeline_time()
- C++ API:
world::run_pipeline
Sourcepub fn run_pipeline_time<Component>(&self, delta_time: FTime)where
Component: ComponentType<Struct> + ComponentId,
Available on crate feature flecs_pipeline
only.
pub fn run_pipeline_time<Component>(&self, delta_time: FTime)where
Component: ComponentType<Struct> + ComponentId,
flecs_pipeline
only.Run pipeline. Runs all systems in the specified pipeline. Can be invoked from multiple threads if staging is disabled, managing staging and, if needed, thread synchronization.
Using World::progress()
auto-invokes this for the default pipeline.
Additional pipelines may be run explicitly.
§Note
Only supports single-threaded applications with a single stage when called from an application.
§Type Parameters
Component
- The associated type to use for the pipeline.
§Arguments
delta_time
- Time to advance the world.
§See also
World::run_pipeline()
World::run_pipeline_id()
World::run_pipeline_id_time()
- C++ API:
world::run_pipeline
Sourcepub fn run_pipeline<Component>(&self)where
Component: ComponentType<Struct> + ComponentId,
Available on crate feature flecs_pipeline
only.
pub fn run_pipeline<Component>(&self)where
Component: ComponentType<Struct> + ComponentId,
flecs_pipeline
only.Run pipeline. Runs all systems in the specified pipeline. Can be invoked from multiple threads if staging is disabled, managing staging and, if needed, thread synchronization.
Using World::progress()
auto-invokes this for the default pipeline.
Additional pipelines may be run explicitly.
§Note
Only supports single-threaded applications with a single stage when called from an application.
§Type Parameters
Component
- The associated type to use for the pipeline.
§See also
World::run_pipeline_id()
World::run_pipeline_id_time()
World::run_pipeline_time()
- C++ API:
world::run_pipeline
Sourcepub fn set_time_scale(&self, mul: FTime)
Available on crate feature flecs_pipeline
only.
pub fn set_time_scale(&self, mul: FTime)
flecs_pipeline
only.Sourcepub fn get_time_scale(&self) -> FTime
Available on crate feature flecs_pipeline
only.
pub fn get_time_scale(&self) -> FTime
flecs_pipeline
only.Get time scale.
Retrieves the current time scale of the world, which affects the speed at which time passes within the simulation. A time scale of 1.0 means real-time, values greater than 1.0 speed up the simulation, and values less than 1.0 slow it down.
§Returns
The current time scale as a floating point number.
§See also
- C++ API:
world::get_time_scale
Sourcepub fn get_target_fps(&self) -> FTime
Available on crate feature flecs_pipeline
only.
pub fn get_target_fps(&self) -> FTime
flecs_pipeline
only.Get target frames per second (FPS).
Retrieves the target FPS for the world. This value is used to calculate the time step for each simulation tick when the automatic time step is enabled. Adjusting the target FPS can be used to control simulation speed.
§Returns
The target FPS as a floating point number.
§See also
- C++ API:
world::get_target_fps
Sourcepub fn set_target_fps(&self, target_fps: FTime)
Available on crate feature flecs_pipeline
only.
pub fn set_target_fps(&self, target_fps: FTime)
flecs_pipeline
only.Set target frames per second (FPS).
Configures the world to run at the specified target FPS, ensuring that
World::progress()
is not called more frequently than this rate. This mechanism
enables tracking the elapsed time since the last World::progress()
call and
sleeping for any remaining time in the frame, if applicable.
Utilizing this feature promotes consistent system execution intervals and conserves CPU resources by avoiding more frequent system runs than necessary.
It’s important to note that World::progress()
will only introduce sleep periods
when there is surplus time within a frame. This accounts for time consumed both
within Flecs and in external operations.
§Arguments
world
- The world context.fps
- The desired target FPS as a floating-point number.
§See also
- C++ API:
world::set_target_fps
Examples found in repository?
17fn main() {
18 let world = World::new();
19
20 world.set(Timeout { value: 3.5 });
21
22 world
23 .system::<&mut Timeout>()
24 .each_iter(|it, _index, timeout| {
25 timeout.value -= it.delta_time();
26 });
27
28 world.system_named::<()>("Tick").interval(1.0).run(tick);
29
30 world.system_named::<()>("FastTick").interval(0.5).run(tick);
31
32 // Run the main loop at 60 FPS
33 world.set_target_fps(60.0);
34
35 while world.progress() {
36 if world.map::<&Timeout, _>(|timeout| timeout.value <= 0.0) {
37 println!("Timed out!");
38 break;
39 }
40 }
41
42 // Output:
43 // FastTick
44 // Tick
45 // FastTick
46 // FastTick
47 // Tick
48 // FastTick
49 // FastTick
50 // Tick
51 // FastTick
52 // FastTick
53 // Timed out!
54}
More examples
5fn main() {
6 let world = World::new();
7
8 // Create system that prints delta_time. This system doesn't query for any
9 // components which means it won't match any entities, but will still be ran
10 // once for each call to ecs_progress.
11 world.system::<()>().run(|mut it| {
12 while it.next() {
13 println!("Delta time: {}", it.delta_time());
14 }
15 });
16
17 // Set target FPS to 1 frame per second
18 world.set_target_fps(1.0);
19
20 // Run 3 frames
21 for _ in 0..3 {
22 // To make sure the frame doesn't run faster than the specified target
23 // FPS ecs_progress will insert a sleep if the measured delta_time is
24 // smaller than 1 / target_fps.
25 //
26 // By default ecs_progress uses the sleep function provided by the OS
27 // which is not always very accurate. If more accuracy is required the
28 // sleep function of the OS API can be overridden with a custom one.
29 //
30 // If a value other than 0 is provided to the delta_time argument of
31 // ecs_progress, this value will be used to calculate the length of
32 // the sleep to insert.
33 world.progress();
34 }
35
36 // Output:
37 // Delta time: 1
38 // Delta time: 1.0182016
39 // Delta time: 1.0170991
40}
10fn main() {
11 let world = World::new();
12
13 // System that deletes an entity after a timeout expires
14 world
15 .system::<&mut Timeout>()
16 .each_iter(|it, index, timeout| {
17 timeout.value -= it.delta_time();
18 if timeout.value <= 0.0 {
19 // Delete the entity
20
21 // To make sure that the storage doesn't change while a system
22 // is iterating entities, and multiple threads can safely access
23 // the data, mutations (like a delete) are added to a command
24 // queue and executed when it's safe to do so.
25
26 // When the entity to be mutated is not the same as the entity
27 // provided by the system, an additional mut() call is required.
28 // See the mutate_entity_handle example.
29 let e = it.entity(index);
30 e.destruct();
31 println!("Expire: {} deleted!", e.name());
32 }
33 });
34
35 // System that prints remaining expiry time
36 world.system::<&Timeout>().each_entity(|e, timeout| {
37 println!(
38 "PrintExpire: {} has {:.2} seconds left",
39 e.name(),
40 timeout.value
41 );
42 });
43
44 // Observer that triggers when entity is actually deleted
45 world
46 .observer::<flecs::OnRemove, &Timeout>()
47 .each_entity(|e, _timeout| {
48 println!("Expired: {} actually deleted", e.name());
49 });
50
51 let e = world.entity_named("MyEntity").set(Timeout { value: 2.5 });
52
53 world.set_target_fps(1.0);
54
55 while world.progress() {
56 // If entity is no longer alive, exit
57 if !e.is_alive() {
58 break;
59 }
60
61 println!("Tick...");
62 }
63
64 // Output:
65 // PrintExpire: MyEntity has 2.00 seconds left
66 // Tick...
67 // PrintExpire: MyEntity has 0.99 seconds left
68 // Tick...
69 // Expire: MyEntity deleted!
70 // PrintExpire: MyEntity has -0.03 seconds left
71 // Expired: MyEntity actually deleted
72}
16fn main() {
17 let world = World::new();
18
19 // System that deletes an entity after a timeout expires
20 world
21 .system::<&mut Timeout>()
22 .each_iter(|it, _index, timeout| {
23 timeout.value -= it.delta_time();
24 if timeout.value <= 0.0 {
25 // Delete the entity
26
27 // To make sure the delete operation is enqueued (see
28 // mutate_entity example for more details) we need to provide it
29 // with a mutable context (stage) using the mut() function. If
30 // we don't provide a mutable context, the operation will be
31 // attempted on the context stored in the flecs::entity object,
32 // which would throw a readonly error.
33
34 // To catch these errors at compile time, replace the type of
35 // to_delete with flecs::entity_view. This class does not have
36 // any methods for mutating the entity, which forces the code to
37 // first call mut().
38
39 // The it.world() function can be used to provide the context:
40 // t.to_delete.mut(it.world()).destruct();
41 //
42 // The current entity can also be used to provide context. This
43 // is useful for functions that accept a flecs::entity:
44 // t.to_delete.mut(it.entity(index)).destruct();
45 //
46 // A shortcut is to use the iterator directly:
47 let world = it.world();
48 let to_delete = world.get_alive(timeout.to_delete);
49 println!("Expire: {} deleted!", to_delete.name());
50 to_delete.destruct();
51 }
52 });
53
54 // System that prints remaining expiry time
55 world.system::<&Timeout>().each_entity(|e, timeout| {
56 let world = e.world();
57 let to_delete = world.get_alive(timeout.to_delete);
58 println!(
59 "PrintExpire: {} has {:.2} seconds left",
60 to_delete.name(),
61 timeout.value
62 );
63 });
64
65 // Observer that triggers when entity is actually deleted
66 world
67 .observer::<flecs::OnRemove, &Tag>()
68 .each_entity(|e, _tag| {
69 println!("Expired: {} actually deleted", e.name());
70 });
71
72 let to_delete = world.entity_named("ToDelete").add::<Tag>();
73
74 world.entity_named("MyEntity").set(Timeout {
75 to_delete: to_delete.id(),
76 value: 2.5,
77 });
78
79 world.set_target_fps(1.0);
80
81 while world.progress() {
82 // If entity is no longer alive, exit
83 if !to_delete.is_alive() {
84 break;
85 }
86
87 println!("Tick...");
88 }
89
90 // Output:
91 // PrintExpire: ToDelete has 2.00 seconds left
92 // Tick...
93 // PrintExpire: ToDelete has 0.98 seconds left
94 // Tick...
95 // Expire: ToDelete deleted!
96 // PrintExpire: ToDelete has -0.03 seconds left
97 // Expired: ToDelete actually deleted
98}
Sourcepub fn reset_clock(&self)
Available on crate feature flecs_pipeline
only.
pub fn reset_clock(&self)
flecs_pipeline
only.Reset world clock. Reset the clock that keeps track of the total time passed in the simulation.
§See also
- C++ API:
world::reset_clock
Sourcepub fn set_threads(&self, threads: i32)
Available on crate feature flecs_pipeline
only.
pub fn set_threads(&self, threads: i32)
flecs_pipeline
only.Set number of worker threads.
Setting this value to a value higher than 1 will start as many threads and
will cause systems to evenly distribute matched entities across threads.
The operation may be called multiple times to reconfigure the number of threads used,
but never while running a system / pipeline. Calling World::set_threads()
will also end the use
of task threads setup with World::set_task_threads()
and vice-versa
§Arguments
threads
- The number of threads to use.
§See also
World::set_stage_count()
World::set_task_threads()
- C++ API:
world::set_threads
Sourcepub fn get_threads(&self) -> i32
Available on crate feature flecs_pipeline
only.
pub fn get_threads(&self) -> i32
flecs_pipeline
only.Get number of configured stages. Return number of stages set by World::set_stage_count()
.
§Returns
The number of stages as an integer.
§See also
World::set_stage_count()
World::set_threads()
- C++ API:
world::get_threads
Sourcepub fn set_task_threads(&self, task_threads: i32)
Available on crate feature flecs_pipeline
only.
pub fn set_task_threads(&self, task_threads: i32)
flecs_pipeline
only.Set number of worker task threads.
Configures the world to use a specified number of short-lived task threads,
distinct from World::set_threads()
where threads persist. Here, threads are
created and joined for each world update, leveraging the os_api_t
tasks
APIs for task management instead of traditional thread APIs. This approach
is advantageous for integrating with external asynchronous job systems,
allowing for the dynamic creation and synchronization of tasks specific to
each world update.
This function can be invoked multiple times to adjust the count of task threads,
but must not be called concurrently with system or pipeline execution. Switching
to World::set_task_threads()
from World::set_threads()
(or vice versa) will
terminate the use of the previously configured threading model.
§Arguments
task_threads
- The number of task threads to use.
§See also
World::using_task_threads()
- C++ API:
world::set_task_threads
Sourcepub fn using_task_threads(&self) -> bool
Available on crate feature flecs_pipeline
only.
pub fn using_task_threads(&self) -> bool
flecs_pipeline
only.Returns true if task thread use have been requested.
§Returns
True if task threads are being used, false otherwise.
§See also
World::set_task_threads()
- C++ API:
world::using_task_threads
Sourcepub fn delete_empty_tables(
&self,
id: impl Into<Id>,
clear_generation: u16,
delete_generation: u16,
min_id_count: i32,
time_budget_seconds: f64,
) -> i32
Available on crate feature flecs_pipeline
only.
pub fn delete_empty_tables( &self, id: impl Into<Id>, clear_generation: u16, delete_generation: u16, min_id_count: i32, time_budget_seconds: f64, ) -> i32
flecs_pipeline
only.Sourcepub fn app(&self) -> App<'_>
Available on crate feature flecs_app
only.
pub fn app(&self) -> App<'_>
flecs_app
only.Create a new app.
The app builder is a convenience wrapper around a loop that runs
World::progress()
. An app allows for writing platform agnostic code,
as it provides hooks to modules for overtaking the main loop which is
required for frameworks like emscripten.
§See also
addons::app
- C++ API:
world::app
Sourcepub fn set_doc_name<T: ComponentId>(&self, name: &str)
Available on crate feature flecs_doc
only.
pub fn set_doc_name<T: ComponentId>(&self, name: &str)
flecs_doc
only.Add human-readable name to entity.
Contrary to entity names, human readable names do not have to be unique and can contain special characters used in the query language like ‘*’.
§Type Parameters
T
- The type that implementsComponentId
.
§Arguments
name
- The name to add.
§See also
Doc::set_doc_name()
World::set_doc_name_id()
- C++ API:
doc::get_name()
Sourcepub fn set_doc_name_id(&self, entity: impl Into<Entity>, name: &str)
Available on crate feature flecs_doc
only.
pub fn set_doc_name_id(&self, entity: impl Into<Entity>, name: &str)
flecs_doc
only.Add human-readable name to entity.
Contrary to entity names, human readable names do not have to be unique and can contain special characters used in the query language like ‘*’.
§Arguments
entity
- The entity to which to add the name.name
- The name to add.
§See also
Doc::set_doc_name()
World::set_doc_name()
- C++ API:
world::set_doc_name()
Sourcepub fn set_doc_brief<T: ComponentId>(&self, brief: &str)
Available on crate feature flecs_doc
only.
pub fn set_doc_brief<T: ComponentId>(&self, brief: &str)
flecs_doc
only.Add brief description to entity.
§Type Parameters
T
- The type that implementsComponentId
.
§Arguments
brief
- The brief description to add.
§See also
Doc::set_doc_brief()
World::set_doc_brief_id()
- C++ API:
world::set_doc_brief()
Sourcepub fn set_doc_brief_id(&self, entity: impl Into<Entity>, brief: &str)
Available on crate feature flecs_doc
only.
pub fn set_doc_brief_id(&self, entity: impl Into<Entity>, brief: &str)
flecs_doc
only.Add brief description to entity.
§Arguments
entity
- The entity to which to add the brief description.brief
- The brief description to add.
§See also
Doc::set_doc_brief()
World::set_doc_brief()
- C++ API:
world::set_doc_brief()
Sourcepub fn set_doc_detail<T: ComponentId>(&self, detail: &str)
Available on crate feature flecs_doc
only.
pub fn set_doc_detail<T: ComponentId>(&self, detail: &str)
flecs_doc
only.Add detailed description to entity.
§Type Parameters
T
- The type that implementsComponentId
.
§Arguments
detail
- The detailed description to add.
§See also
Doc::set_doc_detail()
World::set_doc_detail_id()
- C++ API:
world::set_doc_detail()
Sourcepub fn set_doc_detail_id(&self, entity: impl Into<Entity>, detail: &str)
Available on crate feature flecs_doc
only.
pub fn set_doc_detail_id(&self, entity: impl Into<Entity>, detail: &str)
flecs_doc
only.Add detailed description to entity.
§Arguments
entity
- The entity to which to add the detailed description.detail
- The detailed description to add.
§See also
Doc::set_doc_detail()
World::set_doc_detail()
- C++ API:
world::set_doc_detail()
Sourcepub fn set_doc_link<T: ComponentId>(&self, link: &str)
Available on crate feature flecs_doc
only.
pub fn set_doc_link<T: ComponentId>(&self, link: &str)
flecs_doc
only.Add link to external documentation to entity.
§Type Parameters
T
- The type that implementsComponentId
.
§Arguments
link
- The link to add.
§See also
Doc::set_doc_link()
World::set_doc_link_id()
- C++ API:
world::set_doc_link()
Sourcepub fn set_doc_link_id(&self, entity: impl Into<Entity>, link: &str)
Available on crate feature flecs_doc
only.
pub fn set_doc_link_id(&self, entity: impl Into<Entity>, link: &str)
flecs_doc
only.Add link to external documentation to entity.
§Arguments
entity
- The entity to which to add the link.link
- The link to add.
§See also
Doc::set_doc_link()
World::set_doc_link()
- C++ API:
world::set_doc_link()
Sourcepub fn set_doc_color<T: ComponentId>(&self, color: &str)
Available on crate feature flecs_doc
only.
pub fn set_doc_color<T: ComponentId>(&self, color: &str)
flecs_doc
only.Add color to entity.
UIs can use color as hint to improve visualizing entities.
§Type Parameters
T
- The type that implementsComponentId
.
§Arguments
color
- The color to add.
§See also
Doc::set_doc_color()
World::set_doc_color_id()
- C++ API:
world::set_doc_color()
Sourcepub fn set_doc_color_id(&self, entity: impl Into<Entity>, color: &str)
Available on crate feature flecs_doc
only.
pub fn set_doc_color_id(&self, entity: impl Into<Entity>, color: &str)
flecs_doc
only.Add color to entity.
UIs can use color as hint to improve visualizing entities.
§Arguments
entity
- The entity to which to add the color.color
- The color to add.
§See also
Doc::set_doc_color()
World::set_doc_color()
- C++ API:
world::set_doc_color()
Sourcepub fn import<T: Module>(&self) -> EntityView<'_>
Available on crate feature flecs_module
only.
pub fn import<T: Module>(&self) -> EntityView<'_>
flecs_module
only.Import a module.
This operation will load a module. The module name will be used to verify if the module was already loaded, in which case it won’t be reimported.
Module contents will be stored as children of the module entity. This prevents modules from accidentally defining conflicting identifiers. This is enforced by setting the scope before and after loading the module to the module entity id.
world.import::<MyModule>();
§See also
addons::module
Module
World::module()
- C++ API:
world::import
Sourcepub fn module<M: ComponentId>(&self, name: &str) -> EntityView<'_>
Available on crate feature flecs_module
only.
pub fn module<M: ComponentId>(&self, name: &str) -> EntityView<'_>
flecs_module
only.Define a module.
This operation is not mandatory, but can be called inside the module ctor to obtain the entity associated with the module, or override the module name.
§Type Parameters
M
- The type of the module.
§Arguments
name
- The name to give the module.
§Returns
The module entity.
§See also
addons::module
Module
World::import()
- C++ API:
world::module
Sourcepub fn timer_from<T: ComponentId>(&self) -> Timer<'_>
Available on crate feature flecs_timer
only.
pub fn timer_from<T: ComponentId>(&self) -> Timer<'_>
flecs_timer
only.Sourcepub fn randomize_timers(&self)
Available on crate feature flecs_timer
only.
pub fn randomize_timers(&self)
flecs_timer
only.Enable randomizing initial time value of timers. Initializes timers with a random time value, which can improve scheduling as systems/timers for the same interval don’t all happen on the same tick.
§See also
- C++ API:
world::randomize_timers