A 2D rust game engine focused on portability.

Overview

Emerald Crates.io License: MIT Discord chat

The Cross Platform Engine

Emerald is designed to be as lightweight as possible, while remaining a fully-featured and cross-platform game engine.

The api is simple and powerful, giving you direct access to physics, audio, graphics, game worlds, and asset loading.

Supported Platforms

OpenGL MacOS Linux Windows RaspberryPi HTML5

--- Work in progress ---

Android
--------------------------

Asset Loading

let my_sprite = emd.loader()
    .sprite("my_sprite.png")
    .unwrap();

let my_audio = emd.loader()
    .sound("my_sound.wav")
    .unwrap();

Physics

Creating Bodies

    let entity = emd.world().spawn((Transform::from_translation((0.0, 0.0))));

    let body_handle = emd.world().physics().build_body(
        entity,
        RigidBodyBuilder::dynamic()
    );


    emd.world().physics().build_collider(
        body_handle,
        ColliderDesc::cuboid(6.0, 6.0)
    );

    // You can alternatively build both the entity and body at once.
    let (entity, body_handle) = emd.world()
        .spawn_with_body(
            (Transform::from_translation((0.0, 0.0))),
            RigidBodyBuilder::dynamic()
        )?;

Physics Stepping

    emd.world()
        .physics()
        .step();

You decide when physics steps! This makes it very easy to "pause" the game without needing to alter any data.

Graphics

The default method to draw the game is to draw all of the entities in the current world. However, you can write your own draw function if you need to do more!

fn draw(&mut self, mut emd: Emerald) {
    emd.graphics().begin();

    emd.graphics().draw_world();

    emd.graphics().render();
}

Audio

let my_sound = emd.loader().sound("sounds/my_song.ogg")?;

emd.audio().mixer("background_music")?.play_and_loop(my_sound);

ECS

Emerald uses the Entity Component System paradigm for creating, managing, and updating game entities.

Emerald uses Hecs under the hood for fast entity iteration, and a remarkably clean query Api.

More detailed features can be found in the Hecs documentation.

for (id, (sprite, mut position)) in emd.world().query::<(&Sprite, &mut Position)>().iter() {
    position.x += 10.0;
}

Aseprite

Emerald has built in aseprite loading and rendering. Simply load in the file, then tell it which animations to play.

let mut aseprite = emd.loader().aseprite("my_sprite.aseprite").unwrap();

aseprite.play("some_aseprite_animation");

emd.world().spawn((aseprite, Position::zero()));

Alternatively, Emerald can load a sprite sheet exported from aseprite.

let mut aseprite = emd.loader()
    .aseprite_with_animations("my_texture.png", "my_animation.json").unwrap();

Export settings Preferred export settings

WASM

Build

cargo build --target wasm32-unknown-unknown

Asset Loading

In order to keep a clean, simple API, and avoid network requests for assets. Emerald takes the approach of packing all necessary assets into the WASM binary.

This same method can be used to pack all assets into the game binary regardless of which platform you target.

Use the pack_bytes function to load data into the engine.

fn initialize(&mut self, mut emd: Emerald) {
    /// Pack all game files into WASM binary with path references
    /// so that the regular file loading Api is supported.
    #[cfg(target_arch = "wasm32")]
    {
        emd.loader()
            .pack_bytes(
                "bunny.png",
                include_bytes!(".bunny.png").to_vec()
            );
    }

    /// We can now load texture/sprites via the normal Api,
    /// regardless of which platform we're targeting.
    let sprite = emd.loader()
        .sprite("bunny.png")
        .unwrap();
    
    // Default transform at 0.0, 0.0
    let mut transform = Transform::default();

    self.count = 1000;
    emd.world().spawn_batch(
        (0..1000).map(|_| {
            transform.translation.x += 6.0;
            transform.translation.y += 1.0;
            let mut s = sprite.clone();
            (transform.clone(), s, Vel { x: 5.0, y: 3.0 })
        })
    );
}

Android

