Skip to main content

examples/systems/
system_ctx.rs

1use crate::z_ignore_test_common::*;
2
3use core::{borrow::Borrow, ffi::c_void};
4use flecs_ecs::prelude::*;
5use std::time::{SystemTime, UNIX_EPOCH};
6
7#[derive(Debug, Component)]
8pub struct Position {
9    pub x: f32,
10    pub y: f32,
11}
12
13#[derive(Component)]
14struct Radius {
15    value: f32,
16}
17
18fn sqr(value: f32) -> f32 {
19    value * value
20}
21
22fn distance_sqr(p1: &Position, p2: &Position) -> f32 {
23    sqr(p2.x - p1.x) + sqr(p2.y - p1.y)
24}
25
26fn rand(max: u64) -> f32 {
27    let start = SystemTime::now();
28
29    //this rand method isn't great, but it's good enough for this example
30    let since_the_epoch = start
31        .duration_since(UNIX_EPOCH)
32        .expect("Time went backwards");
33
34    // Use some aspect of the current time to generate a number
35    let random_number = since_the_epoch.as_secs() ^ since_the_epoch.subsec_nanos() as u64;
36
37    (random_number % max) as f32
38}
39
40fn main() {
41    let world = World::new();
42
43    // Applications can pass context data to a system. A common use case where this
44    // comes in handy is when a system needs to iterate more than one query. The
45    // following example shows how to pass a custom query into a system for a simple
46    // collision detection example.
47
48    let mut query_collide = world.new_query::<(&Position, &Radius)>();
49
50    let sys = world
51        .system::<(&Position, &Radius)>()
52        .set_context(&mut query_collide as *mut Query<(&Position, &Radius)> as *mut c_void)
53        .each_iter(|mut it, index, (p1, r1)| {
54            let query = unsafe { it.context::<Query<(&Position, &Radius)>>() };
55            let e1 = it.entity(index);
56
57            query.each_entity(|e2, (p2, r2)| {
58                if e1 == *e2 {
59                    // don't collide with self
60                    return;
61                }
62
63                if e1 > *e2 {
64                    // Simple trick to prevent collisions from being detected
65                    // twice with the entities reversed.
66                    return;
67                }
68
69                // Check for collision
70                let d_sqr = distance_sqr(p1, p2);
71                let r_sqr = sqr(r1.value + r2.value);
72                if r_sqr > d_sqr {
73                    println!("{e1} and {e2} collided!");
74                }
75            });
76        });
77
78    // Create a few test entities
79    for _ in 0..10 {
80        world
81            .entity()
82            .set(Position {
83                x: rand(50),
84                y: rand(50),
85            })
86            .set(Radius {
87                value: rand(10) + 1.0,
88            });
89    }
90
91    // Run the system
92    sys.run();
93
94    // Output:
95    //  532 and 539 collided!
96    //  532 and 540 collided!
97    //  534 and 538 collided!
98    //  536 and 537 collided!
99    //  536 and 540 collided!
100    //  537 and 540 collided!
101}
102
103#[cfg(feature = "flecs_nightly_tests")]
104#[test]
105fn test() {
106    let output_capture = OutputCapture::capture().unwrap();
107    main();
108    assert!(output_capture.output().lock().unwrap().len() > 0);
109}