Bevy Engine, as a Small Unity, Big Processing (P5)
Tags: gamedev, creativecoding, poem
Published: 2024-01-23 00:26:09

(This article is self-translation from [my original post in Japanese](https://qiita.com/funatsufumiya/items/b4b62ec7b044dd28e7fe). I'm sorry if not translated well.)

![2D Bloom sample of Bevy Engine](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nye5tay3zd0tpcff9sip.png) [^1]

## Introduction: Creative Coding and Processing

There are many game engines out there, what are you using now?

I like so-called creative coding, and I use, for example, Unity, UE5, [Touch Designer](https://derivative.ca/), [Notch](https://www.notch.one/), React, etc., to make what I have in mind. I always choose a tool that seems to be just right for prototyping each time.

When I wonder what the origin of creative coding is for me, I think it must be [Processing](https://processing.org/) (also called P5[^p]).

When I look back on why I love Processing, it was just "simple", as ease of use. Even today, that philosophy continues in the form of [p5.js](https://p5js.org/) and [openFrameworks](https://openframeworks.cc/ja/). For example, p5.js has an [online editor](https://editor.p5js.org/) in your browser [^2].

![p5.js online editor](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7oeon6ucusqknt0gtcm4.png)

From that time on, Processing required only one editor and nothing else, and we just enjoyed pure simplicity of writing code.

### Large-scale game engines and the in-between ravine

By the way, creative coding is a formless concept, and I consider the so-called visual editors in Blender, Unreal Engine, etc. as the same creative coding.

![Blender's geometry node](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3c8awn16bag6oiw58ed1.png) (Figure: Blender's geometry node [^3])

![Material Editor in Unreal Engine 5](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/715ii6dz8shgbgydpomk.png) (Figure: Material Editor in Unreal Engine 5 [^4])

In fact, I myself make full use of such things to give shape to my ideas, and as the word of "no code" suggests, I feel "code" has become just "a concept" nowadays.

Web browsers are also one type of engine, and "engines", not limited to game engines, are the backbone that supports our production and have become indispensable.

However, sometimes I feel a desire to go back to the roots of something lightweight and easy to use like Processing, or I want something that combines modern concepts (such as reactive programming in React) and ease of use, in other words, **something in between Unity and Processing**, which I can get my hands on immediately, without having to wait for dozens of GB of editors to download [^5].

## Bevy Engine, as a in-between Unity and Processing

While I was thinking about above, I came across the [Bevy Engine](https://github.com/bevyengine/bevy).

![3D Gizmos example of Bevy Engine](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n9vv445jfs45lq5disez.png) [^6]

Bevy Engine is open source and has not been developed for many years, although, there are already many volunteer [plug-ins](https://bevyengine.org/assets/#assets), just like [add-ons to openFrameworks](https://ofxaddons.com/).

Similar to Processing and openFrameworks, the core is written small, with such plugin systems being added **as you need**.

And most importantly, you basically don't need any tools other than Rust (cargo). First, create an empty project with `$ cargo new bevy-hello` [^bash], move to the project folder with `$ cd bevy-hello`, add bevy as a library with `$ cargo add bevy`, and then just paste any code in `src/main.rs` (e.g. the following) and run `$ cargo run` to get it working.

```rust
// hello world example of src/main.rs

use bevy::prelude::*;

fn main() {
    App::new()
        //.add_plugins(DefaultPlugins) // uncomment this to show the window
        .add_systems(Startup, hello_world)
        .run();
}

fn hello_world() {
    println!("hello world");
}
```

![hello world with VSCode editor](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7wilehnp8do0naef1f7g.png)

It takes a while to start (build, compile) the first time, but after the second time it reloads surprisingly fast and can hot-reload assets if you need.

## Short look at ECS (Entity Component System)

![ECS's mock-up diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gx5ycrfpyf4kwxunugio.png) (Figure: ECS's mock-up diagram [^e])

### First, "System".

Now that we have written what is called "Hello World," let's take a look at some other code.

```rust
// (first part omitted)

fn main() {
    App::new()
        .add_plugins(DefaultPlugins) // this is a magic spell
        .add_systems(Startup, setup)
        .add_systems(Update, (system, rotate_camera, update_config))
        .run();
}
```

This is the beginning of the code taken from a sample called [3D Gizmos](https://bevyengine.org/examples/3D%20Rendering/3d-gizmos/), where `add_systems(Startup, ...) ` and `add_systems(Update, ...) ` registers functions, in terms of [Processing ](https://processing.org/),  `setup` (a function called only once) and `draw` (a function called every time when updating).

Let's take a look at one of the functions actually registered.

```rust
fn system(mut gizmos: Gizmos, time: Res<Time>) {
    gizmos.cuboid(
        Transform::from_translation(Vec3::Y * 0.5).with_scale(Vec3::splat(1.)),
        Color::BLACK,
    );
    gizmos.rect(
        Vec3::new(time.elapsed_seconds().cos() * 2.5, 1., 0.),
        Quat::from_rotation_y(PI / 2.),
        Vec2::splat(2.),
        Color::GREEN,
    );
    
    // (last part omitted)
}
```

Here's the amazing part: if you specify a **type** for the arguments that points to what you want, and it will automatically bind that value. It's a trick that could be called [DI (Dependency Injection)](https://en.wikipedia.org/wiki/Dependency_injection),  how cool :)

`Startup` basically does registering elements, like  HTML or JSX in React. The elements are updated by functions registered in `Update`, which is equivalent to JavaScript in HTML.

We call this group of functions **"System"**, and basically everything that does any work is written in "System" [^7].

The difference from `draw` in Processing is that **the drawing itself is basically done automatically** [^d]. So, instead of `draw`, it's called `update`, and in `update`, basically only parameters such as values and components are changed, not the drawing itself. This is similar to React and others.

### All are Entity, all attributes are Component, all data are Resource

And this is where it is similar to Unity (strictly speaking [Unity DOTS](https://unity.com/dots)): all elements are derived from something called `Entity`. Everything is `Entity` (same as `Game Object` in Unity), so it is easy to handle in a unified way, and furthermore, all attributes are derived from `Component`, and since `Component`s exist under the same concept in Unity, it is easy to understand how to read them.

In addition, all data that you want to keep, which are so-called variables, become `Resource`, and assets such as images and 3D data are `Asset`. This is also simple and easy to understand.

And how to get them from the `System` is the same as before: declare a **type** as an argument and it will fetch them for you [^8]. It's magic.

```rust
fn check_zero_health(
    // Access Entity with `Health` and `Transform` Component.
    // Get `Health` as read-only, get `Transform` as mutable.
    // Optional: get the `Player` Component if it exists
    mut query: Query<(&Health, &mut Transform, Option<&Player>)>,
) {
    // Get all matching Entities
    for (health, mut transform, player) in query.iter_mut() {
        eprintln!("Entity at {} has {} HP.", transform.translation, health.hp);

        // If HP is 0, move to center
        if health.hp <= 0.0 {
            transform.translation = Vec3::ZERO;
        }

        if let Some(player) = player {
            // here Entity is `Player`.
        }
    }
}

// code cited from (includes comments, but I translated into English from Japanese):
// https://xianliang2032.hatenablog.com/entry/2021/09/28/Rust_Bevy_Query%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6
```
I would like to keep just as introduction to this architecture, which is called **ECS (Entity Component System)**, but you can see that it has the same general-purpose mechanisms as Unity and others.

![Unity and Bevy terminology correspondence chart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3lm54uy1qvl9894r4zut.png) (Figure: Unity and Bevy terminology correspondence chart)

## Other features: Cross-platform, low-level drawing engine abstraction, etc. (skips today)

![Cross platform check table](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s4logfdp38x7whdcw7j1.png) [^g]

There are many other interesting features of the Bevy Engine, such as the `wgpu` mechanism, which allows automatic cross-platform support for DirectX, Metal, Vulkan, WebGL, etc. with a single code, but skips description today, because it would be commonplace in Unity and other platforms nowadays.

## Last one: Plug-in system for more and more extensions / e.g. Inspector, Gizmo, Particles ...etc...

Finally, I would like to mention a few things about plug-ins. For example, if you get greedy, you may wish to have an "editor" like Unity. Plug-ins can do it.

![Bevy editor plug-in like Unity](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2qrr01npplb937ma06rg.png) [^9]

For example, if you want a GPU particle system, you can use [bevy_hanabi](https://github.com/djeedai/bevy_hanabi), with display a more casual inspector, [bevy-inspector-egui](https://github.com/ jakobhellermann/bevy-inspector-egui) can be used to.

![bevy_hanabi and bevy-inspector-egui](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nwabeaalse6uacaqbo3w.png)

The list of plug-ins is endless, but at last if you felt "want to write a UI in HTML!", a plugin called [belly](https://github.com/jkb0o/belly) will do it for you.

![belly for bevy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9pnigxlckisl3mqh7ih0.png)

This kind of casual extension is fun part of any engine, and thanks to the ECS architecture, I'm happy to be able to use it in parallel and well-ordered with other `Entity`, `Component`, and other structures without any discomfort.

**p.s.** Bevy Plug-in list is here: https://bevyengine.org/assets/#assets, and here https://github.com/topics/bevy-plugin 

## Summary: Merging "past" and "future" of Creative Coding will be...?

Now, I have introduced the Bevy Engine as a "just fit" product in between, for those of you who are tired of Unity, Unreal Engine (and other game engines), and who are wondering what to do next to Processing in your programming classes. 

By the way, if you actually try to write a game with the Bevy Engine, you will be surprised at how hard it is to understand the errors that Rust produces... (LOL 😂) [^10]

...Half joking but... it's largely a matter of getting used to it, but Bevy Engine is designed so that you don't have to be so conscious of ownership and lifetime (which are difficult parts of Rust) thanks to the component system called ECS. And probably in the future, something like the Bevy Engine will be available from general languages such as TypeScript, and I feel that this may be the future of creative coding.

Bevy has only been around for a short period of time, so there is no handy sketch sharing platform online like p5.js, or ~~there is no~~ web-site or list of add-ons (**p.s.** [Bevy plug-ins list](https://bevyengine.org/assets/#assets) 
 already existed in official!), but already [Example](https://bevyengine.org/examples/) can be viewed interactively with WebGL, and I think such a future is just around the corner.

I hope that little by little, from a place like this, the best of each of the "past" and "future" of creative coding can be merged well together.

<hr>

## Additional information

- You can use [shadplay](https://github.com/alphastrata/shadplay) as the same kind of tool like [ShaderToy](https://www.shadertoy.com/) for `wgsl` shader language, it's useful if you want to try only effects without worrying about ECS, or debugging purposes [^dc].

[^1]: quoted and reconstructed from https://bevyengine.org/examples/2D%20Rendering/bloom-2d/.

[^p]: Originally, Processing had used the domain proce55ing.net, it became origin of P5. see https://en.wikipedia.org/wiki/Processing#History.

[^2]: As a side note, cultures such as [Tweet Processing](https://twitter.com/TweetProcessing) is also interesting related to one-liners.

[^3]: Image cited from https://forest.watch.impress.co.jp/docs/serial/blenderwthing/1373040.html (Japanese article).

[^4]: Image cited from https://docs.unrealengine.com/5.0/en-US/organizing-a-material-graph-in-unreal-engine/.

[^5]: Just to follow up on the capacity thing, capacity and specs are relative, and I think the impression of what simplicity is will always change. In fact, Processing at the time was about 300 MB, which was not small in capacity. So, in the context of this article, I'll assume here that simplicity means keeping the core simple by using plugin systems, abstractions, etc. (Unity, for example, is already simple enough, I think).

[^6]: quoted and reconstructed from https://bevyengine.org/examples/3D%20Rendering/3d-gizmos/.

[^bash]: Commands beginning with `$` refer to what you type into the terminal. (Omit the `$` and type what follows.)

[^e]: Figure cited from https://blog.mozvr.com/introducing-ecsy/.

[^7]: "System" also allows you to specify dependencies and create combinations (called sets), but this is redundant and will not be discussed here.

[^d]: Note that this does not mean that you cannot customize your drawing, as there is a good balance provided between high-level APIs such as ECS, low-level APIs for the drawing engine itself (wgpu), and mid-level APIs that fall in between. Using mid-level APIs or low-level APIs, assured that the shader pipeline and various buffer objects can be manipulated.

[^8]: Code cited from  (includes comments, but I translated into English from Japanese) https://xianliang2032.hatenablog.com/entry/2021/09/28/Rust_Bevy_Query%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6.

[^g]: Table cited from https://bevy-cheatbook.github.io/gpu/intro.html.

[^9]: Image cited from https://zenn.dev/eloy/articles/ea11899ee3dbe4 (Japanese article).

[^10]: I omitted it in the article, but when you actually write the code, if you put [rust-analyzer in VSCode](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer), the completion will work perfectly, so you are now ready. Have a happy coding!

[^dc]: Information was received from the official Bevy Discord [community](https://bevyengine.org/community/). I really appreciate all the support from the community.