I recently discovered Bevy, and it's so much fun to play with.
I wouldn't be surprised if in 2-4 years, we see some fantastic, revolutionary indie game coded in Bevy that totally breaks the mold in some way. The next Minecraft, basically.
I say that because Unreal sucks for developers who like to code in text, want a fresh blank canvas, and don't want someone else making all the decisions about how gameplay should be created: Basically, the exact same type of person who's likely to make something really cool.
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.
Plus, my understanding is that Bevy is way better at multithreading than Unreal and Unity; and consumer core counts just keep going up.
IMO, there's a big opportunity for someone(s) with resources to invest in Bevy's development somehow.
> 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.
I've been using Bevy recently, and definitely have the same feeling around future potential.
Being designed for ECS first should in theory open up a lot of potential for optimizations well beyond traditional OO game engines. You can already see that many parts of the game loop/workflow is parallelized.
I've been rendering procedurally generated chunks via Bevy's task system, and it's pretty insane how fast it is. Can generate meshes from millions of (live function queried) points and render the results with lighting, etc in a second or so leveraging SIMD and threading.
Rust really feels like the ideal language to replace C/C++ for gamedev.
How far do you think you are from a 1.0 release? What areas do you think need improvement?
I've been working on a project in Bevy for the last few weeks, having previously attempted it in TS+pixie.js and Godot. It's been a joy in comparison, with much faster progress - in TS I was constantly fighting the ecosystem, and GDScript is just awful, particularly it's type system. Thank you!
I think we're about 2 years away. Some areas that need work: a visual Bevy Editor (not built yet but we're shifting focus to it this release cycle), audio (we have it but users need finer control), animation (more composition tools and editor integrations), ui (needs more widgets and ux improvements), asset system (I've been working on the next iteration for awhile to enable things like pre-processing assets), nice visual scene editing workflows (implemented inside the upcoming Bevy Editor).
I'd be happy to donate money specially to support animation (especially morph targets) and drive that forward. [1]
We want to make a break from Unreal pixel streaming and Rust on the frontend delivered over WASM/WebGPU would be so ideal. The rest of our stack is Rust, so it would slot right in with our Rust monorepo.
[1] I was donating to one of the devs until GitHub removed PayPal payments without warning or mitigation about a week ago. I'll fix that soon.
Scene editing, fast value tweaking (like in bevy_inspector_egui) and more powerful visualization tools for things like schedules are the big "this must be visual" features that I want to land first.
Code-first is lovely, but being able to fine-tune things without a recompile is key, and the workflow needs to work for any artists on larger teams too.
It's exciting to see so much development happening in Bevy!
I see in the Bevy FAQ that you've contributed to other open source game engines. How did you get originally interested in game engine development? Are you developing a game yourself using Bevy? Or contracting with any studios using Bevy in their games?
I originally got interested in middle school because I liked videogames, technology, and art. In middle school I played with game maker and a cool piece of mmo tech called RealmCrafter. That eventually snowballed into a programming obsession, a computer science degree, ~6-ish engine prototypes in various languages and stacks, a job at Microsoft, a game called High Hat (built in Godot), Godot contributions, and ultimately Bevy.
While I hate Unity, I think one of the few things they did really well is the decision to make scriptable render pipeline. The game we're developing is high stylized. Istead of a shadow map for each spot light, we have a small shadow map for each character (rendered to a 4k altas). It's surprisingly easy to do that in Unity. Easier than in most engines, I believe.
How is Bevy going to approach this kind of render pipeline customization?
(I'm very new to Bevy. So if it's a stupid question please bear with me.)
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.
That sounds very promising. Could you point me the right direction on how to learn about Bevy's render pipeline? I've had some rather superficial understanding of Bevy (mostly just by following along the examples on the official site)
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?
> 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.
I don't mind to eventually read the code. I've learned how to use SRP by reading URP code anyway, because Unity's document in this regard isn't particularly great either ;p (of course my Rust fluency is still not at the same level of my C#).
Would you suggest Bevy for people who struggle with Rust.
Do I need to learn Rust first, or does Bevy use a limited subset of the language like Unity and C#. Although I'd argue till I'm blue in the face C# is a much easier language.
I learned Rust (and frankly, most of programming) with Bevy :) It was a good experience, although I definitely recommend learning the basics from the Rust Book as you go to reduce frustration and confusion.
In simple game code you don't need to write your own traits, use unsafe, and like laundmo says, the borrow checker pains are way easier than in most Rust codebases because there's already a nice architecture in place.
You can't code in Rust by just trying things and seeing if they work, you'll get very frustrated. This approach works for learning other languages but you'll hit a wall with Rust. Gotta read the book.
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.
It does in a way use a limited subset. Specifically, the borrow checker is rarely a concern since Bevys ECS storage abstracts that mostly away from the user.
I've been using Bevy to push me into learning Rust and it's working well for me, I haven't had to worry about lifetimes much and even without understanding references for a while I could still tinker with stuff.
Thanks! I have some questions about integrating ECS with cross-platform concerns.
How did you tackle the problem of components containing geometry for platform-specific graphics engines? Does Bevy use platform-specific components? If an application needs multiple offscreen textures to compose a frame, are there components that contain metadata for which passes they belong to (so, now, platform and pass specific components)?
We handle this class of problem in a few different ways:
1. We build on top of cross platform abstractions with feature detection (wgpu is our cross platform low level graphics library, cpal is that for audio, etc). We build our features in a way that adjust the ECS app logic according to what features are available at runtime
2. In a few cases we do "compile time feature/platform detection" to select the appropriate code for a given platform. But most "Bevy features" don't use this / we opt for (1) more than anything else
In the case of geometry: that has a "dynamic" representation that can be adjusted according to the platform context (although in practice we don't do any platform-specific geometry transforms yet). And that gets written to the platform's gpu using wgpu.
Bevy has a "render graph", which feeds on Bevy ECS data. We adapt the render graph (and the ECS data that drives it) according to the features supported on a given platform.
I've been talking with someone that got Rust working / rendering shaders on Playstation. In the past people have been able to target Switch in Rust and I suspect Xbox is pretty approachable with UWP. I have a lot of hope :)
(not _yet_ my highest priority, but others are already investigating this)
There was a user on discord a while back who got bevy running in some capacity on, I think, Xbox and Switch. He had trouble with the PlayStation, though. Since you have to sign NDAs with the companies to do that, I don't know what came of it.
The only reason we haven't merged it yet is we need to sort out a high level "app api" thing: WebGPU requires async init (as in the Rust async feature). The PR above solves this by making our plugin init async. This is the most straightforward, but it makes people put `.await` in their app init, which we're not sure is the right call yet. We're discussing alternatives that might "encapsulate" the async.
What are your expectations for Bevy's ability to compete with Unreal's Nanite and Lumen, and when might that become a priority?
Additionally, while obviously not perfect, are you following new developments in AI based animation[0] and prediction based light transport[1]? Do you expect these types of automation to eventually become first class within Bevy, or any thoughts on how they can be best integrated into a Bevy game?
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.
Congratulations! I've been closely following and donating (when I can) since your launch.
I'm now unemployed on a sabbatical, and looking to pour my heart into game development. Jumping into such a large, moving project can be intimidating. How can I get started effectively contributing to Bevy?
I'll add, a ton of work seems to be happening in rendering. This is not an area I can contribute or know enough about, but I am able/willing to help with just about everything higher level than that.
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.
Can you post on hn when the statement that reads like, "btw don't use this package if you're not cool with breaking changes every four days" leaves your docs? I pretty much immediately decided I wasn't cool with that, even though bevy looks like a really interesting project.
Real answer: Bevy is already very featureful, but we have a long way to go before we can start making "stable api guarantees". Locking things down right now would prevent us from achieving the best apis we can. We are building the engine in the open and people will naturally still take dependencies on us, even under these constraints. We are very careful about our messaging / provide warnings in the appropriate places.
In practice, migrating between versions is generally pretty straightforward and we provide migration guides to help the process. The dust is already settling on some of our APIs / they're starting to feel "stable". Many people (and companies) are happily building real products right now in Bevy (and porting them across versions).
Follow up reply: I misinterpreted your question. I thought you were saying "(How) can you post this on HN when you are still unstable". But on a re-read it sounds like you just wanted me to post on HN when we have stability guarantees. I definitely can/will! If that is what you meant, I apologize for the misread (and unnecessary cheekiness).
The problem is that "the prototyping phase" isn't a real phase, and this doesn't specify if breaking changes will occur between major, minor, or patch versions. It gives developers no guidance of what semver to track based on their own willingness to endure breaking changes. Using a library that still can't tell you that is just asking for trouble.
> Initial development releases starting with "0.y.z" can treat changes in "y" as a major release, and "z" as a minor release. "0.0.z" releases are always major changes. This is because Cargo uses the convention that only changes in the left-most non-zero component are considered incompatible.
The 0.x is essentially used as way to tell people to use at their own risk since it isn't considered stable yet. Using a library like this isn't asking for trouble if you know what you are dealing with and in the context of bevy it currently means a breaking change every 3 months with a blog post and migration guide.
I'm not saying they're breaking the law and should be arrested, I'm saying if they're breaking shit in patch release, even on v0, I refuse to touch it until v1. If you're not breaking shit in patch releases, I'll touch v0 and pin to a minor.
People can run anything they want however the fuck they want, I just won't use it. How's that?
> I'm saying if they're breaking shit in patch release
You just assumed this, but this isn't true. Bevy uses semver like most of the rust ecosystem.
The warning is just telling people that the breaking changes will be frequent. It doesn't mean they will be in a patch release. I don't understand what's to be confused about here. Bevy never specified any custom release strategy because there isn't one, it's just semver like almost everything else in rust.
> doesn't specify if breaking changes will occur between major, minor, or patch versions
What I'm telling you is that it _does_ specify that: by using a 0.x.y version they are explicitly specifying that breaking changes can occur between _any_ version. If you don't want to use Bevy because of that, then that's fine.
But you've just nailed the problem: this is NOT the convention used within Rust.
In Rust, 0.x.y would treat .y as NON-BREAKING, BACKWARDS-COMPATIBLE changes.
I don't think I'm stepping beyond the pale of reasonable engineering when I suggest that a package in the Rust ecosystem that doesn't follow the Rust semver guidance -- and doesn't EXPLICITLY STATE that they don't follow the Rust semver guidance -- is a library I won't touch.
The fact that there's so much confusion on this thread about what their semver policy actually is shows exactly why it should be stated upfront and not masked behind a generic "stability warning."
Hi, I'm on libs-api. You are incorrect. Cargo always has, since its inception, treated changes to the leftmost non-zero number in the version as semver incompatible releases. That means 0.0.1 and 0.0.2 are semver incompatible. That means 0.1.2 and 0.2.8 are semver incompatible. 0.1.2 and 0.1.8 are semver compatible.
semver says that in 0.x.y, "anything goes." But that is just not true with Cargo.
This is also documented, emphasis mine:
> This guide uses the terms "major" and "minor" assuming this relates to a "1.0.0" release or later. Initial development releases starting with "0.y.z" can treat changes in "y" as a major release, and "z" as a minor release. "0.0.z" releases are always major changes. This is because Cargo uses the convention that only changes in the left-most non-zero component are considered incompatible.
It’s more complicated than that. Maybe I’ll finally actually write a blog post.
While the semver spec has contained that line about 0.y.z, the semver spec also does not define ranges, that is, how specifying version requirements works. Cargo implements these things, like ^ and > and etc, the exact same way that every other semver implementation implements them.
That’s because very quickly the “use minor like major when major == 0” thing became the de facto way that people used semver in its earlier days. Implementations understood this, but the spec was never changed.
So Cargo does follow semver in practice, like everyone else. There’s a combination of discrepancy and under-specification in the spec; which is a great reminder that specifications tend to follow implementations, not the other way around.
It’s on my long list of things to do to eventually reconcile this in the semver specification, but it’s been a few years and I still haven’t managed it, so no promises there.
Hmmm I'm struggling to see the difference between what you're saying and what I'm (and the Cargo docs) are saying. semver says anything goes at 0.x.y:
> Major version zero (0.y.z) is for initial development. Anything MAY change at any time. The public API SHOULD NOT be considered stable.
It is also simultaneously the case that "anything may change at 0.x.y" is not true for Cargo. Cargo is stricter than "anything may change."
Maybe what you're saying is that Cargo is consistent with semver, but "just" stricter? I'd agree with that, absolutely. That is why I try hard to not say "Cargo doesn't follow semver." (Although it's easy to slip on that one.)
Yeah I should probably actually write the post, haha. Commenting between sets at the gym just isn’t the same. I’ll let you know if/when I do. This comment of yours already helped me formulate a bit of it, I think, so thanks for that.
“Just stricter” is much more accurate than “doesn’t follow”, for sure.
“No semver implementation follows the major version zero sentence in the semver spec, and Cargo does what they all do” is maybe an even closer approximation. We’ll see how good I can do with more than 60 seconds rest between typing :)
> this doesn't specify if breaking changes will occur between major, minor, or patch versions
The entire Rust ecosystem works on a model of breaking changes for 0.x version happening in minor but not patch releases. In fact, I'm struggling to think of any software project that intentionally releases breaking changes in patch releases.
I'm not sure what we're arguing about. You say "don't break bugfix releases." I say "don't break bugfix releases." Docs don't say "we don't break bugfix releases." Instead, docs say "we break all the time don't trust us" instead of "pin to a minor version if you don't want to break all the time."
It's specifically not a question of knowing how the Rust community usually does these things, it's a question of "does this package conform to Rust's semver conventions, the official semver conventions, or something custom?"
The statement, _as its written in the docs_ implies "we do something custom." Whether that's true or not is irrelevant. I read it, interpreted it as a lack of governance or adherence to standards, and moved on. Any professional engineer would do the same.
No, the statement says that there will be frequent breaking APIs, it doesn't make any claim about release strategy. Releasing breaking changes on every 0.minor release perfectly fits in this definition.
Making a quick judgement based on an assumption that's provably wrong isn't really the definition of a professional engineer.
Tell me you've never had a job without telling me you've never had a job. Not having a release strategy at all is insta-trashcan at any enterprise I've ever worked at.
You can see Bevy's release history here: https://github.com/bevyengine/bevy/releases where you can see that there have historically been releases with breaking roughly every 2 months (although the last one was back in Nov 2022)
two questions:
How big is the part of the engine that uses 'unsafe' Rust?
What systems are to be multithreaded on release? Like Rendering, Physics etc.
Bevy ECS has a good chunk of `unsafe` as we're doing granular parallel data access that the Rust compiler cannot reason about. Anything related to low-level system api bindings (Vulkan, audio, etc) is inherently unsafe. But basically all "engine logic" (like our actual renderer logic, scenes, assets, etc) is written in safe Rust. We only use unsafe if we _absolutely need to_ and give it a lot of scrutiny. Impossible to avoid it entirely in the engine space though!
The engine is very threaded in general. We do pipelined rendering so the next frame's logic is computed while the current frame is rendering, we multithread expensive potentially high-entity tasks like animation and transform propagation, all ECS systems run in parallel (which includes the renderer systems), etc. We'll use whatever cores you give us!
The blog says that Bevy currently uses Rodio as the audio library.
As I am also working on improving the Rust audio library for Glicol language (https://github.com/chaosprint/glicol), I would like to know what features are the most required for merging this into a game engine, for example the HRTF mentioned in the blog. Another feature required is to embed scripting language like Rhai (https://github.com/chaosprint/glicol/discussions/112). Anything else?
From my personal side, I would love to see more demos with both action and sound (then we can talk about latency etc.), not just the graphical side.
Particularly excited about AccessKit integration. As Bevy's announcement says, as far as we know, this makes Bevy the first general-purpose game engine with first-party accessibility support.
The whole "same engine, new assets, a lil scripting" model of game dev I can't help but think makes for a artistic monoculture. Scripting is a painkiller, not a cure, for the problem of the inflexible inscruitable C++ monster engine.
If everything is modular and in the same language, we can get less "framework-y" and more "library-y", making a porous boundary between the "game" and the "engine".
Tiny Glad is a perfect example of that. I didn't even know today they were making a game! Because it is started as just a little procedural modeling demo to be used in other games. It's great its getting attention as an actual game, but they can and definitely should eventually get the code out as a the library for use in other games too!
Edit: i was a dunce and explained data-driven, which it also is, but is not what you asked.
Bevy is data oriented due to its ECS: roughly: which data an entity has attached to it decides which behaviours are run. Want something to have a health bar? Just attach the Health { current: 50, max: 100 } struct and it will have all associated behaviour like being able to take damage. Want to make it invincible again? Just remove the Health struct.
This is different from OOP engines, where you might need to keep an is_invincible boolean around to check against.
This usually means that data is organized in ways that are friendly to cpu cache, instruction parallelism, and multithreading. Lining up data in arrays, arrays of positions instead of arrays of objects each of which has a position, and so on.
Usually this is done via an entity component system.
Mostly it has to do with internally storing "objects" as Structures of Arrays (SoA) instead of the traditional object-oriented Array of Structures (AoS) for more parallelization opportunities with SIMD improving cache efficiency. See https://en.m.wikipedia.org/wiki/Data-oriented_design
It is basically operating on the "column-oriented database" idea, which when applied to a game becomes the "Entity-Component-System" paradigm.
More performance thanks to cache locality, makes it much easier to write multithreaded gameplay code (remember, games are basically a big ol' pile of "cross-cutting concerns" [1]), as well as facilitating simulation-y code by allowing you to address game objects by arbitrary sets of properties.
---
[1]: Games often break the traditional "layers" we like to build in software architecture to enhance maintainability. That means traditionally you often get blobs of references and mutations scattered everywhere through the code. In a shooter, the visuals for a bullet need to know not only their origin and direction, but possibly the pose of any players in their path, as well as stats about the weapon, or even network latency, for a crude example.
It doesn't work currently. The only problem is that plugin initialization must be asynchronous, so you have to pass control back to the browser to allow it to initialize the WebGPU api properly[1]. I hacked async plugin initialization into a fork for Bevy 0.8[2], but I never got it to 100% work because Chrome had already moved onto a newer WGSL syntax. In theory if you do the same changes for 0.10 as I did for 0.8 it should allow WebGPU to work (and I plan on doing this in the next couple days).
I wouldn't be surprised if in 2-4 years, we see some fantastic, revolutionary indie game coded in Bevy that totally breaks the mold in some way. The next Minecraft, basically.
I say that because Unreal sucks for developers who like to code in text, want a fresh blank canvas, and don't want someone else making all the decisions about how gameplay should be created: Basically, the exact same type of person who's likely to make something really cool.
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.
Plus, my understanding is that Bevy is way better at multithreading than Unreal and Unity; and consumer core counts just keep going up.
IMO, there's a big opportunity for someone(s) with resources to invest in Bevy's development somehow.