-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add spawn callback for scene entities #4933
Comments
Can you give a realistic snippet of what this proposed API would look like? I'm having a bit of trouble piecing together the design and its value. |
Yeah a snippet would be helpful. I don't think it can just take an |
Here is how I imagined it: let map = asset_server.load("my_map.gltf");
commands.spawn_scene(map).with_commands(|entity_commands| {
entity_commands.insert(RigidBody::Fixed);
}); In heron we have PendingConvexCollision and in rapier we have AsyncSceneCollider for it. In Heron it just copy physics-based components from the root and assign them to all children with meshes, but the list of components is just hardcoded. In Rapier it only assigns colliders, so I was going to submit a PR with behavior similar to heron (the author agreed on it), but then I realized that we probably could solve it here.
Yes, you are right. I think we should have a world and an |
I don't know if |
I would expect to have this callback called for each spawned entity. Here is a better example: let map = asset_server.load("my_map.gltf");
commands.spawn_scene(map).with_commands(|world, entity_commands| {
if let Some(mesh) = world.entity(entity_commands.id()).get::<Mesh>() {
// Entity have mesh, let's assign collision:
entity_commands.insert(RigidBody::Fixed);
entity_commands.insert(Collider::from_bevy_mesh(mesh));
}
}); Users will be able to check for Having EntityRef instead of |
I've came up with something here https://github.com/nicopap/bevy-scene-hook Which seems to be exactly what you are describing. The initial version only provided a |
Ok. Having read your issue more carefully. You seem to specifically not want that, but rather want a "lightweight" sort of thing, that doesn't require adding a system to the schedule. |
Looks nice. But instead of name I would use EntityRef to be able to access components. To generate collisions from mesh, for example. |
This is exactly the problem that this proposal is supposed to solve :) With |
I realized that after #2424 scenes won't be a special case anymore. I think it's an awesome change, but it also means that the suggested command API won't fit. So what if we add a component called commands.spawn_bundle(SceneBundle {
scene: asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0"),
..Default::default()
}).insert(SceneHook::new(|entity_ref, entity_commands| {
if let Some(mesh) = entity_ref.get::<Mesh>() {
// Entity have mesh, let's assign collision:
entity_commands.insert(RigidBody::Fixed);
entity_commands.insert(Collider::from_bevy_mesh(mesh));
} else if let Some(name) = entity_ref.get::<Name>() {
// Can insert some components based on name
}
})); And it should be much simpler to implement. What do you think? @nicopap already reworked his plugin to provide a similar API for 0.7 :) |
Should this be included in |
I thought of it, but declaring a boxed closure will look like this: commands.spawn_bundle(SceneBundle {
scene: asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0"),
hook: Box::new(|entity_ref, entity_commands| {
if let Some(mesh) = entity_ref.get::<Mesh>() {
// Entity have mesh, let's assign collision:
entity_commands.insert(RigidBody::Fixed);
entity_commands.insert(Collider::from_bevy_mesh(mesh));
} else if let Some(name) = entity_ref.get::<Name>() {
// Can insert some components based on name
}
}),
..Default::default()
}); Or is it okay? |
I made a prototype that mirrors this PR's |
I meant more along the lines of including Like in @nicopap's example. |
@MrGVSV, oh, right, updated the description with your suggestion.
I like it, but I would remove the trait and use hook: SceneHook::new_comp::<Name, _>(move |name, cmds| hook(&decks, name.as_str(), cmds)), and hook: SceneAssets {
deck: deck_assets.clone(),
cards: cards_assets.clone(),
}.into(), Looks confusing as to me. So I would replace |
Closing per #4980 (comment) (better to modify scenes once loaded as discussed in #3972) |
This will be solved on the Bevy side with asset preprocessing: bevyengine/bevy#4933. In the meanwhile there is a dedicated plugin that can do this and even more: https://github.com/nicopap/bevy-scene-hook.
This will be solved on the Bevy side with asset preprocessing: bevyengine/bevy#4933. In the meanwhile there is a dedicated plugin that can do this and even more: https://github.com/nicopap/bevy-scene-hook.
What problem does this solve or what need does it fill?
When spawning a scene, you often need to add additional components. For example, generate a collision from a mesh or assign a collision group.
What solution would you like?
It would be great to be able to specify a closure with EntityCommands
and EntityRef as arguments which will be called for each spawned entity from scene.
So I would suggest adding a bean called
SceneHook
with a closure that users can assign on scenes. For convenience, I would add it toSceneBundle
introduced in #2424.Example:
What alternative(s) have you considered?
SceneRoot
component that users can monitor for addition using a variety of change detection tools (was suggested by@cart
in this comment).But both approaches require adding a separate system for each scene for which you need to add components after spawn. Also it forces user to create a separate component for each scene to somehow differentiate events or added
SceneRoot
s in "post-spawn" systems.The text was updated successfully, but these errors were encountered: