{"id":15653690,"url":"https://github.com/janhohenheim/spew","last_synced_at":"2025-12-30T05:21:33.248Z","repository":{"id":143504448,"uuid":"615907951","full_name":"janhohenheim/spew","owner":"janhohenheim","description":"A simple helper for spawning objects in Bevy.","archived":true,"fork":false,"pushed_at":"2024-07-08T16:09:37.000Z","size":93,"stargazers_count":31,"open_issues_count":1,"forks_count":10,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-10-29T22:52:14.023Z","etag":null,"topics":["bevy","game-development","spawning"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/janhohenheim.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license-apache.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-03-19T02:53:39.000Z","updated_at":"2024-10-16T09:52:28.000Z","dependencies_parsed_at":"2024-03-27T01:24:02.492Z","dependency_job_id":"36baf4f9-2ff7-4173-a095-697825bd007e","html_url":"https://github.com/janhohenheim/spew","commit_stats":{"total_commits":59,"total_committers":6,"mean_commits":9.833333333333334,"dds":"0.10169491525423724","last_synced_commit":"4dedc7bd97f2852b3e7348f55065b7ba980fa2f1"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/janhohenheim%2Fspew","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/janhohenheim%2Fspew/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/janhohenheim%2Fspew/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/janhohenheim%2Fspew/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/janhohenheim","download_url":"https://codeload.github.com/janhohenheim/spew/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242711147,"owners_count":20173283,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bevy","game-development","spawning"],"created_at":"2024-10-03T12:46:31.362Z","updated_at":"2025-12-12T13:21:21.041Z","avatar_url":"https://github.com/janhohenheim.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003e [!IMPORTANT]  \r\n\u003e Starting from Bevy 0.14, we now have [observers!](https://docs.rs/bevy/latest/bevy/ecs/prelude/struct.Observer.html).\r\n\u003e Because they can do everything spew set out to do, Bevy 0.14 will be the last version supported by the plugin.\r\n\u003e From now on, spew will no longer receive updates.\r\n\u003e \r\n\u003e For an example of how I recommend to do spawning logic now, see [this PR](https://github.com/TheBevyFlock/bevy-template/pull/70)\r\n\u003e on the new semi-official Bevy jam template. \r\n\r\n# Spew\r\n\r\n[![crates.io](https://img.shields.io/crates/v/spew)](https://crates.io/crates/spew)\r\n[![docs.rs](https://docs.rs/spew/badge.svg)](https://docs.rs/spew)\r\n\r\nA simple helper for spawning objects in Bevy.\r\n\r\n## Usage\r\n\r\nFirst, create an `enum` that holds objects you might want to spawn:\r\n\r\n```rust\r\n#[derive(Debug, Eq, PartialEq)]\r\nenum Objects {\r\n    Player,\r\n    Monster,\r\n    Coin,\r\n}\r\n```\r\n\r\nThink about which data you want to pass to the spawning function. In this example, we will specify a `Transform` for the new object.\r\nNext, add the plugin to your app, noting the two types we just mentioned:\r\n\r\n```rust,ignore\r\nuse spew::prelude::*;\r\nuse bevy::prelude::*;\r\n\r\nfn main() {\r\n    App::new()\r\n    // ...\r\n        .add_plugins(SpewPlugin::\u003cObjects, Transform\u003e::default()) // \u003c--- Add the plugin\r\n    // ...\r\n        .run();\r\n}\r\n```\r\n\r\nNow, 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 `\u0026mut World` and the user provided data:\r\n\r\n```rust,ignore\r\nuse spew::prelude::*;\r\nuse bevy::prelude::*;\r\n\r\nfn main() {\r\n    App::new()\r\n    // ...\r\n        .add_spawners( // \u003c--- Register the spawn functions\r\n            (Objects::Player, spawn_player),\r\n            (Objects::Monster, spawn_monster),\r\n            (Objects::Coin, spawn_coin),\r\n        )\r\n    // ...\r\n        .run();\r\n}\r\n\r\nfn spawn_player(In(transform): In\u003cTransform\u003e, mut commands: Commands) {\r\n    commands.spawn((\r\n        Name::new(\"Spiffy the Adventurer\"),\r\n        TransformBundle::from_transform(transform),\r\n    ));\r\n}\r\n\r\nfn spawn_monster(In(transform): In\u003cTransform\u003e, mut commands: Commands) {\r\n    commands.spawn((\r\n        Name::new(\"Grumblor the Grumpy\"),\r\n        TransformBundle::from_transform(transform),\r\n    ));\r\n}\r\n\r\nfn spawn_coin(In(transform): In\u003cTransform\u003e, mut commands: Commands) {\r\n    commands.spawn((\r\n        Name::new(\"$1000\"),\r\n        TransformBundle::from_transform(transform),\r\n    ));\r\n}\r\n```\r\n\r\nFinally, we can set our spawn functions to work by sending a `SpawnEvent`:\r\n\r\n```rust,ignore\r\nuse spew::prelude::*;\r\nuse bevy::prelude::*;\r\n\r\nfn main() {\r\n    App::new()\r\n    // ...\r\n        .add_systems(Startup, setup_map)\r\n    // ...\r\n        .run();\r\n}\r\n\r\nfn setup_map(mut spawn_events: EventWriter\u003cSpawnEvent\u003cObject, Transform\u003e\u003e) {\r\n    spawn_events.send(SpawnEvent::with_data(\r\n        Objects::Player,\r\n        Transform::from_xyz(0.0, 0.0, 0.0),\r\n    ));\r\n    spawn_events.send(SpawnEvent::with_data(\r\n        Objects::Monster,\r\n        Transform::from_xyz(5.0, 0.0, 0.0),\r\n    ));\r\n    spawn_events.send(SpawnEvent::with_data(\r\n        Objects::Coin,\r\n        Transform::from_xyz(10.0, 0.0, 0.0),\r\n    ));\r\n}\r\n```\r\n\r\nYou can read through the [docs](https://docs.rs/spew) or peruse the [examples](https://github.com/janhohenheim/spew/tree/main/examples) for more use cases.\r\nOther 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.\r\n\r\n## Compatibility\r\n\r\n| bevy        | spew     |\r\n|-------------|----------|\r\n| 0.14        | 0.6      |\r\n| 0.13        | 0.5      |\r\n| 0.12        | 0.4      |\r\n| 0.11        | 0.3      |\r\n| 0.10        | 0.2      |\r\n\r\n## Motivation\r\n\r\nBevy's `Commands` API allows you to spawn new entities with arbitrary components:\r\n\r\n```rust\r\nuse bevy::prelude::*;\r\n\r\nfn spawn_player(commands: \u0026mut Commands) {\r\n    commands.spawn((\r\n        Name::new(\"Adventurer\"),\r\n        TransformBundle::from_transform(Transform::from_xyz(0.0, 0.0, 0.0)),\r\n    ));\r\n}\r\n```\r\n\r\nThis works great! We can spawn more complex objects by just adding more components like assets:\r\n\r\n```rust\r\nuse std::f32::consts::TAU;\r\nuse bevy::prelude::*;\r\n\r\nfn spawn_bullet(commands: \u0026mut Commands, asset_server: Res\u003cAssetServer\u003e) {\r\n    commands.spawn((\r\n        Name::new(\"Bullet\"),\r\n        SceneBundle {\r\n            scene: asset_server.load(\"models/bullet.gltf#Scene0\"),\r\n            transform: Transform {\r\n                translation: Vec3::new(5.0, 4.0, 12.0),\r\n                scale: Vec3::splat(0.012),\r\n                rotation: Quat::from_rotation_y(TAU / 2.),\r\n            },\r\n            ..default()\r\n        },\r\n    ));\r\n}\r\n```\r\n\r\nbut, in a real project, we would not spawn a bullet like that. The bullet would be spawned by a weapon at a certain translation.\r\nWe might thus encapsulate the bullet spawning like this:\r\n\r\n```rust,ignore\r\nuse bevy::prelude::*;\r\nfn handle_input(...) {\r\n    // ...\r\n    if should_fire_bullet {\r\n        let position = player_transform.translation;\r\n        spawn_bullet(\u0026mut commands, \u0026asset_server, position);\r\n    }\r\n}\r\n\r\nfn spawn_bullet(commands: \u0026mut Commands, asset_server: \u0026AssetServer, position: Vec3) {\r\n    commands.spawn((\r\n        Name::new(\"Bullet\"),\r\n        SceneBundle {\r\n            scene: asset_server.load(\"models/bullet.gltf#Scene0\"),\r\n            transform: Transform {\r\n                translation: position,\r\n                scale: Vec3::splat(0.012),\r\n                rotation: Quat::from_rotation_y(TAU / 2.),\r\n            },\r\n            ..default()\r\n        },\r\n    ));\r\n}\r\n```\r\n\r\nAs 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,\r\nand `spawn_bullet` has a jumble of seemingly unrelated parameters that will grow and grow over time. Growing parameter lists are not a problem\r\nwhen 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,\r\nwith all its parameters leaking into `handle_input`.\r\n\r\nThe 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! :)\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjanhohenheim%2Fspew","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjanhohenheim%2Fspew","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjanhohenheim%2Fspew/lists"}