Zig has not hit 1.0 yet, and as recently as a few months ago completely reworked how every form of IO is written. AFAIK, this wasn't a syntax change, but it changed the function signature or type definition of every piece of code that reads/writes a file, establishes a connection, etc. At the current time, there is little guarantee that the code you write today will still work in 5-10 years time.
HN user
james7132
Once you understand that a crate is the translation unit in Rust, it doesn't feel as bad. Most medium to large Rust project's will separate out their code into separate crates for both organization and compile time.
I've definitely cloned down my fair share of C projects, mashed the make command into my terminal, and watched the gcc/clang logs fly by and never batted an eye beyond checking the sha256sum on any downloaded tarballs.
There's a valid argument to be made about supply chain attacks, but there does exist tooling to lock that down, and I would argue that any serious software development firm should be auditing every third party dependency they take on.
Not cart, but another maintainer of Bevy here.
More traditional game engines tend to be a giant tangle of pointers with much more complex lifetimes than what Rust's borrows would allow. For example, the skeleton used to animate your character is reliant on a centralized hierarchy of transforms, which is deeply interwoven with physics, rendering, gameplay scripting, etc. These relationships and lifetimes is difficult or impossible to model with Rust's borrows, forcing the use of unsafe, and makes it harder to expose safe Rust interfaces to engine users due to Rust's aliasing rules around borrows and essentially forces the use of a scripting runtime. These factors also make it very hard to make performant multithreaded code without littering locks or channels everywhere, in any language or runtime, not just with Rust.
Bevy's ECS handles this by flattening these relationships. Instead of pointer chasing through the physics system to fetch rigidbodies which then point to the transforms, you expose the backing ECS memory as a query view: `Query<(&mut Transform, &Rigidbody)>` directly fetches all entities that have the two components without relying on one to hold a reference to the other. The lifetimes of the queried components is strictly bound to the surrounding function (a system in ECS terminology) by the borrow checker, and all of the unsafe used to create those borrows is neatly packaged behind the ECS crate boundary. This is so effective that the majority of Bevy's crates can have `forbid(unsafe_code)` enabled.
The downside here is that all of the complexity is now centralized into the bevy_ecs crate: there are many parts in it that are basically C written in Rust, but that does mean that we can focus all of our memory safety efforts on that one crate instead of making that collective responsibility of everyone in the ecosystem.
Of course, we do expose unsafe APIs from the ECS, but the use of this escape hatch explicitly demarcated, and generally you'll only see incremental performance improvements (no big-O algorithmic gains) over their safe variants. With the sole exception of `Query::get_unchecked_mut` allowing parallel access to mutable components that cannot be proven to be safe from static analysis (e.g. parallel hierarchy traversals), which enables parallelism where it otherwise would not be feasible.
I'm running a nanode for a few personal projects and their dashboard was showing something close to 8mbps since 05/29/2024. Went almost 2TB over for the month of June. Nearly 4x'ed my bill. It's not a lot, but it seems like someone's use case like mine (streaming music) could have easily exploded their monthly compute budget on this.
Just checked with nethogs, the VPS averages ~250kbps, so this is a near 32x increase in reported bandwidth usage on my end.
Given the fact that foreign values inherently require the use of unsafe due to not being able to verify anything about the value and it's behavior, yes, it's generally not recommended unless you're looking to write your own scripting integration plugin. Likewise, most of these scripting language runtimes are almost always not threadsafe in the slightest, requiring either single threading all scripted behavior, expensive locks, and heavy use of marshalling, which negates a lot of the performance benefits of the engine.
For more developer experience oriented reasons why this is done, I strongly suggest reading cart's reasons for making Bevy to begin with: https://github.com/bevyengine/bevy/discussions/8107#discussi.... More specifically the "Turtles all the way down" bullet point.
A scripting language is an explicit non-goal for first-party support, but there have been tools for using the ECS entirely without Rust types which can be exposed via FFI or embedded languages like Lua.
Just search "_by_id" in the bevy_ecs docs, and you'll find all of the associated APIs for access. There are then (unsafe) APIs for creating the internal mappings necessary to use them. These are normally called via the monomorphized generics automatically, but need to be manually called since we don't have compile time knowledge of the data being stored and accessed.
There is still a game loop that runs every tick. The engine wouldn't work so well if we only responded to inputs as they come in, event pub-sub style.
As for ECS overhead, I've made it one of my top priorities to eliminate it wherever possible since it underpins the entire engine. We're at the point where most optimizations are saving a few tens or low-hundreds of microseconds per frame in your average game/app (i.e. lowering context switch costs from parallel system execution). If you're pushing below 60 FPS in your app, chances are the performance issues are not coming from the ECS, but some other part of the engine, or the app's own code.
The blog post directly mentions efforts towards a GUI-based editor in the "What's next" section.
We can definitely deliver on global illumination in some way, as shown with the irradiance volume support added in this release, though it may not match Lumen 1:1. Nanite is definitely more involved, but worth investigating.
Fyrox definitely has a better end-to-end feature offering right now, but I personally think Bevy has the stronger ecosystem.
Animation support is growing rapidly. I'm one of the two SMEs (subject matter experts) focused on this area, and we just rounded out the final parts of the animation composition RFC. I'm hoping to get that feature to land in 0.11, but may take until 0.12 to be fully available. There's also an open PR for animating morph targets, the primary other way of deforming meshes for animation, which I think should land in 0.11. I'm also working on inverse kinematics implementation, which should round out the core "animate to move things" features. More powerful animation features are likely going to be reliant on an editor going forward though.
The editor is definitely something we're pushing hard on. Cart recently just opened a PR rewriting the asset system to better support preprocessing and more complex asset interactions, something we desperately needed for the development of an editor. I'd like to say we'll break ground on the editor before Q3 of this year, but that might be an overaggressive target.
I'm one of the maintainers of Bevy. In my opinion, Godot clearly has a significant lead in many fronts, some moreso than others. A clear few that are lagging behind are:
Editor: Godot has one, Bevy does not. Animation support: Godot has support for complex animation blending and animating anything that can be serialized. Bevy does not. Audio: Bevy's audio is pretty simple right now and lacks direct world entity driven spatial audio. Rendering: Godot has pretty deep support for higher performance and higher fidelity rendering techniques like automatic instancing and
Everything in this list is being worked on, but require time to bake. Everything else more or less has most of the core pieces in place that Godot has, though may be missing a few small features here or there.
Where is Bevy ahead?
Multithreaded CPU performance. I can almost guarantee your average Bevy app will have higher thread utilization than your average Godot/Unity/Unreal game, and this will continue to scale as more complex computations are required for various engine systems are added.
Testability: ECS makes it really easy to write dependency injection based unit tests, something otherwise difficult to test end-to-end with engines like Godot and Unity.
Extendability and customization: Bevy is plugins all the way down. Godot definitely takes a much more monolithic approach to building an engine, and making significant changes to the core engine will require forking. Where Godot requires exposing deeper APIs for exposing functionality, Bevy already supports ripping out the relevant plugins and subsituting just those with your own.
Memory safety: As the mantra goes, every 1k LoC of C/C++, there's one CVE that is yet to be found, and 70% of those are memory safety issues. Bevy heavily leverages unsafe in the ECS, but rarely touches it in the other core engine crates. We can with high confidence say there are no memory safety problems or problems caused by undefined behavior in Bevy due to Rust's strong safety guarantees.
We explicitly label easy first issues in our issue tracker: https://github.com/bevyengine/bevy/issues?q=is%3Aissue+is%3A.... These should get you up to speed with the contribution process and, at the very minimum, get your feet wet with hacking against the engine, if not dive deeper into various specifics.
I strongly suggest any of the docs issues, as it doesn't require you to write any actual functionality, but forces you to get to know the architecture, the language, and the core parts of the engine itself.
Rendering is definitely moving really fast and we have a lot of accumulated domain expertise in the area now. If you're looking to potentially bootstrap or collaborate on design in a new space: animation or audio both need a lot more love. I'm one of the two animation SMEs and I still am playing catchup to the state of the art.
I want to step back a bit. All of these require a more involved and production ready asset system, which we've sorely needed for a few releases now.
I'm one of the two developers currently behind our longer term animation efforts, and I am keeping up with the state of the art in terms of animation compression, streaming, composition, and generation, but there's still a sizable amount of groundwork and plumbing before any of that can even be attempted. We definitely need a lot more eyes on this area of the engine.
Could you point me the right direction on how to learn about Bevy's render pipeline?
The best 10,000ft view that doesn't just point you at the code itself is probably https://bevy-cheatbook.github.io/gpu/intro.html. If you need finer details, you'll need to read the code itself, or ask in the #rendering(-dev) channels on the Discord.
Again, I'm not happy with the state of public documentation for this, but as seen with this release, it's still heavily in flux. I don't think we've had a single release since 0.5 that hasn't made major architectural changes of some kind.
And what's the equivalance of Unity's Frame Debugger? Since Bevy doesn't have a GUI editor yet, I guess the answer is just to use Render Doc?
Yep, just use RenderDoc right now. I don't think we'll have a good solution for this for a long while, since building one of those from the ground up is a huge undertaking.
It's turtles all the way down. You can replace the renderer wholesale, or strip out the top, middle, and/or low level abstractions. You choose how much meat you want stripped off from the bones. It's not that well-documented (something I want to address soon), but IMO it lives up to Bevy's reputation of modularity.
For a comparison with Unity, it's equivalent to the scriptable render pipeline, but abandoning the default one doesn't mean you need to write your own pipeline from the ground up.
On the contrary, about 50% of my time with Rust is spent throwing shit at the wall and seeing if it works. The great thing is that the compiler will probably tell you that what you're doing is garbage and you might want to consider redesigning, which is where the other 50% goes. If you hack works, great, just need to get it through code review, which will probably reject most other garbage. If it doesn't, back to the drawing board, and you won't have spent the time pestering someone to read your hackjob.
And Bevy's coded in Rust! Bevy gains all of Rust's safety, ergonomics, speed; yet it avoids pitfalls with some OSS Rust products: it doesn't overuse lifetimes or macros and is relatively easy to follow.
Just uhhh... don't look at the core ECS implementation, haha. There's probably no other concentration that much use of unsafe in the entire Rust ecosystem, outside of the stdlib. Could always use some more eyes scrutinizing the design and API surface there. I'm saying this as someone who's wrote most of the optimizations to the ECS in the past 3-4 releases. Definitely have introduced (and fixed) my fair share of undefined behavior bugs due to hyper-aggressive use of unsafe.
Entity as a type is an generational ID. We only support up to 2^32 entities in a World, which makes up the bottom 32 bits. The top 32 bits is the generation. Once we destroy an entity, it's ID is reused, but the generation is increased.
Skeletal animation is supported in the renderer, and there is a (very basic) implementation of an animation player available, but more complex animation (blending, state machines, masking, IK, etc.) is currently still in the design phase right now.
Terrain and collision detection are currently reliant on a third party ecosystem integration with rapier via bevy_rapier. It may be a while before Bevy has a native physics system.
Text rendering is fully supported, and IMO is significantly better looking than anything Unity currently offers by default, though that might not be a particularly high bar, haha.
Prebuilt UI elements are in the works but not upstreamed in any way right now. The UI system has a lot of flexbox-esque primitives that currently lack a way to bind it to gameplay elements. This is a very active area of development though, given that the goal is to dogfood these UI elements for the engine's editor.
wgpu (the implementation, not the WebGPU standard) does have quite a few of those aforementioned escape hatches on native platforms. Bevy currently doesn't use many of them due to aiming for maximum platform compatibility, but their use is not off the table.
https://en.wikipedia.org/wiki/Data-oriented_design
The intent is to layout structures in memory in a way that is conducive to how it's actually accessed in the physical hardware.
For video games, this typically means leveraging contiguous pieces of memory to minimize cache misses while iterating over the objects in the game. This can see some huge performance gains over other ways of structuring the game's code.
Think of Bevy's ECS as a ultra-high performance in-memory columnar database that you're scanning 60+ times a second. Then building your game as a series of (potentially parallelizable) mutative queries over that database.
I think it's more in terms of the ergonomics and developer UX. Both Bevy and Flask have a very minimal and surprisingly idiomatic "hello world" example, and both rather seamlessly and progressively introduce concepts, which helps onboard developers into the framework/engine.
In Bevy's case, it also helps onboard the developer into engine development too, since engine code is entirely ECS based, so engine code looks nearly identical to both user and plugin code. For your typical user, this is a bit odd, but speaking as someone who went from new to the engine to helping write the headliner features for this release in the course of just a few months, this is a surprisingly empowering experience.
Most ECS implementations realistically are high-performance in-memory columnar databases, where systems use granular mutation patterns. Hell, the main access pattern is literally a called a Query. It's become quite a meme to call bevy_ecs "turning games into SQL databases". If you've used BigQuery or Redshift, you've basically just used a super-scaled up ECS engine.