A Client/Server game networking plugin using QUIC, for the Bevy game engine.

Overview

Bevy tracking crates.io

Bevy Quinnet

A Client/Server game networking plugin using QUIC, for the Bevy game engine.

QUIC as a game networking protocol

QUIC was really attractive to me as a game networking protocol because most of the hard-work is done by the protocol specification and the implementation (here Quinn). No need to reinvent the wheel once again on error-prones subjects such as a UDP reliability wrapper, some encryption & authentication mechanisms, congestion-control, and so on.

Most of the features proposed by the big networking libs are supported by default through QUIC. As an example, here is the list of features presented in GameNetworkingSockets:

  • Connection-oriented API (like TCP): -> by default
  • ... but message-oriented (like UDP), not stream-oriented: -> by default (*)
  • Supports both reliable and unreliable message types: ->by default
  • Messages can be larger than underlying MTU. The protocol performs fragmentation, reassembly, and retransmission for reliable messages: -> by default (frag & reassembly is not done by the protocol for unreliable packets)
  • A reliability layer [...]. It is based on the "ack vector" model from DCCP (RFC 4340, section 11.4) and Google QUIC and discussed in the context of games by Glenn Fiedler [...]: -> by default.
  • Encryption. [...] The details for shared key derivation and per-packet IV are based on the design used by Google's QUIC protocol: -> by default
  • Tools for simulating packet latency/loss, and detailed stats measurement: -> Not by default
  • Head-of-line blocking control and bandwidth sharing of multiple message streams on the same connection.: -> by default
  • IPv6 support: -> by default
  • Peer-to-peer networking (NAT traversal with ICE + signaling + symmetric connect mode): -> Not by default
  • Cross platform: -> by default, where UDP is available

-> Roughly 9 points out of 11 by default.

(*) Kinda, when sharing a QUIC stream, reliable messages need to be framed.

Features

Quinnet has basic features, I made it mostly to satisfy my own needs for my own game projects.

It currently features:

  • A Client plugin which can:
    • Connect/disconnect to/from one or more server
    • Send & receive unreliable and ordered/unordered reliable messages
  • A Server plugin which can:
    • Accept client connections & disconnect them
    • Send & receive unreliable and ordered/unordered reliable messages
  • Both client & server accept custom protocol structs/enums defined by the user as the message format.
  • Communications are encrypted, and the client can authenticate the server.

Although Quinn and parts of Quinnet are asynchronous, the APIs exposed by Quinnet for the client and server are synchronous. This makes the surface API easy to work with and adapted to a Bevy usage. The implementation uses tokio channels internally to communicate with the networking async tasks.

Roadmap

This is a bird-eye view of the features/tasks that will probably be worked on next (in no particular order):

  • Previous roadmap tasks
  • Security: More certificates support, see certificates-and-server-authentication
  • Feature: Implement unordered & ordered reliable message channels on client & server, see channels
  • Feature: Implement unreliable message channel on client & server
  • Feature: Implement unreliable messages larger than the path MTU from client & server
  • Performance: feed multiples messages before flushing ordered reliable channels
  • Clean: Rework the error handling in the async back-end
  • Clean: Rework the error handling on collections to not fail at the first error
  • Documentation: Fully document the API

Quickstart

Client

  • Add the QuinnetClientPlugin to the bevy app:
 App::new()
        // ...
        .add_plugin(QuinnetClientPlugin::default())
        // ...
        .run();
  • You can then use the Client resource to connect, send & receive messages:
