bevyengine / bevy

A refreshingly simple data-driven game engine built in Rust
https://bevyengine.org
Apache License 2.0
34.77k stars 3.4k forks source link

LD49 Post-Mortem -- First use of Bevy & learnings #2914

Closed djeedai closed 2 years ago

djeedai commented 2 years ago

Hi everyone,

I wanted to do a post-mortem of my participation to Ludum Dare LDJam 49 which just finished, and my first-time use of Bevy Engine. I originally planned to do some blog-style or Twitter post somewhere, but I realized many of the comments and learnings from this first use could be used to improve Bevy.

I don't want this post to be seen as any kind of attack or anything like that, so first let me say that this project is quite frankly amazing, and got me started with a game in a matter of minutes. Congrats to all contributors, this is an awesome achievement!

However I believe in constructive criticism and the value of a fresh set of eyes, which provide an insight on the barrier to entry and any friction to adoption that daily contributors might not have anymore. I hope this post will be that.

Long story short, the tech is amazing, but the documentation very unequal in amount and quality. In some areas everything is quick and intuitive, while in others I lost hours trying to do a simple thing.

What went right

Examples

Overall some of the examples helped boostrap the project. Having a working reference from where to copy/paste code proved invaluable. The examples are still missing some things, but digging through them covers most of the basic things one would want to do. I wish I'd have read them earlier, I would have saved a lot more time.

Rendering, GLTF, ECS

I didn't try anything fancy, but rendering for me just worked, which is not something that often happens. GLTF support was best explained I think from this blog post, although I struggled with the #Mesh0/Primitive0 part, as it seems object names exported from Blender didn't work (that's what I tried first). ECS finally was pretty much painless, much easier to grok than e.g. Unity's game objects and components, with an immediate intuitive idea of what to use for which purpose. There were some learnings along the way, but it was mostly OK.

What didn't

I've read a large parts of the discussions on the lack of Editor, so I'll ignore that part. I'll just note that I spent 1 hour trying to place a plane on top of a cube ;) Sometimes something incomplete/imperfect is better than nothing.

Bevy book

The Bevy book is a nice introduction, but falls very short as it's missing so many elementary things. I ended up relying mainly on the Unofficial Bevy Cheat Book which contains a lot of things I'd have expected to see in the official book. Is there any possibility to integrate this work into the official one?

UI

Every single use in the game of UI was a major pain. It took me hours to find (or, hack together) how to display a single word of text on the screen. The UI system looks very powerful at first, but in practice falls short due to the lack of documentation and higher-level explanation of how the layout model works. I appreciate that the UI system seems marked for redesign for next version IIRC, but still, this is such a pain at the minute that a little bit of documentation would be greatly appreciated (unless I missed it, in which case I apologize in advance).

Code comments

There is a very large amount of code published in 0.5 without any comment, rendering docs.rs close to useless. With the otherwise lack of learning resources, this makes examples the only real source of information. This is a real missed opportunity here, given how well code comments are integrated in Rust. A few lines of explanation over the most comment types (Query, Commands, ...) would go a long way I think.

Audio

Audio is too limited to be of any use (no audio looping for example). I eventually found bevy_kira_audio but its setup is not trivial (need to undo default features, then re-add a bunch of them; this is not really detailed in any of the two projects). If there is no intent to improve the built-in Audio module, which is fine, then I suggest Kira integration (or others) should probably be more prominently pushed forward and explained.

Some questions

A few questions I asked myself, which either took a long time to get answered, or I'm still wondering about:

Thanks for reading, and thanks again to all contributors for the hard work! :) Let me know if there's anything I can help with on the above points.

alice-i-cecile commented 2 years ago

Awesome feedback, thank you! I'll respond more fully below.

@cart can you convert this to a discussion? I seem to have lost my ability to do so.

alice-i-cecile commented 2 years ago

Bevy book

Yep, this is very much on the radar! https://github.com/bevyengine/bevy-website has some open PRs to implement https://github.com/bevyengine/rfcs/blob/main/rfcs/23-quick_start_book.md.

