-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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 loading_screen example #3618
Conversation
Interestingly, I wonder if this would actually make more sense as an optional We want a way to add this logic to other examples quickly and without distraction, and I don't want to be importing things across examples. The other option would be to do both, but that seems very prone to drifting divergence, which would really suck. |
I am not sure that this is a good idea for a plugin. I think there are a lot of different needs for a loading screen for different games, such as a progress bar, a background image (even changing ones), text for info or tips, some more animated stuff, etc. So a fully featured plugin is a different kind of beast....and i was under the impression, that the "official" stance is to not use any external plugins for examples in the bevy repo. Whereas, with a #[path = "../common/lib.rs"]
mod common; It's not ideal, but i don't know of any other way (except using a plugin) to do this. |
That's correct. I was thinking making it an "official" optional plugin, in the sense of the
Hmm right: a plugin would be harder to extend than a code snippet that users can copy-paste.
Yeah, I'm on the fence about this. @mockersf, do you have opinions? @Weasy666 could you refactor this example to define a |
I can convert it into a plugin inside the |
e5c931b
to
ac97e76
Compare
Yeah, this was my intent. The idea is that we can reduce the amount of modification needed: every user will want to make their own The intended workflow is "find example, copy-paste into their own app", so we should make that as easy as possible. |
Ok. Is it ok like this, or did you have something different in mind? |
examples/asset/loading_screen.rs
Outdated
.add_plugins(DefaultPlugins) | ||
// Loading screen plugin and its `asset_listening_system` | ||
.add_plugin(plugin::SimpleLoadingScreenPlugin { | ||
loading_state: GameState::Loading, |
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.
I'm not sure this needs to be internal state to the plugin. It's not really use anywhere inside of it. this could just be a state on the App.
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.
Or, I think it's possible to move the asset_listening system inside the plugin. Let the plugin insert a LoadingState and have a system in the main example that simply listens to that State change
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.
It's not really use anywhere inside of it.
It is used on line 117 and 120, so that the plugin "knows" at which state it has to work and when it needs to be closed. 🙂
bevy/examples/asset/loading_screen.rs
Lines 117 to 120 in d36ceef
SystemSet::on_update(self.loading_state.clone()).with_system(animate_spinner), | |
) | |
.add_system_set( | |
SystemSet::on_exit(self.loading_state.clone()) |
Or, I think it's possible to move the asset_listening system inside the plugin.
My initial intention for this example was, to later extract the plugin into a lib in the example folder, to share it with other examples. If something like shared example code is ok within Bevy. That would mean, that the plugin doesn't know to which AssetEvent
s it has to listen. That is the reason why i left the asset_listening_system
in the main example. I wanted the plugin to take a Fn
and store it internal, but the Plugin
trait requires Send + Sync
and the Fn
would also need to be 'static
which would make it really ugly. And using a generic with IntoSystemDescriptor<Params>
bound would also not work, because it isn't Copy
or Clone
and as such can't be used as param for with_system
, because we only get it as borrowed reference inside build
. 😅
That said...if there is no chance, that this will happen, then there is no reason to not move asset_listening_system
inside the plugin.
Regarding GameState
...i thought, that we need a "global" state to make sure, that the systems run in the correct order and didn't want to impose a state to a game/app that uses the plugin.
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.
For the state, I'd rather have a LoadingState that is controlled by the plugin entirely so that examples that need loading screens could simply do .add_system_set(SystemSet::on_enter(LoadingState::Done).with_system(game_system))
. I believe states are already global by default if the struct holding the state is pub.
For the asset event issue, I didn't think about the fact that it was for specific asset types, but if it's only the gltf assets that are slow to load I wouldn't having it only for gltf. Or maybe a different plugin for each type.
Essentially, I would prefer if examples had as little code as possible related to loading assets and with the current approach it would be to verbose to use in other examples. It's still a decent example on it's own to showcase how a loading screen would work.
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.
Hm...i'm not that deep into the stages and state stuff. What happens if an example, like alien_cake_addict
, already has a state, can they be used together, is there a way to say, run LoadingState
stuff first and afterwards run the GameState
stuff?
Yeah...AssetEvents
really are the problematic part in making this generic, without manually tracking (somehow registering) assets and their events in the plugin.
Yep, this is exactly the direction I had in mind :) @IceSentry's comments are excellent, we can do a final polish pass once those are addressed. |
6f3cf91
to
f874a0e
Compare
bors try |
@Weasy666 can you pull this out of draft mode? |
With the issue that extracts the camera controller to an example_utils crate, I think this one should follow a similar pattern |
Sorry, for the late answer. This somehow slipped my mind. Oh...we now have an examples_utils crate? Cool! I'm planning to rebase and move this to the examples_utils crate in the course of this week. 🙂 |
Well, it's not merged right now, but #4458 introduces the example_utils crate |
This PR adds a new example. Adding module and item level doc comments, as described in:
would be really useful to those who will browse examples. Copypasta aside, this example is quite in line with the current standards. The only changes needed is to document the module instead of |
…ipulation, because `loading_screen` query does not work because of system ordering.
@bevyengine/docs-team can I get some eyes on this? |
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.
Not on docs team, but I'll do my best.
Suggested some changes to comply on #3951.
I also think there are too many comments. I would limit them to doc comments for all the items, and use normal comments just for things that are directly related to the scope of the example. Comments about layout, single
and first
, and such things are a little bit distracting IMO.
.add_system_set( | ||
SystemSet::on_update(LoadingState::Loading).with_system(animate_spinner), | ||
) | ||
.add_system_set( | ||
SystemSet::on_update(LoadingState::Loading).with_system(asset_listening_system), | ||
) |
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.
Not a system set expert, but wouldn't putting those two systems in the same set be the same?
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.
Yes, would also work...i can only guess, that i had a good reason for doing this...naa...probably not 🙈
.run(); | ||
} | ||
|
||
// Here we prepare our gaming scene, meaning we setup our ingame camera and load our asset. |
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.
// Here we prepare our gaming scene, meaning we setup our ingame camera and load our asset. | |
/// Here we prepare our gaming scene, meaning we setup our ingame camera and load our asset. |
Comments about items should be doc comments.
}); | ||
} | ||
|
||
// Your, or at least one of your, game systems. |
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.
// Your, or at least one of your, game systems. | |
/// Your, or at least one of your, game systems. |
//########################################## Example of a loading screen plugin ##########################################// | ||
// You can use this as a template for your own project/game. Don't forget, that you also need a system, | ||
// like `asset_listening_system`, to track your loading progress and to transition into your playing state. |
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.
//########################################## Example of a loading screen plugin ##########################################// | |
// You can use this as a template for your own project/game. Don't forget, that you also need a system, | |
// like `asset_listening_system`, to track your loading progress and to transition into your playing state. | |
/// ########################################## Example of a loading screen plugin ##########################################// | |
/// You can use this as a template for your own project/game. Don't forget, that you also need a system, | |
/// like `asset_listening_system`, to track your loading progress and to transition into your playing state. |
Honestly I'm not a fan of these decorations. I don't think we also have them in other parts of the engine.
// Setup our simple loading screen, it uses an image as spinner and a loading text bellow it. | ||
// INFO: you need to change this if you want something fancier 🙂 |
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.
// Setup our simple loading screen, it uses an image as spinner and a loading text bellow it. | |
// INFO: you need to change this if you want something fancier 🙂 | |
/// Setup our simple loading screen, it uses an image as spinner and a loading text below it. | |
/// | |
/// INFO: you need to change this if you want something fancier 🙂 |
Double space is newline in generated docs, and it is appropriate to keep the first paragraph short.
// System that listens for our `AssetEvent` and changes our game state after we finished loading our asset | ||
// INFO: you need to change this if you have different assets 🙂 |
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.
// System that listens for our `AssetEvent` and changes our game state after we finished loading our asset | |
// INFO: you need to change this if you have different assets 🙂 | |
/// System that listens for our `AssetEvent` and changes our game state after we finished loading our asset. | |
/// | |
/// INFO: you need to change this if you have different assets 🙂 |
} | ||
} | ||
|
||
// Animates aka rotates the bevy bird `UiIamge` clockwise. |
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.
// Animates aka rotates the bevy bird `UiIamge` clockwise. | |
/// Animates aka rotates the bevy bird `UiImage` clockwise. |
} | ||
} | ||
|
||
// Close our loading screen. This system is called when we exit `LoadingState::Loading`. |
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.
// Close our loading screen. This system is called when we exit `LoadingState::Loading`. | |
/// Close our loading screen. This system is called when we exit `LoadingState::Loading`. |
// we don't care about these events in our example | ||
AssetEvent::Modified { handle: _ } => {} | ||
AssetEvent::Removed { handle: _ } => {} |
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.
// we don't care about these events in our example | |
AssetEvent::Modified { handle: _ } => {} | |
AssetEvent::Removed { handle: _ } => {} | |
_ => {} |
This is a much cleaner solution, and it implicitly transmits the “I don't care about the other cases” message.
use bevy::prelude::*; | ||
|
||
/// This example illustrates, how a loading screen can be implemented. It has an animated spinner and listens for an `AssetEvent`. |
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.
use bevy::prelude::*; | |
/// This example illustrates, how a loading screen can be implemented. It has an animated spinner and listens for an `AssetEvent`. | |
//! Illustrates how a loading screen can be implemented. | |
//! | |
//! The loading screen logic is handled by the [`SimpleLoadingScreenPlugin`]. | |
//! Its functionality is based on the states defined by [`LoadingState`]. When | |
//! the example starts, the initial state is `LoadingState::Loading`. Then the | |
//! `setup_game` startup system requests that an asset gets loaded. While the | |
//! loading screen runs, the `asset_listening_system` checks if the asset has been | |
//! fully loaded. When this happens, the state is changed to `LoadingState::Done`. | |
//! This will remove the loading screen and make `game_system` run. | |
//! | |
//! [`SimpleLoadingScreenPlugin`]: plugin::SimpleLoadingScreenPlugin | |
//! [`LoadingState`]: plugin::LoadingState | |
use bevy::prelude::*; |
I changed the doc comment to module-level, as it is the new standard. I also added a more comprehensive description.
Now superseded by the likes of bevy_new_2d. |
Objective
As stated here, bevyengine/bevy-website#236, the examples with big assets can be problematic, depending on the internet connection.
Solution
Add a
loading_screen
example and expose its system for other examples. This should (hopefully) be possible, with this.This is a draft PR, because i first want to get feedback on the
loading_screen
example, if the way i do it, is the preferred one, or if there is a better one. Aaaaand...i didn't have more time today. Hope i can integrate it intoload_gltf
andupdate_gltf_scene
example tomorrow. Are there more examples where aloading_screen
makes sense?