-
Notifications
You must be signed in to change notification settings - Fork 31
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
Remove audio
+ assets
modules in favor of raw Bevy APIs and thin LoadResource API
#264
Conversation
…n LoadResource API
audio
+ assets
modules in favor of raw Bevy APIs and thin LoadResource APIsaudio
+ assets
modules in favor of raw Bevy APIs and thin LoadResource API
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Some first thoughts:
- I have no big thoughts on the asset organization. Personally, I have enjoyed knowing exactly which file I needed to look at if I wanted to change an asset, but I'm sure I would be happy with your solution as well after playing around with it 🙂
- I don't have much personal preference for the audio, other than that I would prefer having a central bottleneck through which all SFX flows as I can then easily control things like "how many sound effects are allowed to play at once?". But such an abstraction is fairly easy to build yourself, so I wouldn't block on that. I however heavily suspect that @alice-i-cecile will disagree with the lack of audio abstraction here as this version comes directly from her design. In fact, since this API is coming from here PR to the Bevy examples, this is closer to Bevy code than to bevy_quickstart code 😅
- If the asset loading can be made to resemble the future official solution, I'm all for it! 😄
Approving the PR since I have nothing against it really. Will wait with merging until others have bikeshed it.
Overall opinions:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall I'm not opposed to this: it's simpler, and well-suited to a jam. I still think it's harder to polish up, but that's fine in this context.
In general you all are describing a Bus API: context-specific mixable audio targets (ex: A "background music" bus, a "sound effects" bus, etc). This is definitely something Bevy should support, but I will assert that pretty much any abstraction we try to build in bevy-quickstart will be:
I will assert that this is not the platform to be designing such an API. The experts haven't been engaged and the oversight here is too low. In general, I would like to (again) urge everyone to be conservative when it comes to abstraction building. We should favor doing things "the bevy way" and drive improvements upstream when things are lacking. Adding new abstractions to the template should be a last resort. They should be very scoped and augment the "bevy" way of doing things. I do agree that it makes sense to be able to categorize and control playback of audio. I think we already have a good tool for that ... marker components (which yall are already making use of in fn play(mut commands: Commands, player_assets: Res<PlayerAssets>) {
commands.spawn((
PlayerBundle {
source: player_assets.step().clone(),
settings: PlaybackSettings::DESPAWN,
},
SoundEffect,
))
}
fn adjust_sound_effect_volume(sinks: Query<&AudioSink, With<SoundEffect>) {
for sink in &sinks {
sink.set_volume(0.5);
}
} I think this is already significantly preferable to the proposed APIs.
This is going to happen no matter what in the context of scenes, which will each have their own audio that will be loaded and unloaded as the scene is loaded and unloaded. I also think that is "good design" generally (with or without scenes), as it allows people to build cohesive / standalone sets of functionality that nest into a larger whole. I will assert that constructing a thing that knows every possible piece of music that could play ahead of time prevents modularization for very little benefit. We can answer questions like "what is playing" and "how do we cross-fade" without having an uber-struct. In fact, I consider those problems to be fully independent of "where do handles live". Finding what is currently playing is a question for the live data on the spawned entities, not an uber-handle-manager-resource. Any view you try to build there will be incomplete and risks being out of date. Ditto for cross fading (which includes answering the question "what is playing" and then adjusting the volume per-frame between old and new audio entities). If/when/how these things happen is context specific. Any abstraction you try to build over them has a high risk of not being the right fit. Hiding these mechanisms from users isn't doing them any favors. Again, I think marker components and raw Bevy Audio APIs are the move here. |
I've added marker components, per the discussion above. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds fair enough. Thanks for the explanation. The marker components indeed would make something like "play only 25 SFX at the same time" or "generally crossfade between all BGM" easy to implement: just add an observer for Trigger<OnAdd, SoundEffect>
.
I'll leave some minor comments, but I fully agree with the PR now :)
We actually already went from Sfx
to SoundEffects
and then back again to Sfx
because we noticed that the extra wording ended up making the code more verbose but not more clear. This is the reason why we are using Bgm
over Soundtrack
: it's a bit less correct, but way smaller typographically. I would like to see one of the following two changes:
- Change
SoundEffect
toSfx
andBackgroundMusic
toBgm
, or - change
BackgroundMusic
toSoundtrack
I think we should name these whatever we would call them in the context of a theoretical "volume control screen" in a game. I haven't seen I think "soundtrack" implies a more linear / intentionally listenable collection of music. I consider it to be a "more specific category" that is a subset of "background music". Aka you buy "the soundtrack" for a game. Thats not necessarily the same thing as the category of audio playing that is generally music. I'm actually most inclined to use Some prior art: |
@cart those comparisons are a very good point for using "music" over "soundtrack", you've convinced me. |
IMO code and UI are different contexts with different requirements. My personal preference would be |
I've opted for
While I do agree, generally, I also see no reason to have two separate concept names that then later need to be coupled in these contexts. Bevy generally favors unshortened names for things in the interest of clarity (with some exceptions for uber-highly trafficked types like Res and Mut). I think it makes sense to follow that convention here. In the world of autocomplete, those extra characters don't cost much. |
I think this is merge-able now. |
Ah forgot the dependency comment. |
Also worth calling out that ultimately we'd like to have something like this: #[derive(Resource, AssetCollection, Reflect, Clone)]
pub struct PlayerAssets {
pub ducky: Handle<Image>,
pub steps: Vec<Handle<AudioSource>>,
} Where the (it would probably also support defining the paths inline as attributes) |
Comments have been resolved! |
I think we shouldn't encourage something like an
assets
module containing generic things like ImageHandles, SfxHandles, BgmHandles, etc. Mixing a "footstep" sound and a "button press" sound under the same categorization is (1) not scalable to large numbers of things and (2) a missed opportunity to organize things based on context. Put "button sounds" next button logic, inside a button module. Put "footstep sounds" next to footstep logic.The whole
audio
module (PlaySfx, PlayBgm abstractions) should be removed ... too opinionated and too centralized. Triggering clips with their string name is a pattern we should not encourage. We should just use the Bevy APIs (load handles and spawn bundles to play audio). They are more than good enough, and I want people learning how to write Bevy code, not bevy-quickstart code.To replace the load tracking logic, I've added a "load resource" system, which allows us to define and load Resources as Assets. This allows us to rely on Bevy's built-in asset tracking to determine when the Resource is ready to be inserted. Using this pattern is preferable because it is much closer to what we will encourage after "high level asset-driven state transitions" are implemented.