A simple helper for spawning objects in Bevy.

Overview

Spew

crates.io docs.rs

A simple helper for spawning objects in Bevy.

Usage

First, create an enum that holds objects you might want to spawn:

#[derive(Debug, Eq, PartialEq)]
enum Objects {
    Player,
    Monster,
    Coin,
}

Think about which data you want to pass to the spawning function. In this example, we will specify a Transform for the new object. Next, add the plugin to your app, noting the two types we just mentioned:

use spew::prelude::*;
use bevy::prelude::*;

fn main() {
    App::new()
    // ...
        .add_plugin(SpewPlugin::<Objects, Transform>::default()) // <--- Add the plugin
    // ...
        .run();
}

Now, we are ready to register our spawn functions. Each variant of the enum will be associated with its own spawn function that takes in a &mut World and the user provided data:

use spew::prelude::*;
use bevy::prelude::*;

fn main() {
    App::new()
    // ...
        .add_spawners( // <--- Register the spawn functions
            (Objects::Player, spawn_player),
            (Objects::Monster, spawn_monster),
            (Objects::Coin, spawn_coin),
        )
    // ...
        .run();
}

fn spawn_player(In(transform): In<Transform>, mut commands: Commands) { {
    commands.spawn((
        Name::new("Spiffy the Adventurer"),
        TransformBundle::from_transform(transform),
    ));
}

fn spawn_monster(In(transform): In<Transform>, mut commands: Commands) {
    commands.spawn((
        Name::new("Grumblor the Grumpy"),
        TransformBundle::from_transform(transform),
    ));
}

fn spawn_coin(In(transform): In<Transform>, mut commands: Commands) {
    commands.spawn((
        Name::new("$1000"),
        TransformBundle::from_transform(transform),
    ));
}

Finally, we can set our spawn functions to work by sending a SpawnEvent:

use spew::prelude::*;
use bevy::prelude::*;

fn main() {
    App::new()
    // ...
        .add_system(setup_map.on_startup())
    // ...
        .run();
}

fn setup_map(mut spawn_events: EventWriter<SpawnEvent<Object, Transform>>) {
    spawn_events.send(SpawnEvent::with_data(
        Objects::Player,
        Transform::from_xyz(0.0, 0.0, 0.0),
    ));
    spawn_events.send(SpawnEvent::with_data(
        Objects::Monster,
        Transform::from_xyz(5.0, 0.0, 0.0),
    ));
    spawn_events.send(SpawnEvent::with_data(
        Objects::Coin,
        Transform::from_xyz(10.0, 0.0, 0.0),
    ));
}

You can read through the docs or peruse the examples for more use cases. Other cool stuff you can do is delay the spawning by a certain amount of frames or time or organize your spawn lists into multiple enums.

Compatibility

bevy spew
0.10 0.2.1

Motivation

Bevy's Commands API allows you to spawn new entities with arbitrary components:

use bevy::prelude::*;

fn spawn_player(commands: &mut Commands) {
    commands.spawn((
        Name::new("Adventurer"),
        TransformBundle::from_transform(Transform::from_xyz(0.0, 0.0, 0.0)),
    ));
}

This works great! We can spawn more complex objects by just adding more components like assets:

use std::f32::consts::TAU;
use bevy::prelude::*;

fn spawn_bullet(commands: &mut Commands, asset_server: Res<AssetServer>) {
    commands.spawn((
        Name::new("Bullet"),
        SceneBundle {
            scene: asset_server.load("models/bullet.gltf#Scene0"),
            transform: Transform {
                translation: Vec3::new(5.0, 4.0, 12.0),
                scale: Vec3::splat(0.012),
                rotation: Quat::from_rotation_y(TAU / 2.),
            },
            ..default()
        },
    ));
}

but, in a real project, we would not spawn a bullet like that. The bullet would be spawned by a weapon at a certain translation. We might thus encapsulate the bullet spawning like this:

use bevy::prelude::*;
fn handle_input(...) {
    // ...
    if should_fire_bullet {
        let position = player_transform.translation;
        spawn_bullet(&mut commands, &asset_server, position);
    }
}

fn spawn_bullet(commands: &mut Commands, asset_server: &AssetServer, position: Vec3) {
    commands.spawn((
        Name::new("Bullet"),
        SceneBundle {
            scene: asset_server.load("models/bullet.gltf#Scene0"),
            transform: Transform {
                translation: position,
                scale: Vec3::splat(0.012),
                rotation: Quat::from_rotation_y(TAU / 2.),
            },
            ..default()
        },
    ));
}

As you can see, this works but is quite ugly. handle_input has to pass around an asset server we might otherwise not even need in the system, and spawn_bullet has a jumble of seemingly unrelated parameters that will grow and grow over time. Growing parameter lists are not a problem when writing a system, but notice how here spawn_bullet is no longer a system but a helper function. Thus, its call will get longer and uglier over time, with all its parameters leaking into handle_input.

The solution to this is to move the spawning of the bullet into an own system that is accessed indirectly by handle_input via events, which is just what this crate helps you with! :)