fn start_connection(client: ResMut<Client>) {
    client
        .open_connection(
            ClientConfigurationData::new(
                "127.0.0.1".to_string(),
                6000,
                "0.0.0.0".to_string(),
                0,
            ),
            CertificateVerificationMode::SkipVerification,
        );
    
    // When trully connected, you will receive a ConnectionEvent
  • To process server messages, you can use a bevy system such as the one below. The function receive_message is generic, here ServerMessage is a user provided enum deriving Serialize and Deserialize.
fn handle_server_messages(
    mut client: ResMut<Client>,
    /*...*/
) {
    while let Ok(Some(message)) = client.connection().receive_message::<ServerMessage>() {
        match message {
            // Match on your own message types ...
            ServerMessage::ClientConnected { client_id, username} => {/*...*/}
            ServerMessage::ClientDisconnected { client_id } => {/*...*/}
            ServerMessage::ChatMessage { client_id, message } => {/*...*/}
        }
    }
}

Server

  • Add the QuinnetServerPlugin to the bevy app:
 App::new()
        /*...*/
        .add_plugin(QuinnetServerPlugin::default())
        /*...*/
        .run();
  • You can then use the Server resource to start the listening server:
fn start_listening(mut server: ResMut<Server>) {
    server
        .start_endpoint(
            ServerConfigurationData::new("127.0.0.1".to_string(), 6000, "0.0.0.0".to_string()),
            CertificateRetrievalMode::GenerateSelfSigned,
        )
        .unwrap();
}
  • To process client messages & send messages, you can use a bevy system such as the one below. The function receive_message is generic, here ClientMessage is a user provided enum deriving Serialize and Deserialize.
fn handle_client_messages(
    mut server: ResMut<Server>,
    /*...*/
) {
    let mut endpoint = server.endpoint_mut();
    for client_id in endpoint.clients() {
        while let Some(message) = endpoint.try_receive_message_from::<ClientMessage>(client_id) {
            match message {
                // Match on your own message types ...
                ClientMessage::Join { username} => {
                    // Send a messsage to 1 client
                    endpoint.send_message(client_id, ServerMessage::InitClient {/*...*/}).unwrap();
                    /*...*/
                }
                ClientMessage::Disconnect { } => {
                    // Disconnect a client
                    endpoint.disconnect_client(client_id);
                    /*...*/
                }
                ClientMessage::ChatMessage { message } => {
                    // Send a message to a group of clients
                    endpoint.send_group_message(
                            client_group, // Iterator of ClientId
                            ServerMessage::ChatMessage {/*...*/}
                        )
                        .unwrap();
                    /*...*/
                }           
            }
        }
    }
}

You can also use endpoint.broadcast_message, which will send a message to all connected clients. "Connected" here means connected to the server plugin, which happens before your own app handshakes/verifications if you have any. Use send_group_message if you want to control the recipients.

Channels

There are currently 3 types of channels available when you send a message:

  • OrderedReliable: ensure that messages sent are delivered, and are processed by the receiving end in the same order as they were sent (exemple usage: chat messages)
  • UnorderedReliable: ensure that messages sent are delivered, in any order (exemple usage: an animation trigger)
  • Unreliable: no guarantees on the delivery or the order of processing by the receiving end (exemple usage: an entity position sent every ticks)

By default for the server as well as the client, Quinnet creates 1 channel instance of each type, each with their own ChannelId. Among those, there is a default channel which will be used when you don't specify the channel. At startup, this default channel is an OrderedReliable channel.

let connection = client.connection();
// No channel specified, default channel is used
connection.send_message(message);
// Specifying the channel id
connection.send_message_on(ChannelId::UnorderedReliable, message);
// Changing the default channel
connection.set_default_channel(ChannelId::Unreliable);

One channel instance is more than enough for UnorderedReliable and Unreliable since messages are not ordered on those, in fact even if you tried to create more, Quinnet would just reuse the existing ones. This is why you can directly use their ChannelId when sending messages, as seen above.

In some cases, you may however want to create more than one channel instance, it may be the case for OrderedReliable channels to avoid some Head of line blocking issues. Channels can be opened & closed at any time.

// If you want to create more channels
let chat_channel = client.connection().open_channel(ChannelType::OrderedReliable).unwrap();
client.connection().send_message_on(chat_channel, chat_message);

On the server, channels are created and closed at the endpoint level and exist for all current & future clients.

let chat_channel = server.endpoint().open_channel(ChannelType::OrderedReliable).unwrap();
server.endpoint().send_message_on(client_id, chat_channel, chat_message);

Certificates and server authentication

Bevy Quinnet (through Quinn & QUIC) uses TLS 1.3 for authentication, the server needs to provide the client with a certificate confirming its identity, and the client must be configured to trust the certificates it receives from the server.

Here are the current options available to the server and client plugins for the server authentication:

  • Client :
    • Skip certificate verification (messages are still encrypted, but the server is not authentified)
    • Accept certificates issued by a Certificate Authority (implemented in Quinn, using rustls)
    • Trust on first use certificates (implemented in Quinnet, using rustls)
  • Server:
    • Generate and issue a self-signed certificate
    • Issue an already existing certificate (CA or self-signed)

On the client:

    // To accept any certificate
    client.open_connection(/*...*/, CertificateVerificationMode::SkipVerification);
    // To only accept certificates issued by a Certificate Authority
    client.open_connection(/*...*/, CertificateVerificationMode::SignedByCertificateAuthority);
    // To use the default configuration of the Trust on first use authentication scheme
    client.open_connection(/*...*/, CertificateVerificationMode::TrustOnFirstUse(TrustOnFirstUseConfig {
            // You can configure TrustOnFirstUse through the TrustOnFirstUseConfig:
            // Provide your own fingerprint store variable/file,
            // or configure the actions to apply for each possible certificate verification status.
            ..Default::default()
        }),
    );

On the server:

    // To generate a new self-signed certificate on each startup 
    server.start_endpoint(/*...*/, CertificateRetrievalMode::GenerateSelfSigned);
    // To load a pre-existing one from files
    server.start_endpoint(/*...*/, CertificateRetrievalMode::LoadFromFile {
        cert_file: "./certificates.pem".into(),
        key_file: "./privkey.pem".into(),
    });
    // To load one from files, or to generate a new self-signed one if the files do not exist.
    server.start_endpoint(/*...*/, CertificateRetrievalMode::LoadFromFileOrGenerateSelfSigned {
        cert_file: "./certificates.pem".into(),
        key_file: "./privkey.pem".into(),
        save_on_disk: true, // To persist on disk if generated
    });

See more about certificates in the certificates readme

Logs

For logs configuration, see the unoffical bevy cheatbook.

Examples

Chat example

This demo comes with an headless server, a terminal client and a shared protocol.

Start the server with cargo run --example chat-server and as many clients as needed with cargo run --example chat-client. Type quit to disconnect with a client.

terminal_chat_demo

Breakout versus example

This demo is a modification of the classic Bevy breakout example to turn it into a 2 players versus game.

It hosts a local server from inside a client, instead of a dedicated headless server as in the chat demo. You can find a server module, a client module, a shared protocol and the bevy app schedule.

It also makes uses of Channels. The server broadcasts the paddle position every tick via the PaddleMoved message on an Unreliable channel, the BrickDestroyed and BallCollided events are emitted on an UnorderedReliable channel, while the game setup and start are using the default OrdrerdReliable channel.

Start two clients with cargo run --example breakout, "Host" on one and "Join" on the other.

Examples can be found in the examples directory.

Compatible Bevy versions

Compatibility of bevy_quinnet versions:

bevy_quinnet bevy
0.2-0.3 0.9
0.1 0.8

Limitations

  • QUIC is not available in a Browser (used in browsers but not exposed as an API). For now I would rather wait on WebTransport("QUIC" on the Web) than hack on WebRTC data channels.

Credits

Thanks to the Renet crate for the inspiration on the high level API.

License

bevy-quinnet is free and open source! All code in this repository is dual-licensed under either:

at your option. This means you can select the license you prefer! This dual-licensing approach is the de-facto standard in the Rust ecosystem and there are very good reasons to include both.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Comments
  • Feature suggestion: add the ability for a

    Feature suggestion: add the ability for a "client application" to handle multiple connections

    First of all I must say that this crate is very good and I hope it will continue to improve.

    Suggested feature

    I think it would be nice that a "client application" could manage several connections at the same time.

    Use cases

    One of the use cases would be to make a server list menu where the client would send requests to each server to know their status, ping, number of connected players, etc. (a la Minecraft)

    Implementation ideas

    • Make the Client resource capable of handling multiple connections
    • Make the Client resource a component to have multiple clients in one application
    opened by Lemonzyy 5
  • Gracefully disconnect connections and trigger events

    Gracefully disconnect connections and trigger events

    Two somewhat related fixes in this PR:

    1. The client and server will now attempt to process pending messages before closing. Previously, the following pattern would cause a race.
    send_message(...);
    close_connection(...);
    
    1. A separate wait task is spawned to wait on closed connections in order to signal the ConnectionLostEvents.
    opened by zheilbron 3
  • Expose a function for retrieving stats about a connection

    Expose a function for retrieving stats about a connection

    I wanted a way for exposing ConnectionStats and came up with a quick POC of storing the internal Quinn connection when the successful connection is made. This lets you call .stats() on it later on, which is useful for grabbing the RTT / net stats for observability.

    I'm not sure if this is the best way about going about it, so I'm up for amending this in whichever way you see fit! (I'm not sure if we want to just re-export the ConnectionStats struct from quinn-proto, it seems quinn itself doesn't re-export this for some reason.. )

    opened by andrewvy 2
  • [API] Unneeded use of `&mut self` on some `Endpoint` send methods

    [API] Unneeded use of `&mut self` on some `Endpoint` send methods

    The Issue

    While using this library, I noticed that some Endpoint send methods are &mut self and some are just &self. Looking further, it looks like the method for sending payloads is just &self, meaning that potentially none of these send methods need to be &mut self?

    opened by Kneelawk 1
  • Add send channels

    Add send channels

    Add send channels to Quinnet:

    • Changes:

      • OrderedReliable
      • UnorderedReliable
      • Unreliable
      • Add 2 new important API calls on server & client: open_channeland close_channel (and a few minor utilities such as some try_ functions)
      • Add new error types and rename ambiguous ChannelClosed to InternalChannelClosed
    • Task list:

      • [x] Channels on the client
      • [x] Channels on the server
      • [x] Default channels creation
      • [x] Keep the current simple API working by default
      • [x] Open & close channels at runtime
      • [x] Graceful shutdown, wait for all channels to be properly flushed and finished
      • [x] Share channels implementation
      • [x] Documentation
    • Implement channel types:

      • [x] OrderedReliable
      • [x] UnorderedReliable
      • [x] Unreliable
    opened by Henauxg 0
  • Multiple connections & connection opening/closing

    Multiple connections & connection opening/closing

    • Adds support for the client plugin to handle multiple server connections simultaneously
    • Also adds support for opening & closing a connection multiple times which was previously not possible

    Connections are opened/closed from the Client resource.

    Alternatives:

    Another approach was attempted on the connection-component branch. in this other branch, each connection is a component on an entity spawned by the client. Although it allows for some Bevy ECS style access to the connections, I found that it polluted the ECS World too much with objects that make more sense as global objects in a resource.

    opened by Henauxg 0
  • [Enhancement] Add ability to use domain names for client connections

    [Enhancement] Add ability to use domain names for client connections

    The Issue

    Currently, client connections can only be specified as IP address strings. It would be handy if applications could also specify a domain name to connect to.

    As an alternative, this library could let applications specify separate connection IP addresses and certificate domains, allowing them to do their own DNS resolution.

    opened by Kneelawk 1
  • [Enhancement] Add event for when a connection fails

    [Enhancement] Add event for when a connection fails

    The Issue

    Currently, if a client tries to connect to a server that does not exist, then a timed out error is printed to the console but the bevy application has no way of detecting this. It would be helpful if the bevy application could tell if a connection fails so it could let users know.

    opened by Kneelawk 1
  • [Bug] No way to specify IPv6 address in client `ConnectionConfiguration`

    [Bug] No way to specify IPv6 address in client `ConnectionConfiguration`

    The Issue

    Attempting to specify an IPv6 address to a client-side ConnectionConfiguration, results in errors no matter how the address is formatted.

    Specifying a simple IPv6 address like ::1 causes an AddrParseError(Socket) because the IP address and port are simply concatenated with a : between them, then fed into the SocketAddr parser. However, the SocketAddr parser expects IPv6 addresses to be surrounded with square brackets, like so: [::1]. Here is the full error reported:

    thread 'tokio-runtime-worker' panicked at 'Failed to parse server address: AddrParseError(Socket)', ~/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_quinnet-0.3.0/src/client/connection.rs:378:10
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    

    Specifying a bracketed IPv6 address like [::1] causes an InvalidDnsName("[::1]") because the address is ultimately fed into an IpAddr parser when bevy_quinnet attempts to connect its Endpoint and the IpAddr parser expects IPv6 address to not be bracketed. Here is the full error reporteed:

    thread 'tokio-runtime-worker' panicked at 'Failed to connect: configuration error: InvalidDnsName("[::1]")', ~/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_quinnet-0.3.0/src/client/connection.rs:389:10
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    

    Versions

    • bevy: 0.9.1
    • bevy_quinnet: 0.3.0
    opened by Kneelawk 1
  • Make systems used in initialization of this Plugin public

    Make systems used in initialization of this Plugin public

    It is often useful to create custom Stages or SystemSets but your Plugin does not allow for putting the systems into custom Stages or SystemSets. I need to be able to insert and delete Client and Server resource at runtime and run their systems when appropriate. Simply using the following is not flexible enough:

    app
    .add_plugin(QuinnetClientPlugin::default())
    .add_plugin(QuinnetServerPlugin::default());
    

    I need the controll so that I can manage when the Client and Server resource is created and manage when the systems run.

    So make these pub please:

    bevy_quinnet::client::create_client bevy_quinnet::client::update_sync_client bevy_quinnet::client::update_sync_client bevy_quinnet::server::update_sync_server and maybe also AsyncRuntime?

    opened by tomaspecl 3
Releases(v0.3.0)
  • v0.3.0(Jan 20, 2023)

    Version 0.3.0 (2023-01-20)

    Added

    • [client & server] Add OrderedReliable, UnorderedReliable and Unreliable send channels. The existing API uses default channels, additional channel can be opened/closed with open_channel/close_channel and used with derivatives of send_message_on.
    • [client & server] Now also receive Unreliable messages
    • [client & server] Add a stats() function on a connection to retrieve statistics (thanks to Andrewvy, PR #4)
    • [server] Add a clients() function to retrieve all the connected Client ids
    • [tests] Add tests for channels, and move tests to cargo integration test directory

    Changed

    • [server] receive_message and receive_payload functions are now receive_message_from and receive_payload_from, taking a ClientId as parameter (clients messages are now stored on separate queues to prevent a client from filling the shared queue)
    • [client] Expose ConnectionId as pub in ConnectionEvent and ConnectionLostEvent (thanks to Zheilbron, PR #5)
    • [example:breakout] Make use of Unreliable and UnorderedReliable channels
    • Updated dependencies

    Fixed

    • [client & server] Enhancement on disconnection behaviours, existing outgoing messages are now flushed (thanks to Zheilbron, PR #6)
    • [client] Do not fail in store_known_hosts_to_file if the path has no prefix
    • [server] Do not fail in write_certs_to_files if the cert and key files have non-existing parent directories, create them instead
    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(Nov 18, 2022)

    Version 0.2.0 (2022-11-18)

    Added

    • New events: ConnectionEvent and ConnectionLostEvent on both client & server
    • Implemented Trust on First Use authentication scheme on the client
      • Added CertificateVerificationMode for client : SkipVerification, SignedByCertificateAuthority and TrustOnFirstUse
      • New client events for the certificate verification: CertInteractionEvent, CertTrustUpdateEvent and CertConnectionAbortEvent
    • Added new ways to handle server certificates with CertificateRetrievalMode: GenerateSelfSigned, LoadFromFile & LoadFromFileOrGenerateSelfSigned
    • Client can now have multiple connections simultaneously to multiple servers
    • Server now returns the generated/loaded certificate
    • It is now possible to host a server locally on a client
      • New example: Bevy breakout demo as a 2 players versus game, hosted from a client
    • New open_connection & close_connection methods on the client
    • New start_endpoint and close_endpoint on the server
    • New is_listening method on the server
    • New "try" methods that log the errors
    • Added tests
    • Added documentation

    Changed

    • Client & Server configurations now taken as parameter at connection/listen time rather than from a resource. (User can still store it inside a resource)
    • Raised DEFAULT_INTERNAL_MESSAGE_CHANNEL_SIZE in client to 100
    • Use thiserror internally
    • Update Quinn to 0.9
    • Update Bevy to 0.9 (by Lemonzy)
    • Updated all dependencies (minors)
    • Moved chat demo to its own directory
    Source code(tar.gz)
    Source code(zip)
  • v0.1.0(Oct 25, 2022)

Owner
Gilles Henaux
Software engineer. Interested in all kinds of languages, rendering, game engines and software things.
Gilles Henaux
Simple event-based client-server networking library for Bevy

Bevy Client Server Events Simple event-based client-server networking library for Bevy. Easily send bevy events to/from a client/server without worryi

Edouard Poitras 5 Sep 20, 2023
Bevy Simple Portals is a Bevy game engine plugin aimed to create portals.

Portals for Bevy Bevy Simple Portals is a Bevy game engine plugin aimed to create portals. Those portals are (for now) purely visual and can be used t

Sélène Amanita 11 May 28, 2023
Minecraft-esque voxel engine prototype made with the bevy game engine. Pending bevy 0.6 release to undergo a full rewrite.

vx_bevy A voxel engine prototype made using the Bevy game engine. Goals and features Very basic worldgen Animated chunk loading (ala cube world) Optim

Lucas Arriesse 125 Dec 31, 2022
A simple authoritative server networking library for Bevy.

Bevy Networking Plugin This is a simple networking plugin for the Bevy game engine. This plugin provides the building blocks which game developers can

Matthew Fisher 35 Jan 1, 2023
Brine is my attempt at writing a Minecraft client in Rust using the Bevy game engine.

Brine Brine is my attempt at writing a Minecraft client in Rust using the Bevy game engine. It's EXTREMELY work-in-progress. The thing that makes Brin

Ben Reeves 34 Dec 26, 2022
Inspector plugin for the bevy game engine

bevy-inspector-egui This crate provides the ability to annotate structs with a #[derive(Inspectable)], which opens a debug interface using egui where

Jakob Hellermann 517 Dec 31, 2022
Crossterm plugin for the bevy game engine

What is bevy_crossterm? bevy_crossterm is a Bevy plugin that uses crossterm as a renderer. It provides custom components and events which allow users

null 79 Nov 2, 2022
Hanabi — a particle system plugin for the Bevy game engine.

Hanabi — a particle system plugin for the Bevy game engine

Jerome Humbert 256 Dec 30, 2022
Tweening animation plugin for the Bevy game engine.

?? Bevy Tweening Tweening animation plugin for the Bevy game engine. Features Animate any field of any component or asset, including custom ones. Run

Jerome Humbert 135 Dec 23, 2022
A plugin to enable random number generation for the Bevy game engine.

bevy_turborand A plugin to enable random number generation for the Bevy game engine, built upon turborand. Implements ideas from Bevy's Deterministic

Gonçalo Rica Pais da Silva 15 Dec 23, 2022
A spectator camera plugin for the Bevy game engine

bevy_spectator A spectator camera plugin for the Bevy game engine. Controls Action Key Forward W Left A Backward S Right D Up Space Down LControl Alt.

Jonah Henriksson 5 Jan 2, 2023
A game of snake written in Rust using the Bevy game engine, targeting WebGL2

Snake using the Bevy Game Engine Prerequisites cargo install cargo-make Build and serve WASM version Set your local ip address in Makefile.toml (loca

Michael Dorst 0 Dec 26, 2021
A Bevy Engine plugin for making 2D paths, smooth animations with Bezier curves

bevy_pen_tool A Bevy Engine plugin for making 2D paths and smooth animations with Bezier curves TODO: Mesh-making functionality for building 2D shapes

Eli 36 Dec 22, 2022
Bevy engine + miniquad render plugin

Bevy engine + miniquad renderer This is a plugin for Bevy engine that replaces default windowing and rendering plugins with miniquad based one. Usage

Tomasz Sterna 31 Dec 9, 2022
Solana Game Server is a decentralized game server running on Solana, designed for game developers

Solana Game Server* is the first decentralized Game Server (aka web3 game server) designed for game devs. (Think web3 SDK for game developers as a ser

Tardigrade Life Sciences, Inc 16 Dec 1, 2022
Proof-of-concept of getting OpenXR rendering support for Bevy game engine using gfx-rs abstractions

Introduction Proof-of-concept of getting OpenXR rendering support for Bevy game engine using gfx-rs abstractions. (hand interaction with boxes missing

Mika 52 Nov 14, 2022
🌎 Demo for Minecraft-like procedural generation using the Bevy game engine

infinigen This is a demo for Minecraft-like procedural generation using the Bevy game engine. chunks along all axes (X, Y and Z) adjustable zoom level

James Hiew 16 Jun 11, 2023
2d Endless Runner Game made with Bevy Game Engine

Cute-runner A 2d Endless Runner Game made with Bevy Game Engine. Table of contents Project Infos Usage Screenshots Disclaimer Project Infos Date: Sept

JoaoMarinho 2 Jul 15, 2022
A game made in one week for the Bevy engine's first game jam

¿Quien es el MechaBurro? An entry for the first Bevy game jam following the theme of "Unfair Advantage." It was made in one week using the wonderful B

mike 20 Dec 23, 2022