I am personally working to complete at least the first two chapters (hopefully the first three) in time for 0.6's launch.

Doc strings

https://github.com/bevyengine/bevy/pull/2365 was recently merged and greatly improves on this. We agreed!

UI

Yep, that was my experience working with it as well. I am optimistic that we can make some improvements to it (especially on the docs side) before we have a full rework ready to reduce the pain. bevy_egui is also very usable right now.

Audio

This rings true. @NiklasEi, perhaps you or another contributor can help improve the setup instructions?

alice-i-cecile commented 2 years ago

Question time! I'm going to answer all of them here; these should be spun out into their own simple issues where possible.

How to dynamically modify a mesh / material? The button.rs examples shows hot-swapping a material handle, which did the trick in showing me a pattern. I don't know though if there's a way to truly change those items dynamically, instead of switching between multiple instances.

Use ResMut<Assets<T>>::get_mut to modify the underlying data. Change the Handle<T> component to change which data you're pointing to.

How to center a text on screen? I still don't have a good answer because I still don't understand the UI layout.

https://css-tricks.com/snippets/css/a-guide-to-flexbox/ is a guide to the spec we followed that is very useful. bevy-inspector-egui is invaluable for experimenting with UI and layout. I'll let someone better at flexbox answer this particular question though, I personally had similar difficulties with layout (see #2235).

The remaining questions are all well addressed in https://github.com/bevyengine/bevy-website/pull/182, which will be part of the Bevy book in.

How to despawn all entities? I couldn't find a way, and trying to build a Vec and despawn them on state exit resulted in many crashes with "entity doesn't exist". I believe this is a race condition between systems, which made me realize they all work in parallel on those entities.

fn despawn_all_entities_system(query: Query<Entity>, mut commands: Commands){
  for entity in query.iter(){
     commands.despawn(entity);
  }
}

Alternatively:

fn despawn_all_entities_system(entity: Entities, mut commands: Commands){
  for entity in entities {
     commands.despawn(entity);
  }
}

How to access a list of existing entities, and check if an entity exists? No idea.

See above. Entities::contains is a dedicated method for this.

How to get the entity a Query component is attached to? No idea.

Add Entity as a query parameter in the first type argument.

fn who_am_i_system(query: Query<(Entity, &A), With<B>>){
   for (entity, a) in query.iter(){
      dbg!(entity);
      dbg!(a);
   }
} 

How to access if needed the World that I think is implicitly created if using only App::build().add_system(...)? No idea.

Use an exclusive system, created by calling .exclusive_system() on a function which contains &mut World as its only parameter. See the scene example for a usage in practice <3

NiklasEi commented 2 years ago

This is very valuable feedback, thank you! About your comments on Audio:

If there is no intent to improve the built-in Audio module, which is fine, then I suggest Kira integration (or others) should probably be more prominently pushed forward and explained.

There is intent to improve the built-in Audio module, it just has not been a priority yet. Apart from that, it is still an open question which audio library we want to use. This is why bevy_kira_audio exists in the first place. The idea was to build an experiment / a prototype for using Kira in Bevy. In case you have any additional feedback (e.g. about the API) I would be very interested in it. Also in light of what we want for the built-in module.

This rings true. @NiklasEi, perhaps you or another contributor can help improve the setup instructions?

I created NiklasEi/bevy_kira_audio#24 to improve the documentation on how to set up and get started. I think in Bevy itself there is no real setup to be documented. The built-in Audio module works out of the box with the default features. And I don't think we want to point to a third-party module from official documentation (we already list an Audio category on the "assets" page).

DJMcNab commented 2 years ago

Some more/alternative answers:

How to despawn all entities? I couldn't find a way, and trying to build a Vec and despawn them on state exit resulted in many crashes with "entity doesn't exist". I believe this is a race condition between systems, which made me realize they all work in parallel on those entities.

The reason you're getting those errors is because you are despawning an entity which still has 'in-flight' commands. The easiest way to avoid this is to make a custom stage to handle this despawning everything.