You might also like...
Minecraft using Bevy and Bevy-Meshem

minecraft_bevy Minecraft_bevy was built to showcase bevy_meshem. After a week of developing it has: Chunk loading / unloading each chunk's mesh is bei

A prototype plugin providing a simple line drawing api for bevy.
A prototype plugin providing a simple line drawing api for bevy.

bevy_debug_lines A prototype plugin providing a simple line drawing api for bevy. See docs.rs for documentation. Expect breakage on master. Click on t

Simple RUST game with the Bevy Engine

Simple RUST Game using the Bevy Engine YouTube videos for this code base: Episode 1 - Rust Game Development tutorial from Scratch with Bevy Engine Epi

Simple 2d pinball game for testing of bevy and rapier.
Simple 2d pinball game for testing of bevy and rapier.

Pinball2D Using the Bevy game engine and Rapier physics engine for a simple 2D pinball game. pinball2d.mov Wrote a short piece about how the game was

A simple authoritative server networking library for Bevy.

Bevy Networking Plugin This is a simple networking plugin for the Bevy game engine. This plugin provides the building blocks which game developers can

A simple camera for properly displaying tile-based low resolution pixel perfect 2D games in bevy.
A simple camera for properly displaying tile-based low resolution pixel perfect 2D games in bevy.

Bevy Tiled Camera A simple camera for properly displaying low resolution pixel perfect 2D games in bevy. The camera will adjust the viewport to scale

Simple island generator written in rust using bevy engine
Simple island generator written in rust using bevy engine

Getting Started Easy enough to run cargo run --release Change generation speed Find the system set that looks like this .add_system_set(

Bevy is a refreshingly simple data-driven game engine built in Rust

What is Bevy? Bevy is a refreshingly simple data-driven game engine built in Rust. It is free and open-source forever! WARNING Bevy is still in the ve

Simple stupid noise primitives for WGSL and Rust (glam/bevy types)
Simple stupid noise primitives for WGSL and Rust (glam/bevy types)

noisy_bevy Simple stupid noise primitives for glam types (Vec2, Vec3) and wgsl. Main motivations are: ergonomic usage with Bevy same results on rust a

Comments
  • First spawning after the `startup` set

    First spawning after the `startup` set

    I think it is common to spawn some entities in startup systems and then assume that they get spawned before other systems are spawned.

    Following example:

    use bevy::prelude::*;
    use spew::prelude::*;
    #[derive(Debug, PartialEq, Eq)]
    enum Objects {
        Player,
    }
    fn main() {
        App::new()
            .add_plugin(SpewPlugin::<Objects, ()>::default())
            .add_spawner((Objects::Player, spawn_player))
            .add_system(player_state)
            .add_startup_system(setup)
            .run();
    }
    #[derive(Component)]
    struct PlayerMarker;
    fn spawn_player(world: &mut World, _input: ()) {
          world.spawn(PlayerMarker);
    
    }
    fn setup(mut spawn_events: EventWriter<SpawnEvent<Objects, ()>>) {
          spawn_events.send(SpawnEvent {
                object: Objects::Player,
                data: (),
          });
    }
    fn player_state(player: Query<&PlayerLabel>) {
         let _player_label = player.single();
    }
    
    

    This would crash since the event would only be processed after the first frame since the event will first be processed in the first frame and entity spawns are only processed in the last stage (I think) .

    It would be nice to have some kind of new CoreSet which checks if any startup system send spawn events and already spawns them accordingly before the normal systems begin to run

    opened by EmiOnGit 4
  • Data field should be optional

    Data field should be optional

    This is only my opinion so feel free to just close this issue :)

    The problem

    There are quite a lot of objects that don't need any input to be initialized because they are always initialized in the same way, or only depend on a resource which would have to be fetched by the world in the spawn function anyway (I guess?).

    I think a more idiomatic way would be to model it similar to how Query in bevy are modeled with the default value () if not given otherwise (for the filtering)

    opened by EmiOnGit 3
  • `SpawnEvent` has no new method

    `SpawnEvent` has no new method

    I thought I might as well checkout your new crate and see if I can provide a outside perspective :)

    The problem

    I noticed that you use following snipped in your readme

    fn setup_map(mut spawn_events: EventWriter<SpawnEvent<Object, Transform>>) {
        spawn_events.send(SpawnEvent::new(
            Objects::Player,
            Transform::from_xyz(0.0, 0.0, 0.0),
        ));
       // ...
    }
    

    but the SpawnEvent struct has no new function.

    opened by EmiOnGit 1
Releases(v0.2.1)
  • v0.2.1(Mar 20, 2023)

    • Fix changes in spawners not actually being propagated to the ECS world. Full Changelog: https://github.com/janhohenheim/spew/compare/v0.2.0...v0.2.1
    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(Mar 19, 2023)

    What's Changed

    • Simplify event creation by @janhohenheim in https://github.com/janhohenheim/spew/pull/4
    • Allow arbitrary actual systems as spawn functions by @janhohenheim in https://github.com/janhohenheim/spew/pull/5
    • Expose common system set by @janhohenheim in https://github.com/janhohenheim/spew/pull/6

    Full Changelog: https://github.com/janhohenheim/spew/compare/v0.1.1...v0.2.0

    Source code(tar.gz)
    Source code(zip)
  • v0.1.1(Mar 19, 2023)

Owner
Jan Hohenheim
I wrote a book, check it out! https://www.packtpub.com/application-development/rust-standard-library-cookbook
Jan Hohenheim
Using bevy and custom render pipelines in order to render many objects in a forest using chunks for performance.

bevy_efficient_forest_example Using bevy and custom render pipelines in order to render many objects in a forest using chunks for performance. Grass i

Henrik Djurestål 43 Jan 5, 2023
Bevy Entities are nice. Objects are better!

?? Moonshine Object An extension to Bevy which provides an ergonomic interface for managing complex Entity hierarchies. Entities are nice. Objects are

null 7 May 7, 2024
Helper functions and structs for working with 2D space in Bevy.

About Baffled by quaternions? Want to accelerate an object in 2D? Wish that there was a simple way to work with grids? Just want to know if two axis-a

Leafwing Studios 11 May 9, 2022
A helper bevy plugin to handle downloading OpenStreetMap-compliant slippy tiles

Bevy Slippy Tiles A helper bevy plugin to handle downloading OpenStreetMap-compliant slippy tiles. [DownloadSlippyTilesEvent] can be fired to request

Edouard Poitras 4 Jan 25, 2023
A Bevy helper to easily manage resources that need to persist across game sessions.

bevy-persistent A Bevy helper to easily manage resources that need to persist across game sessions. Background In games, there are a lot of resources

Umut 5 Mar 25, 2023
A simple extension for `bevy-editor-pls` to support tilemap editing right inside the bevy app.

What is this This is a simple tilemap editor plugin, that hooks right into bevy_editor_pls to work with bevy_ecs_tilemap. It works completely within i

null 3 May 8, 2023
Bevy Simple Portals is a Bevy game engine plugin aimed to create portals.

Portals for Bevy Bevy Simple Portals is a Bevy game engine plugin aimed to create portals. Those portals are (for now) purely visual and can be used t

Sélène Amanita 11 May 28, 2023
Windows game hack helper utilities in rust.

⚗️ toy-arms Windows game hack helper utilities in rust. This crate has some useful macros, functions and traits. ?? How to use this crate? With this c

s3pt3mb3r 100 Jan 1, 2023
Minecraft-esque voxel engine prototype made with the bevy game engine. Pending bevy 0.6 release to undergo a full rewrite.

vx_bevy A voxel engine prototype made using the Bevy game engine. Goals and features Very basic worldgen Animated chunk loading (ala cube world) Optim

Lucas Arriesse 125 Dec 31, 2022
bevy-hikari is an implementation of voxel cone tracing global illumination with anisotropic mip-mapping in Bevy

Bevy Voxel Cone Tracing bevy-hikari is an implementation of voxel cone tracing global illumination with anisotropic mip-mapping in Bevy. Bevy Version

研究社交 208 Dec 27, 2022