bevy_hanabi
bevy_hanabi copied to clipboard
Spawning particle effect in PostUpdate crashes
Crate versions
bevy
version: 0.14.1
bevy_hanabi
version: 0.12.2
Describe the bug
Spawning a new entity with ParticleEffect
component in PostUpdate
schedule results in unwrap:
thread 'Compute Task Pool (1)' panicked at /<...>/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bevy_hanabi-0.12.2/src/render/mod.rs:2107:59:
called `Option::unwrap()` on a `None` value
Expected behavior I would expect any schedule to be valid for spawning particle effects.
To Reproduce
Here is a diff for examples/spawn_on_command
to reproduce this crash:
Diff
diff --git a/examples/spawn_on_command.rs b/examples/spawn_on_command.rs
index 7b4c0b5..42f324b 100644
--- a/examples/spawn_on_command.rs
+++ b/examples/spawn_on_command.rs
@@ -56,12 +56,15 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
app.add_plugins(WorldInspectorPlugin::default());
app.add_systems(Startup, setup)
- .add_systems(Update, (utils::close_on_esc, update))
+ .add_systems(PostUpdate, (utils::close_on_esc, update))
.run();
Ok(())
}
+#[derive(Resource)]
+struct Storage(Handle<EffectAsset>);
+
#[derive(Component)]
struct Ball {
velocity: Vec2,
@@ -119,7 +122,7 @@ fn setup(
.insert(Name::new("ball"));
// Set `spawn_immediately` to false to spawn on command with Spawner::reset()
- let spawner = Spawner::once(100.0.into(), false);
+ let spawner = Spawner::once(100.0.into(), true);
let writer = ExprWriter::new();
@@ -186,24 +189,17 @@ fn setup(
.render(ScreenSpaceSizeModifier),
);
- commands
- .spawn(ParticleEffectBundle::new(effect))
- .insert(Name::new("effect"));
+ commands.insert_resource(Storage(effect));
}
fn update(
+ mut commands: Commands,
+ storage: Res<Storage>,
mut balls: Query<(&mut Ball, &mut Transform)>,
- mut effect: Query<(&mut EffectProperties, &mut EffectSpawner, &mut Transform), Without<Ball>>,
time: Res<Time>,
) {
const HALF_SIZE: f32 = BOX_SIZE / 2.0 - BALL_RADIUS;
- // Note: On first frame where the effect spawns, EffectSpawner is spawned during
- // PostUpdate, so will not be available yet. Ignore for a frame if so.
- let Ok((mut properties, mut spawner, mut effect_transform)) = effect.get_single_mut() else {
- return;
- };
-
for (mut ball, mut transform) in balls.iter_mut() {
let mut pos = transform.translation.xy() + ball.velocity * time.delta_seconds();
let mut collision = false;
@@ -231,9 +227,7 @@ fn update(
transform.translation = pos.extend(transform.translation.z);
if collision {
- // This isn't the most accurate place to spawn the particle effect,
- // but this is just for demonstration, so whatever.
- effect_transform.translation = transform.translation;
+ let mut properties = EffectProperties::default();
// Pick a random particle color
let r = rand::random::<u8>();
@@ -248,7 +242,14 @@ fn update(
properties.set("normal", normal.extend(0.).into());
// Spawn the particles
- spawner.reset();
+ commands
+ .spawn(ParticleEffectBundle {
+ effect: ParticleEffect::new(storage.0.clone()),
+ effect_properties: properties,
+ transform: transform.clone(),
+ ..default()
+ })
+ .insert(Name::new("effect"));
}
}
}