Build

Recommended way to build for Android is using Docker.

docker run --rm -v $(pwd)":/root/src" -w /root/src notfl3/cargo-apk cargo quad-apk build --example physics

See miniquad readme and cargo-quad-apk for more details.

Asset Loading

Add following to Cargo.toml and load assets as usual:

[package.metadata.android]
assets = "YOUR_ASSETS_DIRECTORY/"

Demos

  • Links
  • To
  • Hosted
  • WASM demos
  • with source code
Comments
  • Dependency conflict

    Dependency conflict

    Two versions of nix are causing this conflict, I guess

    ... Compiling nix v0.23.1 Compiling nix v0.24.2 ... Compiling minimp3 v0.5.1 error[E0308]: mismatched types --> /home/pc/.cargo/registry/src/github.com-1ecc6299db9ec823/cpal-0.13.5/src/host/alsa/mod.rs:245:21 | 244 | let handle = match handle_result { | ------------- this expression has type std::result::Result<host::alsa::alsa::PCM, (host::alsa::alsa::Error, host::alsa::alsa::nix::errno::Errno)> 245 | Err((_, nix::errno::Errno::EBUSY)) => return Err(BuildStreamError::DeviceNotAvailable), | ^^^^^^^^^^^^^^^^^^^^^^^^ expected enum host::alsa::alsa::nix::errno::Errno, found enum nix::errno::Errno | = note: perhaps two different versions of crate nix are being used?

    error[E0308]: mismatched types --> /home/pc/.cargo/registry/src/github.com-1ecc6299db9ec823/cpal-0.13.5/src/host/alsa/mod.rs:246:21 | 244 | let handle = match handle_result { | ------------- this expression has type std::result::Result<host::alsa::alsa::PCM, (host::alsa::alsa::Error, host::alsa::alsa::nix::errno::Errno)> 245 | Err((, nix::errno::Errno::EBUSY)) => return Err(BuildStreamError::DeviceNotAvailable), 246 | Err((, nix::errno::Errno::EINVAL)) => return Err(BuildStreamError::InvalidArgument), | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum host::alsa::alsa::nix::errno::Errno, found enum nix::errno::Errno | = note: perhaps two different versions of crate nix are being used?

    error[E0308]: mismatched types --> /home/pc/.cargo/registry/src/github.com-1ecc6299db9ec823/cpal-0.13.5/src/host/alsa/mod.rs:302:21 | 301 | let handle = match handle_result { | ------------- this expression has type std::result::Result<&mut host::alsa::alsa::PCM, (host::alsa::alsa::Error, host::alsa::alsa::nix::errno::Errno)> 302 | Err((, nix::errno::Errno::ENOENT)) | Err((, nix::errno::Errno::EBUSY)) => { | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum host::alsa::alsa::nix::errno::Errno, found enum nix::errno::Errno | = note: perhaps two different versions of crate nix are being used?

    error[E0308]: mismatched types --> /home/pc/.cargo/registry/src/github.com-1ecc6299db9ec823/cpal-0.13.5/src/host/alsa/mod.rs:302:59 | 301 | let handle = match handle_result { | ------------- this expression has type std::result::Result<&mut host::alsa::alsa::PCM, (host::alsa::alsa::Error, host::alsa::alsa::nix::errno::Errno)> 302 | Err((, nix::errno::Errno::ENOENT)) | Err((, nix::errno::Errno::EBUSY)) => { | ^^^^^^^^^^^^^^^^^^^^^^^^ expected enum host::alsa::alsa::nix::errno::Errno, found enum nix::errno::Errno | = note: perhaps two different versions of crate nix are being used?

    error[E0308]: mismatched types --> /home/pc/.cargo/registry/src/github.com-1ecc6299db9ec823/cpal-0.13.5/src/host/alsa/mod.rs:305:21 | 301 | let handle = match handle_result { | ------------- this expression has type std::result::Result<&mut host::alsa::alsa::PCM, (host::alsa::alsa::Error, host::alsa::alsa::nix::errno::Errno)> ... 305 | Err((_, nix::errno::Errno::EINVAL)) => { | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum host::alsa::alsa::nix::errno::Errno, found enum nix::errno::Errno | = note: perhaps two different versions of crate nix are being used?

    error[E0308]: mismatched types --> /home/pc/.cargo/registry/src/github.com-1ecc6299db9ec823/cpal-0.13.5/src/host/alsa/mod.rs:720:36 | 720 | Err(err) if err.errno() == nix::errno::Errno::EPIPE => { | ^^^^^^^^^^^^^^^^^^^^^^^^ expected enum host::alsa::alsa::nix::errno::Errno, found enum nix::errno::Errno | = note: perhaps two different versions of crate nix are being used?

    Compiling nalgebra v0.31.2 error[E0308]: mismatched types --> /home/pc/.cargo/registry/src/github.com-1ecc6299db9ec823/cpal-0.13.5/src/host/alsa/mod.rs:803:40 | 803 | Err(err) if err.errno() == nix::errno::Errno::EPIPE => { | ^^^^^^^^^^^^^^^^^^^^^^^^ expected enum host::alsa::alsa::nix::errno::Errno, found enum nix::errno::Errno | = note: perhaps two different versions of crate nix are being used?

    For more information about this error, try rustc --explain E0308. error: could not compile cpal due to 7 previous errors warning: build failed, waiting for other jobs to finish...

    opened by coldloaded 7
  • Hot reloading assets

    Hot reloading assets

    Hot reloading assets during development is a big quality of life improvement, we should add a feature hotreload that tracks asset files.

    Sprites - Track texture files, reload them in the rendering engine on change. Aseprites - Track both animation files and sprite files, reload them in the rendering engine on change. Sounds - Track sound files, track sound progress, reload them at the point they were playing at on change.

    enhancement ux 
    opened by Bombfuse 4
  • Some questions regarding this project

    Some questions regarding this project

    Hi, I have some questions regarding this project:

    1. Does it use wgpu by any chance? If not would it be implemented in the near future?
    2. Would it ever support 3D graphics as well?
    3. Is there egui integration?
    4. Is there a community for emerald such as Discord or something?
    5. Does it lock you into a framework like Bevy does or can you code things freely, like in Macroquad?
    6. How does the performance compare with other game engines, is it supposed to be high performance?
    7. Does it use [Rapier[(https://rapier.rs/) physics engine? If not what physics engine does it use then?
    8. Just curious how come you chose hecs over all the other ecs other such as legion?
    opened by Raj2032 3
  • platform icons for dark theme

    platform icons for dark theme

    This is a very minor thing, but as a dark theme user, looking at your repo I noticed that the icons for the supported platforms are nearly invisible for me (and other dark theme users).

    Since I was already fiddling with them for something else I took the liberty to add a white background, if you're interested: icons.zip

    opened by PSteinhaus 3
  • Physics Bodies only get cleaned up when the world is replaced/removed

    Physics Bodies only get cleaned up when the world is replaced/removed

    Physics bodies need to be automatically cleaned up when an entity is despawned, as well as let users remove them manually.

    To alter how despawn to remove physics bodies from the world, will likely need to fork hecs and integrate it directly into the engine.

    bug 
    opened by Bombfuse 3
  • Fix compile errors on wasm

    Fix compile errors on wasm

    MP3 is disabled because kira v0.5.3 uses minimp3 v0.5.1 for decoding, but it depends on slice-deque v0.3.0 that has following issue: https://github.com/gnzlbg/slice_deque/issues/86

    Still not figured out how to run compiled wasm, but at least it compiles.

    opened by iliakonnov 2
  • Autotilemap

    Autotilemap

    Initial feature set for AutoTilemaps. Support rulesets that determine the tile id, in the future these tiles will be able to be baked into physics colliders.

    opened by Bombfuse 1
  • Support rendering with multiple cameras

    Support rendering with multiple cameras

    My use case was to render regular entities in screen space, regardless of the regular camera position, though maybe this could also be useful for split screen rendering.

    opened by sapir 1
  • Memory Leak in Rendering Engine

    Memory Leak in Rendering Engine

    https://github.com/Bombfuse/emerald/blob/master/src/rendering/engine.rs#L396

    Creating a new render pass leaves memory behind and does not get cleaned up. Only create render passes when absolutely necessary, and re-use existing ones.

    bug 
    opened by Bombfuse 1
  • Asynchronously load textures automatically

    Asynchronously load textures automatically

    Textures can be loaded asynchronously until they need to be drawn, when they're called to be drawn, finish the loading synchronously if it hasn't finished.

    opened by Bombfuse 1
  • User and asset file pathing

    User and asset file pathing

    Files are loaded from the user data directory, and the asset directory. The user can change the root path for each directory.

    This change allows people to use simple paths for their assets. This also improves portability because the engine can automatically define where the USER_DATA_DIR and ASSETS_DIR should default to, per platform. Example, windows would store user data in AppData for the game, macOS would store it in the Library for the game. Assets on android will be easier to access also.

    Before: loader().sprite("./assets/my_thing.png") After: loader().sprite("my_thing.png")

    opened by Bombfuse 1
  • Function to get current monitor resolution

    Function to get current monitor resolution

    Just a little quality of life feature I'd like to see. I'd also suggest changing emd.screen_size() to emd.window_size() and reuse the old name for the new function to prevent confusion. I will attempt to look into it and implement it on my own. If it's decent then I'll create a pr with the changes.

    opened by JustASpeedrunner 0
  • 2d light system?

    2d light system?

    First of all, I found this project really reliable and fun! My only concern is there any way to implement 2d light system? if not it would be nice to have this feature.

    opened by rairou 1
  • Input handler for actions

    Input handler for actions

    An option to bind more than one input to a single input action. For example Godot input actions and Unity's new InputSystem. In Godot, there are several ways how to interact with actions, all of which take into account the deadzone (default 0.5). ref: Input | InputMap Input.is_action_pressed - true if any associated input is held Input.is_action_just_pressed / released - true only for one frame Input.get_action_strength - 0.0 to 1.0 for analogue input and 0 or 1 for other Input.get_axis( negative_action, positive_action ) - gives result (example right_action minus left_action)

    For more naming examples/influence: Gamemaker: key_check - true if the button is held key_check_pressed / key_check_released - true for one frame

    Unity: GetKey - true if a key is held GetKeyDown / GetKeyUp - true for one frame

    opened by nezvers 1
  • Hotreload example explanation

    Hotreload example explanation

    Hi, As a just-born Rustacian coming from weekend C, I conveniently landed on this project by trying to track the engine of Rebel Transmute. This is the first project I encountered examples of rust libraries and learned how to use them. Then I went through them but for the Hotreload, I have no clue how actually utilize it. It would be great if it had some comments or language tooltip documentation on how it is used.

    P.S. I love what I'm seeing with this project and I think I'll be able to help a bit after I catch up with the Rust language.

    opened by nezvers 3
  • User Level Shaders

    User Level Shaders

    After discussion on the rust gamedev discord, it sounds like WGSL is the best user-facing shader language to use.

    I think we should use naga as middleware to convert the users WGSL to Emerald's current shader langauge (GLSL).

    enhancement portability 
    opened by Bombfuse 3
  • Video Player Component

    Video Player Component

    Let's add a Video Player Component to the engine.

    Playing video is pretty valuable for a game engine.

    • Playing Cutscenes
    • Tutorial Videos
    • Game Intros

    A Video Player Component would take in the following data in order to function (please add more if you think of anything else a video player component would need)

    • Video File Path
    • Clip Target (if a user only wants to show a select portion of the video, for example, the bottom right corner of the video. Default clip is none, resulting in the entire video being displayed)
    • Audio Mixer name (the audio mixer this video should output to)
    • Audio Volume (default 100%)
    • Looping (default false)

    Should probably target FFMPEG as the first file format for Video Player Component.

    enhancement 
    opened by Bombfuse 0
Releases(0.1.9.1)
Owner
bombfuse
lead/programmer @gemdropgames wishlist https://store.steampowered.com/app/1651500/Harvest_Hero_Origins
bombfuse
2-player game made with Rust and "ggez" engine, based on "Conway's Game of Life"

fight-for-your-life A 2-player game based on the "Conway's Game of Life", made with Rust and the game engine "ggez". Create shapes on the grid that wi

Petros 3 Oct 25, 2021
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
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
A Client/Server game networking plugin using QUIC, for the Bevy game engine.

Bevy Quinnet A Client/Server game networking plugin using QUIC, for the Bevy game engine. Bevy Quinnet QUIC as a game networking protocol Features Roa

Gilles Henaux 65 Feb 20, 2023
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
Work-in-progress Nintendo Switch emulator, written in Rust and slightly less focused on gaming

pegasus Work-in-progress Nintendo Switch emulator, written in pure Rust and slightly less focused on gaming Information This project aims to be a diff

XorTroll 21 Nov 22, 2022
Entity Component System focused on usability and speed.

Shipyard ⚓ Shipyard is an Entity Component System focused on usability and speed. If you have any question or want to follow the development more clos

Dylan Ancel 524 Jan 1, 2023
A refreshingly simple data-driven game engine built in Rust

What is Bevy? Bevy is a refreshingly simple data-driven game engine built in Rust. It is free and open-source forever! WARNING Bevy is still in the ve

Bevy Engine 21.1k Jan 4, 2023
RTS game/engine in Rust and WebGPU

What is this? A real time strategy game/engine written with Rust and WebGPU. Eventually it will be able to run in a web browser thanks to WebGPU. This

Thomas SIMON 258 Dec 25, 2022
unrust - A pure rust based (webgl 2.0 / native) game engine

unrust A pure rust based (webgl 2.0 / native) game engine Current Version : 0.1.1 This project is under heavily development, all api are very unstable

null 368 Jan 3, 2023
A no-frills Tetris implementation written in Rust with the Piston game engine, and Rodio for music.

rustris A no-frills Tetris implementation written in Rust with the Piston game engine, and Rodio for music. (C) 2020 Ben Cantrick. This code is distri

Ben Cantrick 17 Aug 18, 2022
Rust implementation of Another World (aka Out of this world) game engine

RustyWorld Rust implementation of Another World (aka Out of this world) game engine. I wanted a fun project to challenge myself while learning Rust, a

Francesco Degrassi 3 Jul 1, 2021
Simple RUST game with the Bevy Engine

Simple RUST Game using the Bevy Engine YouTube videos for this code base: Episode 1 - Rust Game Development tutorial from Scratch with Bevy Engine Epi

null 150 Jan 7, 2023
Rust Game engine 3D (and 2D)

A feature-rich, production-ready, general purpose 2D/3D game engine written in Rust with a scene editor.

rg3d engine 5.4k Jan 9, 2023
A feature-rich, production-ready, general purpose 2D/3D game engine written in Rust with a scene editor.

A feature-rich, production-ready, general purpose 2D/3D game engine written in Rust with a scene editor.

rg3d engine 5.4k Jan 4, 2023
A Simple Rust Game Engine For 2D

VeeBee VeeBee Is A Nice And Simple Game Engine For 2D. Features Sprites & Images! Btw There Is A Built In 2D Pack (But The Textures Are REALY BAD, Sor

null 2 Feb 2, 2022
Cross-platform game engine in Rust.

Cross-platform game engine in Rust.

Fedor Logachev 1.9k Jan 3, 2023
My first Real-Time 3D Game Engine learning project written in Rust.

EyeEngine-Rust FOA, sry for my poor English. What is Eye Engine? Eye Engine is my first Real-Time 3D Game Engine learning project. There are two editi

F-seeeye 4 Jan 5, 2022