Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/examples/no_std/library/src/lib.rs
6596 views
1
//! Example `no_std` compatible Bevy library.
2
3
// The first step to a `no_std` library is to add this annotation:
4
5
#![no_std]
6
7
// This does 2 things to your crate:
8
// 1. It prevents automatically linking the `std` crate with yours.
9
// 2. It switches to `core::prelude` instead of `std::prelude` for what is implicitly
10
// imported in all modules in your crate.
11
12
// It is common to want to use `std` when it's available, and fall-back to an alternative
13
// implementation which may make compromises for the sake of compatibility.
14
// To do this, you can conditionally re-include the standard library:
15
16
#[cfg(feature = "std")]
17
extern crate std;
18
19
// This still uses the `core` prelude, so items such as `std::println` aren't implicitly included
20
// in all your modules, but it does make them available to import.
21
22
// Because Bevy requires access to an allocator anyway, you are free to include `alloc` regardless
23
// of what features are enabled.
24
// This gives you access to `Vec`, `String`, `Box`, and many other allocation primitives.
25
26
extern crate alloc;
27
28
// Here's our first example of using something from `core` instead of `std`.
29
// Since `std` re-exports `core` items, they are the same type just with a different name.
30
// This means any 3rd party code written for `std::time::Duration` will work identically for
31
// `core::time::Duration`.
32
33
use core::time::Duration;
34
35
// With the above boilerplate out of the way, everything below should look very familiar to those
36
// who have worked with Bevy before.
37
38
use bevy::prelude::*;
39
40
// While this example doesn't need it, a lot of fundamental types which are exclusively in `std`
41
// have alternatives in `bevy::platform`.
42
// If you find yourself needing a `HashMap`, `RwLock`, or `Instant`, check there first!
43
44
#[expect(unused_imports, reason = "demonstrating some available items")]
45
use bevy::platform::{
46
collections::{HashMap, HashSet},
47
hash::DefaultHasher,
48
sync::{
49
atomic::{AtomicBool, AtomicUsize},
50
Arc, Barrier, LazyLock, Mutex, Once, OnceLock, RwLock, Weak,
51
},
52
time::Instant,
53
};
54
55
// Note that `bevy::platform::sync::Arc` exists, despite `alloc::sync::Arc` being available.
56
// The reason is not every platform has full support for atomic operations, so `Arc`, `AtomicBool`,
57
// etc. aren't always available.
58
// You can test for their inclusion with `#[cfg(target_has_atomic = "ptr")]` and other related flags.
59
// You can get a more cross-platform alternative from `portable-atomic`, but Bevy handles this for you!
60
// Simply use `bevy::platform::sync` instead of `core::sync` and `alloc::sync` when possible,
61
// and Bevy will handle selecting the fallback from `portable-atomic` when it is required.
62
63
/// Plugin for working with delayed components.
64
///
65
/// You can delay the insertion of a component by using [`insert_delayed`](EntityCommandsExt::insert_delayed).
66
pub struct DelayedComponentPlugin;
67
68
impl Plugin for DelayedComponentPlugin {
69
fn build(&self, app: &mut App) {
70
app.add_systems(Update, tick_timers);
71
}
72
}
73
74
/// Extension trait providing [`insert_delayed`](EntityCommandsExt::insert_delayed).
75
pub trait EntityCommandsExt {
76
/// Insert the provided [`Bundle`] `B` with a provided `delay`.
77
fn insert_delayed<B: Bundle>(&mut self, bundle: B, delay: Duration) -> &mut Self;
78
}
79
80
impl EntityCommandsExt for EntityCommands<'_> {
81
fn insert_delayed<B: Bundle>(&mut self, bundle: B, delay: Duration) -> &mut Self {
82
self.insert((
83
DelayedComponentTimer(Timer::new(delay, TimerMode::Once)),
84
DelayedComponent(bundle),
85
))
86
.observe(unwrap::<B>)
87
}
88
}
89
90
impl EntityCommandsExt for EntityWorldMut<'_> {
91
fn insert_delayed<B: Bundle>(&mut self, bundle: B, delay: Duration) -> &mut Self {
92
self.insert((
93
DelayedComponentTimer(Timer::new(delay, TimerMode::Once)),
94
DelayedComponent(bundle),
95
))
96
.observe(unwrap::<B>)
97
}
98
}
99
100
#[derive(Component, Deref, DerefMut, Reflect, Debug)]
101
#[reflect(Component)]
102
struct DelayedComponentTimer(Timer);
103
104
#[derive(Component)]
105
#[component(immutable)]
106
struct DelayedComponent<B: Bundle>(B);
107
108
#[derive(EntityEvent)]
109
struct Unwrap;
110
111
fn tick_timers(
112
mut commands: Commands,
113
mut query: Query<(Entity, &mut DelayedComponentTimer)>,
114
time: Res<Time>,
115
) {
116
for (entity, mut timer) in &mut query {
117
timer.tick(time.delta());
118
119
if timer.just_finished() {
120
commands
121
.entity(entity)
122
.remove::<DelayedComponentTimer>()
123
.trigger(Unwrap);
124
}
125
}
126
}
127
128
fn unwrap<B: Bundle>(event: On<Unwrap>, world: &mut World) {
129
if let Ok(mut target) = world.get_entity_mut(event.entity())
130
&& let Some(DelayedComponent(bundle)) = target.take::<DelayedComponent<B>>()
131
{
132
target.insert(bundle);
133
}
134
135
world.despawn(event.observer());
136
}
137
138