Bevy Entities are nice. Objects are better!

Overview

🌴 Moonshine Object

crates.io downloads docs.rs license stars

An extension to Bevy which provides an ergonomic interface for managing complex Entity hierarchies.

Entities are nice. Objects are better! 😎

Overview

This crate is designed to provide a wrapper for some commonly used operations when working with entities in Bevy.

It is often required for various systems to be able to traverse complex entity hierarchies. This is especially true for initialization code when various components need to reference various entities within a hierarchy of entities.

For example, consider a system which reacts to a flying bird by flapping its wings:

use bevy::prelude::*;

#[derive(Component)]
struct Bird;

#[derive(Component)]
struct Flying;

fn setup_bird(
    query: Query<Entity, (With<Bird>, Added<Flying>)>,
    children_query: Query<&Children>,
    name: Query<&Name>,
    mut commands: Commands
) {
    for entity in query.iter() {
        if let Ok(children) = children_query.get(entity) {
            for child in children.iter() {
                if let Ok(name) = name.get(*child) {
                    if name.as_str() == "Wings" {
                        if let Ok(wings) = children_query.get(*child) {
                            for wing in wings.iter() {
                                // TODO: Flap! Flap!
                            }
                        }
                    }
                }
            }
        }
    }
}

This code is intentionally verbose to show the hierarchy complexity.

This crate tries to make these situations more ergonomic by introducing Object<T>.

It behaves like an Entity or Instance<T> with some extra features:

use bevy::prelude::*;
use moonshine_object::prelude::*;

#[derive(Component)]
struct Bird;

#[derive(Component)]
struct Flying;

fn setup_bird(birds: Objects<Bird, Added<Flying>>, mut commands: Commands) {
    for bird in birds.iter() {
        if let Some(wings) = bird.find_by_path("./Wings") {
            for wing in wings.children() {
                // TODO: Flap! Flap!
            }
        }
    }
}

Features

  • Less boilerplate when dealing with complex entity hierarchies
  • Full type safety enforced through Kind semantics
  • No macros! No registration!

Usage

Objects<T>

Use Objects<T> as a system parameter to access all Object<T> instances.

This SystemParam is designed to be used like a Query:

use bevy::prelude::*;
use moonshine_object::prelude::*;

#[derive(Component)]
struct Bird;

fn update_birds(birds: Objects<Bird>) {
    for bird in birds.iter() {
        // ...
    }
}

Like a Query, you may also use a QueryFilter:

use bevy::prelude::*;
use moonshine_object::prelude::*;

#[derive(Component)]
struct Bird;

#[derive(Component)]
struct Flying;

fn update_flying_birds(birds: Objects<Bird, With<Flying>>) {
    for bird in birds.iter() {
        // ...
    }
}

Internally, Objects<T> is just a thin wrapper around some common queries:

  • Query<Instance<T>>
  • Query<&Parent> / Query<&Children>
  • Query<&Name>

Object<T>

Each Object<T> is a reference to an Entity with type, name, and hierarchy information. This provides a convenient way to pass this data between functions:

use bevy::prelude::*;
use moonshine_object::prelude::*;

#[derive(Component)]
struct Bird;

#[derive(Component)]
struct Flying;

fn update_flying_birds(birds: Objects<Bird, With<Flying>>) {
    for bird in birds.iter() {
        flap_wings(bird);
    }
}

fn flap_wings(bird: Object<Bird>) {
    if let Some(wings) = bird.find_by_path("./Wings") {
        for wing in wings.children() {
            // TODO: Flap! Flap!
        }
    }
}

⚠️ Unlike an Entity or Instance<T>, Object<T> has a non-static lifetime and may not be used as a Query term.

Casting

Like Instance<T>, any Object<T> may be be cast into an Object<U> if T implements CastInto<U>.

You may implement this trait for your own kinds using the safe_cast macro:

use bevy::prelude::*;
use moonshine_kind::prelude::*;
use moonshine_object::prelude::*;

#[derive(Component)]
struct Bird;

struct Creature;

// Every Bird is a Creature by definition:
impl Kind for Creature {
    type Filter = (With<Bird>, /* ... */);
}

// Therefore, all birds may safely be cast into creatures:
safe_cast!(Bird => Creature);

// Birds can chirp.
fn chirp(bird: Object<Bird>) {
    // TODO: Chirp!
}

// Creatures can find food.
fn find_food(creature: Object<Creature>) {
    // TODO: Find food!
}