We added an error message for this in #2581

Please note though, in general despawning all entities is a bad idea, because in future we expect certain resources to become entities, e.g. each Window would be an entity instead, so despawning all entities would also close all windows (and thus the app, at least by default)

How to access a list of existing entities, and check if an entity exists? No idea.

I see that we do give access to Entities as a systemparam. Note that it needs to be &Entities instead of just Entities

I'm not sure whether it's actually possible to get access to the Entities in a system (or whether we'd want to). Also afaik, Entities::contain falsely returns true for certain entities, specifically those which are outside the range of currently active entities in 0.5.0, which #2581 also fixes; although you'd be unlikely to hit this false positive.

The most pure pattern to see whether an entity exists would be:

fn check_whether_entity_exists(q: Query<()>){
    let maybe_entity = ..;
    let entity_exists = q.get(maybe_entity).is_ok();
}

Of course, knowing whether an entity exists isn't too useful on its own, so you can use any other kind of query, which will then make this detect whether the entity exists and matches the given query.

djeedai commented 2 years ago

Thanks a lot everyone for the amazingly detailed answers and help on my questions! I'm very glad to hear most of them are known and even some fixed.

A few comments and answers in turn.

@alice-i-cecile

https://css-tricks.com/snippets/css/a-guide-to-flexbox/ is a guide to the spec we followed that is very useful.

Ah, well, I didn't even know the UI followed the CSS spec, otherwise that would have helped. Did I miss it or is it not documented? Already calling that out would put new users in familiar territory as there's a huge amount of resources on CSS layout (and huge amount of pain centering a text; now that all makes sense! 😂).

Add Entity as a query parameter in the first type argument.

I didn't realize Entity or Entities could be queried directly. Since the system feature from .system() looks like magic to me, it was unclear what was and what was not supported (I did find a couple of things not working). I guess I should have tried entities.

@NiklasEi

There is intent to improve the built-in Audio module, it just has not been a priority yet. Apart from that, it is still an open question which audio library we want to use. This is why bevy_kira_audio exists in the first place. The idea was to build an experiment / a prototype for using Kira in Bevy.

That sounds a bit contradictory to me maybe, or I misunderstood something. I totally get the "try as plugin" approach, which is common and good practice. But if you plan to use an external library instead of writing your own, why not just remove the default built-in one, and document that audio is at least for now only available via bevy_kira_audio? My only use case in the game was playing at start a single song in loop until the end of the app (no stop). I think that's almost the most minimal possible thing to do in a game (single method call), and yet the built-in audio doesn't support that. I don't have context nor history on that project, so maybe that's why, but from what I see the built-in audio plugin is simply not enough to be usable for most use cases, and making Kira (or another) the default (even if only via docs) would be a better experience. Thoughts?

And I don't think we want to point to a third-party module from official documentation

Well, unless that "third party" is actually the closest there is to an official implementation, with a concrete plan to merge back if the experiment goes well, no? But again, I'd rather I think have no built-in audio, with a warning if I try to use it redirecting to a GitHub issue (like the rustc compiler does) or official docs explaining why and what are the alternatives. I don't see the value in having the current built-in default (with all due respect to whoever wrote that code, which at least served to demonstrate feasibility).

@DJMcNab

Please note though, in general despawning all entities is a bad idea,

Yes; I was trying to work around some UI issue, some old UI elements affecting the layout of the ones in my next screen.

Of course, knowing whether an entity exists isn't too useful on its own, so you can use any other kind of query, which will then make this detect whether the entity exists and matches the given query.

Makes good sense. As said above I didn't realize this was at all possible. ¯\_(ツ)_/¯

Many thanks again everyone! ❤

alice-i-cecile commented 2 years ago

Ah, well, I didn't even know the UI followed the CSS spec, otherwise that would have helped. Did I miss it or is it not documented?

Not documented. If you'd like to make a very quick PR to add basic docstrings to Style that would be welcome!