// Birds chirp when they get hungry.
fn handle_hunger(bird: Object<Bird>) {
    chirp(bird);
    find_food(bird.cast_into()); // Safe! :)
}

Any Object<T> is safely convertible to Object<Any>.

Support

Please post an issue for any bugs, questions, or suggestions.

You may also contact me on the official Bevy Discord server as @Zeenobit.

You might also like...
A tetris game I wrote in rust using ncurses. I'm sure that there's a better way to write a tetris game, and the code may be sus, but it techinically works
A tetris game I wrote in rust using ncurses. I'm sure that there's a better way to write a tetris game, and the code may be sus, but it techinically works

rustetris A tetris game I wrote in rust using ncurses. I'm sure that there's a better way to write a tetris game, and the code may be sus, but it tech

A Bevy plugin for loading the LDtk 2D tile map format.
A Bevy plugin for loading the LDtk 2D tile map format.

bevy_ldtk ( Tileset from "Cavernas" by Adam Saltsman ) A Bevy plugin for loading LDtk tile maps. Usage use bevy::prelude::*; use bevy_ldtk::*; fn mai

Basic first-person fly camera for the Bevy game engine

bevy_flycam A basic first-person fly camera for Bevy 0.4 Controls WASD to move horizontally SPACE to ascend LSHIFT to descend ESC to grab/release curs

An ergonomic physics API for bevy games.

Heron An ergonomic physics API for 2d and 3d bevy games. (powered by rapier) How it looks like fn main() { App::build() .add_plugins(DefaultPlug

Inspector plugin for the bevy game engine
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

A plugin for Egui integration into Bevy
A plugin for Egui integration into Bevy

bevy_egui This crate provides a Egui integration for the Bevy game engine. Features: Desktop and web (bevy_webgl2) platforms support Clipboard (web su

Crossterm plugin for the bevy game engine
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

A 4X style camera for bevy.

A 4X style camera for bevy. Demo Default Key Bindings: W / A / S / D / Arrow Keys / Mouse Left - Move along the horizontal plane Q / E / Mouse Right -

Game physics in one weekend with bevy

Game Physics in a Weekend (in Rust) This project is an implementation of the Game Physics in a Weekend book using the Rust programming language and th

Owner
Professional Logical Operator
null
An opinionated 2D sparse grid made for use with Bevy. For storing and querying entities

bevy_sparse_grid_2d An opinionated 2D sparse grid made for use with Bevy. For storing and querying entities. Personally, I'm using it for simple stupi

Johan Klokkhammer Helsing 5 Feb 26, 2023
Attach Bevy's Handles/Entities statically to Types.

Easily attach bevy's Handles/Entities statically to types on startup and get them in any system, without using Resources. It's just a little less clut

Dekirisu 6 Sep 4, 2023
Using bevy and custom render pipelines in order to render many objects in a forest using chunks for performance.

bevy_efficient_forest_example Using bevy and custom render pipelines in order to render many objects in a forest using chunks for performance. Grass i

Henrik Djurestål 43 Jan 5, 2023
A simple helper for spawning objects in Bevy.

Spew A simple helper for spawning objects in Bevy. Usage First, create an enum that holds objects you might want to spawn: #[derive(Debug, Eq, Partial

Jan Hohenheim 6 Mar 20, 2023
Persist game settings like music volume or graphic settings in a nice toml file in the right location.

Bevy Settings The goal of this project is to store settings in a resource throughout game launches. Currently this crate supports Linux, Mac and Windo

Tobias Kriebisch 9 Feb 25, 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
bevy-hikari is an implementation of voxel cone tracing global illumination with anisotropic mip-mapping in Bevy

Bevy Voxel Cone Tracing bevy-hikari is an implementation of voxel cone tracing global illumination with anisotropic mip-mapping in Bevy. Bevy Version

研究社交 208 Dec 27, 2022
A simple extension for `bevy-editor-pls` to support tilemap editing right inside the bevy app.

What is this This is a simple tilemap editor plugin, that hooks right into bevy_editor_pls to work with bevy_ecs_tilemap. It works completely within i

null 3 May 8, 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 using Bevy and Bevy-Meshem

minecraft_bevy Minecraft_bevy was built to showcase bevy_meshem. After a week of developing it has: Chunk loading / unloading each chunk's mesh is bei

Adam 7 Oct 4, 2023