The Dense Component Entity System
by Florian Blasius, with contributions from the Rust Community
annotated and documented by Ralf Zerres and all contributors
This version of the text assumes you’re using Rust v1.60.0 or later.
Cargo.toml should define edition="2018"
. That enables and uses
Rust 2018 Edition idioms in all derived projects.
The 2020 Edition of this guide is the initial release. It will be released with the DCES version 0.4.0.
- Appendix A Keywords, explains the new raw identifiers.
- Appendix D Translations, is work in progress. We will release instances of this book in the target language once they are translated.
For online reading, a HTML rendered version is available at DCES
guide. Alternatively you might want to have it handy
for offline usage. Either you download a rendered pdf
or
ebook
version or go ahead and download the source. Then kick on
mdbook (the definition of the target location is optional).
If development has stabalized, this guide will be offered in multiple languages. The source directory is already structured to serve localized sub-directories. Thus to render its contents you need an enhanced version of mdbook. Ruin0x11 is maintaining a git branch localization, a PR is commited upstream.
Go ahead and install that mdBook version like this:
TMPDIR=<your_temporary_directory>
mkdir -p $TMPDIR; cd $TMPDIR
git clone https://github.com/Ruin0x11/mdBook.git
cd mdBook
git checkout localization
cargo update
cargo install --path .
We do make use of process visualization, that will need mermaid. To download and compile it from source, please use the following commands:
cargo install mdbook-mermaid
mermaid install
Now, that all needed binaries are installed on your system you can render the guide like this:
cd <the_DCES_guide__directory>
mdbook build --language en --dest-dir dces-guide/en --open
Introduction
Welcome to Dense Component Entity System, a guide to DCES
. In
the model of an archetype, or dense ECS the entities are stored in
tables. Components are the columns and entities are the
rows. Archetype implementations are fast to query and iterate.
This document provides a quick overview of the different features and
concepts in DCES
with short examples. This is a good resource if
you’re just getting started or just want to get a better idea of what
kind of features are available in DCES!
Warning: This guide is incomplete. Documenting everything and rewriting outdated parts take a while. See the issue tracker to check what’s missing or outdated. If there are any mistakes or ideas that haven’t been reported, feel free to open a new issue there.
Features
- Register entities with components
- Share components between entities
- Register systems and read / write components of entities
- Order systems execution by priority
- Register container for entity organization (Vec, FxHashMap, Custom Container, …)
- Register init and cleanup system
Who DCES is for
DCES
does suite for programmers that like to take advantage of the
Rust programming language to develop games or enhance UI’s frameworks. Since
everything is build native in Rust, there is no need to transform
data structures and types. As an example OrbTk
will completely rely on this
entity component system (ECS) variant.
There are a number of reasons why an ECS is gaining popularity especially amongst game developers:
ECS can typically support larger numbers of game objects
ECS code tends to be more reusable
ECS code is easier to extend with new features
ECS allows for a more dynamic coding style
Why not just …
You might ask, why not just use another production grade, maintained and feature complete ECS? And you are right. There is freedom. At least there are two crates, that are powerful and totally suitable alternative.
DCES
primary goal has been to provide a fast, dependency
free ECS with full integration into the Orbital Toolkit
(OrbTK). We have thought about incorporating parallel
execution into DCES
. This is deferred for now, since there is always
overhead in parallelization. You should carefully profile to see if
there are benefits in the switch. If you have only few things to
iterate over then sequential join is faster.
using Specs
Components and Systems in Specs may be computed in parallel. It uses as Dispatcher to achieve this goal. Details are documented inside the Tutorial.
using legion
The ECS demonstrated an archetypal memory layout and trait-less components.
using Shipyard
This is a sparse set based ECS. It stores each component in its own sparse set, where each entity id is the key to the component. Sparse set implementations allow for fast add/remove operations.
Source Code
The source files from which this guide is generated can be found on its homepage at DCES guide (en).
Getting Started
Let’s start your DCES journey! There’s a lot to learn, but every journey starts somewhere. In this chapter, we’ll discuss:
- Installing DCES on Linux, Bsd, macOS or Windows.
- Using
cargo
, Rust’s package manager and build system.
Installation
The first step is to install Rust. This is described in depth following Rust book Chapter 1
When creating an DCES application, we define the needed dependencies to the DCES crate in the Cargo.toml file of our project. The complile process will resolve the references and download the source as needed.
Command Line Notation
In this chapter and throughout the book, we’ll show some commands used in the terminal. Lines that you should enter in a terminal all start with
$
. You don’t need to type in the$
character; it indicates the start of each command. Lines that don’t start with$
typically show the output of the previous command. Additionally, PowerShell-specific examples will use>
rather than$
.
Troubleshooting
WIP: What are the most common culprits? Can we provide some general, basic solutions?
Local documentation
DCES offers the option to install its documentation locally, so you can read it offline.
Any time a type, a function, a method or a crate is reference by the toolkit and you’re not sure what it does or how to use it, have a look at its application programming interface API documentation to find out!
Install Rust on Linux or macOS
If you are using Linux or macOS open up an terminal and copy and paste the text below and hit the enter key on your keyboard:
curl https://sh.rustup.rs -sSf | sh
Install Rust on Windows
Download and run the Rust windows installer from https://www.rust-lang.org/tools/install.
Install Redoxer (Redox OS)
If you want build and run your Rust application on a KVM capable OS for Redox you can use redoxer.
To install Redoxer you have to first install the rust toolchain. After that open up an terminal and copy and paste the text below and hit the enter key on your keyboard:
cargo install redoxer
To compile and run your application on Redox OS you should check the Redox OS Book.
Editor and IDE integration
A wide range of editors and IDE’s are providing support for Rust code like
- like syntax-highlighting
- auto-completion
- linting
- lsp support
VS Code
There is a big community that rely on the visualstudio implementation
to handle their code base. Following are the steps needed to expand
your installation to support VS Code for Rust
development:
- Download VS Code from.
- Install Rust Language Server plugin (the Rust Language Server).
Alternative Editors and IDEs
If you prefer other solution, you will find in depth help inside the context of this incomplete links:
The Ingredients
DCES
provides a dense ECS rust centric
architecture. The interaction with DCES
is managed via the Entity Component Manager
(ECM), a wrapper API.
In contrast to the Object Oriented Programming
(OOP) paradigma, the
DCES separates data from behavior. Behaviors are handled via
systems. Systems provide the logic and implement the behavior on how
to act on entities with given properties. Data are bound to
components that are assigned to entities. Thus entities are unique
identifiers, that may have multiple, dynamically changable
components. The components itself are usually preceived as properties
in the consuming rust codebase.
The Architecture view
To break up the architecture of an ECS
it’s quite a help to first
define the building blocks. Here we go:
-
Entity: Is an uniquely identifyed object. The Entity can contain zero or more components.
-
Component: You are able to save datatypes inside a component. We will call the saved value of a component it’s property. The property may be looked up via its component key.
-
Entity_Component_Manager: The ECM keeps track of an entity store (bound entities and an associated component store).
-
Resource: A resource is a data slot which lives in a World. The data are shared between systems. Resources can only be accessed according to Rust’s typical borrowing model (one writer xor multiple readers). You may structure the components using resources.
-
Store: For any given storage provider the DCES defines an instance. It is quite common to utilize different, specialized stores. The store handles multiple entities, componets or resources.
-
Systems: The behaviors are processed with functions. This behavior will be processed for all matching entities of a component query.
-
World: A world represents the root of the DECS tree. Since it is totally leagal to have multiple world instances, each one represents a distinguished entity storage provider. This instances are handled via the methods of the entity_component_manager (ECM).
The following ClassDiagramms
visualizes the involved DCES
elements. To improve visibility, we will break up the complete tree into
detailed sub-trees.
classDiagram World --o EntityComponentManager World --o Resource World --o SystemStore EntityComponentManager --o EntityStore EntityComponentManager --o ComponentStore EntityComponentManager : entity_store[EntityStore] EntityComponentManager : component_store[ComponentStore] EntityComponentManager : component_store() EntityComponentManager : component_store_mut() EntityComponentManager : create_entity() EntityComponentManager : entity_counter[u32] EntityComponentManager : entity_store() EntityComponentManager : entity_store_mut() EntityComponentManager : new() EntityComponentManager : register_entity() EntityComponentManager : remove_entity() EntityComponentManager : stores() EntityComponentManager : stores_mut() Resource: FxHashMap[TypeId, Box->dyn Any] Resource : contains() Resource : get() Resource : get_mut() Resource : insert() Resource : is_empty() Resource : len() Resource : new() Resource : try_get() Resource : try_get_mut() World : entity_component_manager[EntityComponetManager] World : resources[FxHashmap] World : system_counter[u32] World : system_store[SystemStore] World : first_run bool World : create_entity() World : create_system() World : drop() World : entity_component_manager() World : from_entity_store() World : insert_resource() World : print_entity() World : register_init_system() World : resource_mut() World : remove_entity() World : run()
Next we have a look at the pieces inside the Entity hierarchy.
classDiagram Trait_EntityStore --o VecEntityStore Trait_EntityStore --o EntityBuilder VecEntityStore --o Entity EntityBuilder --o Entity EntityBuilder --o Component EntityBuilder : EntityStore[Entity, ComponentStore, EntityStore] EntityBuilder : build() EntityBuilder : components() VecEntityStore : Vec[Entity] VecEntityStore : register_entity() VecEntityStore : remove_entity() Trait_EntityStore : Entity Trait_EntityStore : register_entity() Trait_EntityStore : remove_entity() Entity : Entity[u32] Component: E[Any]
Next we present an isolated visualizaton of the Componets hierarchy.
classDiagram Trait_Component --o ComponentStore Trait_Component --o ComponentBuilder Trait_Component --o ComponentBox ComponentBox --o SharedComponentBox ComponentBox --o Component SharedComponentBox --o Component ComponentStore --o Component ComponentBuilder --o Component Component : E[Any] ComponentBuilder : ComponentBuilder[components, shared] ComponentBuilder : build() ComponentBuilder : new() ComponentBuilder : with() ComponentBuilder : with_shared() ComponentBox : ComponentBox[Box->dyn Any, TypeId] ComponentBox : consume() ComponentBox : new() ComponentStore : ComponentStore[Components, SharedComponents] ComponentStore : append() ComponentStore : entities_of_component() ComponentStore : get() ComponentStore : get_mut() ComponentStore : is() ComponentStore : is_empty() ComponentStore : is_origin() ComponentStore : len() ComponentStore : print_entity() ComponentStore : register() ComponentStore : register_box() ComponentStore : register_shared() ComponentStore : register_shared_box() ComponentStore : register_shared_box_by_source_key() ComponentStore : register_shared_by_source_key() ComponentStore : remove_entity() ComponentStore : source() ComponentStore : source_from_shared() ComponentStore : target_key() SharedComponentBox : SharedComponentBox[Entity, TypeId] SharedComponentBox : consume() SharedComponentBox : new() Trait_Component : E[Any]
Followed by the presentation of an isolated visualizaton of the System hierarchy.
classDiagram Trait_System --o SystemStore SystemStore --o SystemStoreBuilder SystemStore --o EntitySystem SystemStoreBuilder --o EntitySystem SystemStoreBuilder <-- InitSystem SystemStoreBuilder <-- CleanupSystem Trait_System : EntityStore[Any] Trait_System : run() EntitySystem: EntitySystem[Box->dyn System, priority] EntitySystem: new() SystemStore : EntityStore[entity_system->HashMap, init_system>Option, cleanup_system->Option, priorities->BTreeMap] SystemStore : borrow_cleanup_system() SystemStore : borrow_init_system() SystemStore : new() SystemStore : register_cleanup_system() SystemStore : register_init_system() SystemStore : register_priority() SystemStore : register_system() SystemStore : remove_system() SystemStoreBuilder: SystemStoreBuilder[entity_system_id, system_store, priority] SystemStoreBuilder: build() SystemStoreBuilder: with_priority()
DCES Example Applications
This section provides DCES
example apps. We hope to cover
interesting aspects.
Take them as a tutorial, all listings are created as a reference. They have in mind to serve as an introduction to a specific topic. As educational content, this apps are marked with in-lined comments and anchors. If we did well, you can concentrate on the parts we like to emphasize.
Inside the library, you will find the collection of example code in
the sub-directory examples
.
The annotated sources are placed in the subdirectory
listings
. A Cargo.toml will group all apps members as a workspace.
Change inside the listings root and call:
cargo build
That will build them all in one run using debug mode. To run a specific app, e.g. call:
cargo run --bin dces_resource
DCES Examples - Basic
This subsection documents the example application dces_basic.
This example instantiates a single world. It creates three entities each with an assigned component that provides the property “name”, “depth” and “size”.
A size system will query the entity store and manipulate the width and height struct values of components that provide and match a key “size”. As a rudimentary use case, we do simply increment by one.
A print system will queries into the entity store “e_store”, collects given entities and prints out the “value” of any component that has a matching component with the property key “name”. Without any fancy magic, entities name, its width and its height are printed to stdout.
The project root
Change to your project root directory. If you didn’t already create the app in the first place, go ahead and type the following in your console:
$ cd ~/guide/examples
Create the source code
Next we will use cargo to create the app. All boilerplate tasks are handled using cargo’s inherited template handling.
$ cargo new dces_basic
$ cd dces_basic
The first command, cargo new
, takes the name of the project
(“dces_basic
”) as the first argument. The second command changes to
the new project’s directory.
Look at the generated Cargo.toml file:
[package]
name = "dces_example"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
With cargo new
, a default project structure is created. Maybe the
author information is already exchanged if Cargo could obtain a
definition from your environment. Cargo also generated source code
for a “Hello, world!” program. Let’s Check out the corresponding
src/main.rs file:
fn main() { println!("Hello DECS!"); }
No need to compile that stage with cargo run
, since we are going to
exchange the project metadata, as well as the dces source code right
away.
Update Cargo.toml
First reopen the Cargo.toml file and enter the Code in Listing 1-3 into Cargo.toml
[package]
name = "dces_basic"
version = "0.4.0"
authors = [
"Florian Blasius <flovanpt@posteo.de>",
"Ralf Zerres <ralf.zerres.de@gmail.com>",
]
description = "DCES - Basic example"
documentation = "https://doc.redox-os.org/dces-guide"
repository = "https://gitlab.redox-os.org/redox-os/dces-guide/"
readme = "README.md"
license = "MIT"
keywords = [
"dces",
"ecs",
]
edition = "2021"
[profile.dev]
opt-level = 1
[dependencies]
dces = { git = "https://gitlab.redox-os.org/redox-os/dces-rust.git", branch = "develop" }
[[bin]]
name = "dces_basic"
path = "src/main.rs"
You may wonder, why the name property inside the Cargo.toml is
formatted like dces_basic
.
name = "dces_basic"
It is a good habit to follow rusts naming convention, that encourages
you to use snake_case naming. While expanding the DCES
example sources, we will keep the grouping prefix dces
. That way we
end up to call our first target binary dces_basic
.
Update main.rs
All of the DCES specific code that is needed to build our first example is shown in Listing 1-4, that you encode into src/main.rs.
Save your changes to the file and go back to the terminal window. Enter the following commands to compile and run the file in debug mode:
$ cargo run --example basic
The following output should be printed inside your console window:
Button width: 6; height: 6
CheckBox width: 4; height: 4
RadioButton width: 5; height: 7
Recap and annotation
The anatomy of a DCES application
Let’s review in detail what just happened in your DCES-basic application. Here are the relevant pieces of the puzzle:
use dces::prelude::*;
#[derive(Default)]
struct Size {
width: u32,
height: u32,
}
#[derive(Default)]
struct Name(String);
#[derive(Default)]
struct Depth(u32);
pub struct SizeSystem;
impl System<EntityStore> for SizeSystem {
fn run(&self, ecm: &mut EntityComponentManager<EntityStore>, _: &mut Resources) {
let (e_store, c_store) = ecm.stores_mut();
for entity in &e_store.inner {
if let Ok(comp) = c_store.get_mut::<Size>("size", *entity) {
comp.width += 1;
comp.height += 1;
}
}
}
}
pub struct PrintSystem;
impl System<EntityStore> for PrintSystem {
fn run(&self, ecm: &mut EntityComponentManager<EntityStore>, _: &mut Resources) {
let (e_store, c_store) = ecm.stores_mut();
for entity in &e_store.inner {
if let Ok(name) = c_store.get::<Name>("name", *entity) {
if let Ok(size) = c_store.get::<Size>("size", *entity) {
println!("{} width: {}; height: {}", name.0, size.width, size.height);
}
}
}
}
}
fn main() {
let mut world = World::from_entity_store(EntityStore::default());
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("Button")))
.with("depth", Depth(4))
.with(
"size",
Size {
width: 5,
height: 5,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("CheckBox")))
.with("depth", Depth(1))
.with(
"size",
Size {
width: 3,
height: 3,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("RadioButton")))
.with("detph", Depth(2))
.with(
"size",
Size {
width: 4,
height: 6,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("depth", Depth(3))
.with(
"size",
Size {
width: 10,
height: 4,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("depth", Depth(0))
.with(
"size",
Size {
width: 5,
height: 8,
},
)
.build(),
)
.build();
world.create_system(PrintSystem).with_priority(1).build();
world.create_system(SizeSystem).with_priority(0).build();
world.run();
}
The first line is introducing a use declaration. A use declaration is used to shorten the path required to refer to rust module items. The prelude is a convenient way to a list of things, that rust will automatically import to you program. Here, we bind the path dces::prelude. All default items defined in this path (referenced with ::) are now accessible in your source using their shorthand name. No need to type in their common prefix (dces::prelude::)
use dces::prelude::*;
#[derive(Default)]
struct Size {
width: u32,
height: u32,
}
#[derive(Default)]
struct Name(String);
#[derive(Default)]
struct Depth(u32);
pub struct SizeSystem;
impl System<EntityStore> for SizeSystem {
fn run(&self, ecm: &mut EntityComponentManager<EntityStore>, _: &mut Resources) {
let (e_store, c_store) = ecm.stores_mut();
for entity in &e_store.inner {
if let Ok(comp) = c_store.get_mut::<Size>("size", *entity) {
comp.width += 1;
comp.height += 1;
}
}
}
}
pub struct PrintSystem;
impl System<EntityStore> for PrintSystem {
fn run(&self, ecm: &mut EntityComponentManager<EntityStore>, _: &mut Resources) {
let (e_store, c_store) = ecm.stores_mut();
for entity in &e_store.inner {
if let Ok(name) = c_store.get::<Name>("name", *entity) {
if let Ok(size) = c_store.get::<Size>("size", *entity) {
println!("{} width: {}; height: {}", name.0, size.width, size.height);
}
}
}
}
}
fn main() {
let mut world = World::from_entity_store(EntityStore::default());
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("Button")))
.with("depth", Depth(4))
.with(
"size",
Size {
width: 5,
height: 5,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("CheckBox")))
.with("depth", Depth(1))
.with(
"size",
Size {
width: 3,
height: 3,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("RadioButton")))
.with("detph", Depth(2))
.with(
"size",
Size {
width: 4,
height: 6,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("depth", Depth(3))
.with(
"size",
Size {
width: 10,
height: 4,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("depth", Depth(0))
.with(
"size",
Size {
width: 5,
height: 8,
},
)
.build(),
)
.build();
world.create_system(PrintSystem).with_priority(1).build();
world.create_system(SizeSystem).with_priority(0).build();
world.run();
}
The main
function is special: it defines the first execution point inside
a compiled Rust binary (leaving rust’s minimal
runtime out of scope). In our example the function name
main
has no parameters and returns nothing. If there were
parameters, they would go inside the parentheses, ()
.
Also, note that the function body is wrapped in curly brackets, {}
. Rust
requires these around all function bodies. It’s good style to place the opening
curly bracket on the same line as the function declaration, adding one space in
between.
An automatic formatter tool called rustfmt
will help you to stick to a
standard style across Rust projects. DCES is following this guidance.
rustfmt
will format your code in a particular style. Depending on the version
of your rust toolchain, it is probably already installed on your computer!
Check the online documentation for more details.
Lets focus on some other important details:
- First, Rust style is to indent with four spaces, not a tab.
- Second, we create five entities inside a world.
- Third, we create two systems inside a world.
- Forth, we start the run loop for our world.
As a first step, we do instantiate a mutable world structure. This structure will make use of an EnityStore.
use dces::prelude::*;
#[derive(Default)]
struct Size {
width: u32,
height: u32,
}
#[derive(Default)]
struct Name(String);
#[derive(Default)]
struct Depth(u32);
pub struct SizeSystem;
impl System<EntityStore> for SizeSystem {
fn run(&self, ecm: &mut EntityComponentManager<EntityStore>, _: &mut Resources) {
let (e_store, c_store) = ecm.stores_mut();
for entity in &e_store.inner {
if let Ok(comp) = c_store.get_mut::<Size>("size", *entity) {
comp.width += 1;
comp.height += 1;
}
}
}
}
pub struct PrintSystem;
impl System<EntityStore> for PrintSystem {
fn run(&self, ecm: &mut EntityComponentManager<EntityStore>, _: &mut Resources) {
let (e_store, c_store) = ecm.stores_mut();
for entity in &e_store.inner {
if let Ok(name) = c_store.get::<Name>("name", *entity) {
if let Ok(size) = c_store.get::<Size>("size", *entity) {
println!("{} width: {}; height: {}", name.0, size.width, size.height);
}
}
}
}
}
fn main() {
let mut world = World::from_entity_store(EntityStore::default());
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("Button")))
.with("depth", Depth(4))
.with(
"size",
Size {
width: 5,
height: 5,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("CheckBox")))
.with("depth", Depth(1))
.with(
"size",
Size {
width: 3,
height: 3,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("RadioButton")))
.with("detph", Depth(2))
.with(
"size",
Size {
width: 4,
height: 6,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("depth", Depth(3))
.with(
"size",
Size {
width: 10,
height: 4,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("depth", Depth(0))
.with(
"size",
Size {
width: 5,
height: 8,
},
)
.build(),
)
.build();
world.create_system(PrintSystem).with_priority(1).build();
world.create_system(SizeSystem).with_priority(0).build();
world.run();
}
Next we create five new entities inside the our world. For each entity we assign components. The components are constructed consuming the method ComponentBuilder to define their values (uppercase string). The corresponding keys are name, depth, and size (in parentheses). A terminating block is calling the build method, that finally instantiates the code.
Following code block extracts the definition of the first entity:
use dces::prelude::*;
#[derive(Default)]
struct Size {
width: u32,
height: u32,
}
#[derive(Default)]
struct Name(String);
#[derive(Default)]
struct Depth(u32);
pub struct SizeSystem;
impl System<EntityStore> for SizeSystem {
fn run(&self, ecm: &mut EntityComponentManager<EntityStore>, _: &mut Resources) {
let (e_store, c_store) = ecm.stores_mut();
for entity in &e_store.inner {
if let Ok(comp) = c_store.get_mut::<Size>("size", *entity) {
comp.width += 1;
comp.height += 1;
}
}
}
}
pub struct PrintSystem;
impl System<EntityStore> for PrintSystem {
fn run(&self, ecm: &mut EntityComponentManager<EntityStore>, _: &mut Resources) {
let (e_store, c_store) = ecm.stores_mut();
for entity in &e_store.inner {
if let Ok(name) = c_store.get::<Name>("name", *entity) {
if let Ok(size) = c_store.get::<Size>("size", *entity) {
println!("{} width: {}; height: {}", name.0, size.width, size.height);
}
}
}
}
}
fn main() {
let mut world = World::from_entity_store(EntityStore::default());
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("Button")))
.with("depth", Depth(4))
.with(
"size",
Size {
width: 5,
height: 5,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("CheckBox")))
.with("depth", Depth(1))
.with(
"size",
Size {
width: 3,
height: 3,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("RadioButton")))
.with("detph", Depth(2))
.with(
"size",
Size {
width: 4,
height: 6,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("depth", Depth(3))
.with(
"size",
Size {
width: 10,
height: 4,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("depth", Depth(0))
.with(
"size",
Size {
width: 5,
height: 8,
},
)
.build(),
)
.build();
world.create_system(PrintSystem).with_priority(1).build();
world.create_system(SizeSystem).with_priority(0).build();
world.run();
}
Please note, that “size” itself is a structure that handles the values width and height.
use dces::prelude::*;
#[derive(Default)]
struct Size {
width: u32,
height: u32,
}
#[derive(Default)]
struct Name(String);
#[derive(Default)]
struct Depth(u32);
pub struct SizeSystem;
impl System<EntityStore> for SizeSystem {
fn run(&self, ecm: &mut EntityComponentManager<EntityStore>, _: &mut Resources) {
let (e_store, c_store) = ecm.stores_mut();
for entity in &e_store.inner {
if let Ok(comp) = c_store.get_mut::<Size>("size", *entity) {
comp.width += 1;
comp.height += 1;
}
}
}
}
pub struct PrintSystem;
impl System<EntityStore> for PrintSystem {
fn run(&self, ecm: &mut EntityComponentManager<EntityStore>, _: &mut Resources) {
let (e_store, c_store) = ecm.stores_mut();
for entity in &e_store.inner {
if let Ok(name) = c_store.get::<Name>("name", *entity) {
if let Ok(size) = c_store.get::<Size>("size", *entity) {
println!("{} width: {}; height: {}", name.0, size.width, size.height);
}
}
}
}
}
fn main() {
let mut world = World::from_entity_store(EntityStore::default());
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("Button")))
.with("depth", Depth(4))
.with(
"size",
Size {
width: 5,
height: 5,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("CheckBox")))
.with("depth", Depth(1))
.with(
"size",
Size {
width: 3,
height: 3,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("RadioButton")))
.with("detph", Depth(2))
.with(
"size",
Size {
width: 4,
height: 6,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("depth", Depth(3))
.with(
"size",
Size {
width: 10,
height: 4,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("depth", Depth(0))
.with(
"size",
Size {
width: 5,
height: 8,
},
)
.build(),
)
.build();
world.create_system(PrintSystem).with_priority(1).build();
world.create_system(SizeSystem).with_priority(0).build();
world.run();
}
We should mention, that our example-code defines all entities with the same number and names of component elements. This is not a requirement nor a design restriction. Which components are attached to which entities may differ significantly and is completely arbitrary.
Our binary will consume a Size- and a Print-System. Both of them do handle entity manipulation via the EntityComponentManager (ECM). The ECM is capable to borrow or mutate Enities and Components via its EntityStore. Thus we can assign distinct store structures for each of them (here: e_store, c_store).
use dces::prelude::*;
#[derive(Default)]
struct Size {
width: u32,
height: u32,
}
#[derive(Default)]
struct Name(String);
#[derive(Default)]
struct Depth(u32);
pub struct SizeSystem;
impl System<EntityStore> for SizeSystem {
fn run(&self, ecm: &mut EntityComponentManager<EntityStore>, _: &mut Resources) {
let (e_store, c_store) = ecm.stores_mut();
for entity in &e_store.inner {
if let Ok(comp) = c_store.get_mut::<Size>("size", *entity) {
comp.width += 1;
comp.height += 1;
}
}
}
}
pub struct PrintSystem;
impl System<EntityStore> for PrintSystem {
fn run(&self, ecm: &mut EntityComponentManager<EntityStore>, _: &mut Resources) {
let (e_store, c_store) = ecm.stores_mut();
for entity in &e_store.inner {
if let Ok(name) = c_store.get::<Name>("name", *entity) {
if let Ok(size) = c_store.get::<Size>("size", *entity) {
println!("{} width: {}; height: {}", name.0, size.width, size.height);
}
}
}
}
}
fn main() {
let mut world = World::from_entity_store(EntityStore::default());
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("Button")))
.with("depth", Depth(4))
.with(
"size",
Size {
width: 5,
height: 5,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("CheckBox")))
.with("depth", Depth(1))
.with(
"size",
Size {
width: 3,
height: 3,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("RadioButton")))
.with("detph", Depth(2))
.with(
"size",
Size {
width: 4,
height: 6,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("depth", Depth(3))
.with(
"size",
Size {
width: 10,
height: 4,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("depth", Depth(0))
.with(
"size",
Size {
width: 5,
height: 8,
},
)
.build(),
)
.build();
world.create_system(PrintSystem).with_priority(1).build();
world.create_system(SizeSystem).with_priority(0).build();
world.run();
}
Next we simply loop over the store in question and use the get() method to consume the values of the given entities and components that match our query.
use dces::prelude::*;
#[derive(Default)]
struct Size {
width: u32,
height: u32,
}
#[derive(Default)]
struct Name(String);
#[derive(Default)]
struct Depth(u32);
pub struct SizeSystem;
impl System<EntityStore> for SizeSystem {
fn run(&self, ecm: &mut EntityComponentManager<EntityStore>, _: &mut Resources) {
let (e_store, c_store) = ecm.stores_mut();
for entity in &e_store.inner {
if let Ok(comp) = c_store.get_mut::<Size>("size", *entity) {
comp.width += 1;
comp.height += 1;
}
}
}
}
pub struct PrintSystem;
impl System<EntityStore> for PrintSystem {
fn run(&self, ecm: &mut EntityComponentManager<EntityStore>, _: &mut Resources) {
let (e_store, c_store) = ecm.stores_mut();
for entity in &e_store.inner {
if let Ok(name) = c_store.get::<Name>("name", *entity) {
if let Ok(size) = c_store.get::<Size>("size", *entity) {
println!("{} width: {}; height: {}", name.0, size.width, size.height);
}
}
}
}
}
fn main() {
let mut world = World::from_entity_store(EntityStore::default());
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("Button")))
.with("depth", Depth(4))
.with(
"size",
Size {
width: 5,
height: 5,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("CheckBox")))
.with("depth", Depth(1))
.with(
"size",
Size {
width: 3,
height: 3,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("RadioButton")))
.with("detph", Depth(2))
.with(
"size",
Size {
width: 4,
height: 6,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("depth", Depth(3))
.with(
"size",
Size {
width: 10,
height: 4,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("depth", Depth(0))
.with(
"size",
Size {
width: 5,
height: 8,
},
)
.build(),
)
.build();
world.create_system(PrintSystem).with_priority(1).build();
world.create_system(SizeSystem).with_priority(0).build();
world.run();
}
Complete example source
Find attached the complete source code for our dces_basic example.
use dces::prelude::*;
#[derive(Default)]
struct Size {
width: u32,
height: u32,
}
#[derive(Default)]
struct Name(String);
#[derive(Default)]
struct Depth(u32);
pub struct SizeSystem;
impl System<EntityStore> for SizeSystem {
fn run(&self, ecm: &mut EntityComponentManager<EntityStore>, _: &mut Resources) {
let (e_store, c_store) = ecm.stores_mut();
for entity in &e_store.inner {
if let Ok(comp) = c_store.get_mut::<Size>("size", *entity) {
comp.width += 1;
comp.height += 1;
}
}
}
}
pub struct PrintSystem;
impl System<EntityStore> for PrintSystem {
fn run(&self, ecm: &mut EntityComponentManager<EntityStore>, _: &mut Resources) {
let (e_store, c_store) = ecm.stores_mut();
for entity in &e_store.inner {
if let Ok(name) = c_store.get::<Name>("name", *entity) {
if let Ok(size) = c_store.get::<Size>("size", *entity) {
println!("{} width: {}; height: {}", name.0, size.width, size.height);
}
}
}
}
}
fn main() {
let mut world = World::from_entity_store(EntityStore::default());
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("Button")))
.with("depth", Depth(4))
.with(
"size",
Size {
width: 5,
height: 5,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("CheckBox")))
.with("depth", Depth(1))
.with(
"size",
Size {
width: 3,
height: 3,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("RadioButton")))
.with("detph", Depth(2))
.with(
"size",
Size {
width: 4,
height: 6,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("depth", Depth(3))
.with(
"size",
Size {
width: 10,
height: 4,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("depth", Depth(0))
.with(
"size",
Size {
width: 5,
height: 8,
},
)
.build(),
)
.build();
world.create_system(PrintSystem).with_priority(1).build();
world.create_system(SizeSystem).with_priority(0).build();
world.run();
}
Compiling and Running Are Separate Steps
Before you are able to run a DCES application, you must compile its source code. A typical DCES project will generate the executable binary code using cargo and place the result in the target subfolder of the project.
Profiles may be used to configure compiler options such as optimization levels
and debug settings. By default the dev
or test
profiles are used. If the
--release
flag is given, then the release or bench profiles are used.
$ cargo build --release --bin dces_basic.rs
$ ../target/release/dces_basic
On Windows, you need to use backslash
as a path delimiter:
> cargo build --release --bin dces_basic.rs
> ..\target\release\dces_basic.exe
DCES Examples - Minimal
This subsection documents the example application dces_minimal.
In a minimalistic use-case, this example creates a single world. It creates one entity and assignes one component that provides the property “name”.
A print system will queries into the entity store “e_store”, collects the given entity and prints out the “value” of any component that has a matching component with the property key “name”. Without any fancy magic, they are printed to stdout.
Update Cargo.toml
First have a look at the corresponding Cargo.toml file as shown in Listing 1-1.
# ANCHOR: All
[package]
# ANCHOR: Name
name = "dces_minimal"
# ANCHOR_END: Name
version = "0.4.0"
authors = [
"Florian Blasius <flovanpt@posteo.de>",
"Ralf Zerres <ralf.zerres.de@gmail.com>",
]
description = "DCES - Minimal example"
documentation = "https://doc.redox-os.org/dces-guide"
repository = "https://gitlab.redox-os.org/redox-os/dces-guide"
readme = "README.md"
license = "MIT"
keywords = [
"dces",
"ecs",
]
edition = "2021"
[profile.dev]
opt-level = 1
[dependencies]
dces = { git = "https://gitlab.redox-os.org/redox-os/dces-rust.git", branch = "develop" }
[[bin]]
# ANCHOR: Name
name = "dces_minimal"
# ANCHOR_END: Name
path = "src/main.rs"
# ANCHOR_END: All
Program source code
All of the DCES specific code that is needed to build the dces_minimal example is shown in [Listing 1-2][dces_minimal, that is encode in src/main.rs.
Enter the following commands inside the terminal window to compile and run in debug mode:
$ cargo run --example miminal
The following output should be printed inside your console window:
DCES
Recap and annotation
The anatomy of the dces_minimal
application
Let’s review the relevant parts of the dces_minimal application.
A more in depth view of a typical DCES
application is documented
inside the annotated dces_basic source.
Following code block extracts the implementation of the PrintSystem:
impl System<EntityStore> for PrintSystem {
fn run(&self, ecm: &mut EntityComponentManager<EntityStore>, _: &mut Resources) {
let (e_store, c_store) = ecm.stores();
for entity in &e_store.inner {
if let Ok(comp) = c_store.get::<Name>("name", *entity) {
println!("{}", comp.value);
}
// ANCHOR_END Print_ComponentValue
}
}
}
We loop over the given entity store “e_store” and get any component
with a key matching "name"
. If the value us non-null, it will be
printed to stdout.
for entity in &e_store.inner {
if let Ok(comp) = c_store.get::<Name>("name", *entity) {
println!("{}", comp.value);
}
// ANCHOR_END Print_ComponentValue
}
As a result, the string DCES!
will make it as the console output.
Complete example source
Find attached the complete source code for our dces_minimal example.
use dces::prelude::*;
#[derive(Default)]
struct Name {
value: String,
}
struct PrintSystem;
impl System<EntityStore> for PrintSystem {
fn run(&self, ecm: &mut EntityComponentManager<EntityStore>, _: &mut Resources) {
let (e_store, c_store) = ecm.stores();
for entity in &e_store.inner {
if let Ok(comp) = c_store.get::<Name>("name", *entity) {
println!("{}", comp.value);
}
// ANCHOR_END Print_ComponentValue
}
}
}
fn main() {
let mut world = World::from_entity_store(EntityStore::default());
world
.create_entity()
.components(
ComponentBuilder::new()
.with(
"name",
Name {
value: String::from("DCES"),
},
)
.build(),
)
.build();
world.create_system(PrintSystem).build();
world.run();
}
Compiling and Running Are Separate Steps
The cargo call to compile dces_minimal
will place the resulting
binary in the target subfolder of the project.
$ cargo build --release --bin dces_minimal.rs
$ ../target/release/dces_minimal
On Windows, you need to use backslash
as a path delimiter:
> cargo build --release --bin dces_minimal.rs
> ..\target\release\dces_minimal.exe
DCES Examples - Resource
This subsection documents the example application dces_resource.
Again, we create a single world instance. Next one entity is build and we assignes one component that provides the property “name”. A mutable resource consuming type “HelloDCES” is assigned as well. Inside the print system we take care to print out any property value that matches the component key “name”. In addition the “say_hello()” method of resource “HelloDCES” is executed, that simply returns the String “Hello DCES!”.
Update Cargo.toml
First have a look at the corresponding Cargo.toml file as shown in Listing 1-1.
# ANCHOR: All
[package]
# ANCHOR: Name
name = "dces_resource"
# ANCHOR_END: Name
version = "0.4.0"
authors = [
"Florian Blasius <flovanpt@posteo.de>",
"Ralf Zerres <ralf.zerres.de@gmail.com>",
]
description = "DCES - Resource example"
documentation = "https://doc.redox-os.org/dces-guide"
repository = "https://gitlab.redox-os.org/redox-os/dces-guide/"
readme = "README.md"
license = "MIT"
keywords = [
"orbital",
"widget",
"ui",
]
edition = "2021"
[profile.dev]
opt-level = 1
[dependencies]
dces = { git = "https://gitlab.redox-os.org/redox-os/dces-rust.git", branch = "develop" }
[[bin]]
# ANCHOR: Name
name = "dces_resource"
# ANCHOR_END: Name
path = "src/main.rs"
# ANCHOR_END: All
Program source code
All of the DCES specific code that is needed to build the dces_resources example is shown in Listing 1-2, that is encode in src/main.rs.
Enter the following commands inside the terminal window to compile and run in debug mode:
$ cargo run --example resource
The following output should be printed inside your console window:
DCES
Hello DCES!
Recap and annotation
The anatomy of the dces_resource
application
Let’s review the relevant parts of the dces_resource application.
A more in depth view of a typical DCES
application is documented
inside the annotated dces_basic source.
Following code block extracts the implementation of the PrintSystem:
impl System<EntityStore> for PrintSystem {
fn run(&self, ecm: &mut EntityComponentManager<EntityStore>, res: &mut Resources) {
let (e_store, c_store) = ecm.stores();
for entity in &e_store.inner {
if let Ok(comp) = c_store.get::<Name>("name", *entity) {
println!("{}", comp.value);
}
}
println!("{}", res.get::<HelloDCES>().say_hello());
}
}
The value of component key "name"
will be processed as already
documented. The new part is inside the handling of the
Resource-Structure via the PrintSystem.
struct HelloDCES;
The code implements a the HelloDCES type which provides the say_hello() method.
impl HelloDCES {
pub fn say_hello(&self) -> &str {
return "Hello DCES!";
}
}
With the resource get()
method, we chain the call to its
say_hello()
method. It returns a String that is
passed over to the println!() macro.
println!("{}", res.get::<HelloDCES>().say_hello());
As a result, the string Hello DCES!
will make it as the console output.
Complete example source
Find attached the complete source code for our dces_resource example.
use dces::prelude::*;
#[derive(Default)]
struct Name {
value: String,
}
struct HelloDCES;
impl HelloDCES {
pub fn say_hello(&self) -> &str {
return "Hello DCES!";
}
}
struct PrintSystem;
impl System<EntityStore> for PrintSystem {
fn run(&self, ecm: &mut EntityComponentManager<EntityStore>, res: &mut Resources) {
let (e_store, c_store) = ecm.stores();
for entity in &e_store.inner {
if let Ok(comp) = c_store.get::<Name>("name", *entity) {
println!("{}", comp.value);
}
}
println!("{}", res.get::<HelloDCES>().say_hello());
}
}
fn main() {
let mut world = World::from_entity_store(EntityStore::default());
world
.create_entity()
.components(
ComponentBuilder::new()
.with(
"name",
Name {
value: String::from("DCES"),
},
)
.build(),
)
.build();
world.resources_mut().insert(HelloDCES);
world.create_system(PrintSystem).build();
world.run();
}
Compiling and Running Are Separate Steps
The compiled dces_resource
with cargo will be placed the
resulting binary in the target subfolder of the project.
$ cargo build --release --bin dces_resource.rs
$ ../target/release/dces_resource
On Windows, you need to use backslash
as a path delimiter:
> cargo build --release --bin dces_resource.rs
> ..\target\release\dces_resource.exe
DCES Examples - Shared
This subsection documents the example application dces_shared.
In a minimalistic use-case, this example creates a single world. It creates two entities. Each entity gets assinged components that provide the properties “name”, “depth” and “size”. When using the ComponentBuilder for the second entity (component “name” == “CheckBox”) we make use of a method “with_shared()”, that will reference to an already given struct “size”.
A size system will query the entity store and manipulate the width and height struct values of components that provide and match a key “size”. As a rudimentary use case, we do simply increment them by one.
A print system will queries into the entity store “e_store”, collects given entities and prints out the “value” of any component that has a matching property key “name”. Without any fancy magic, entities name, its width and its height are printed to stdout. and assignes three component that provides the property “name”, “depth” and “size”.
Update Cargo.toml
First have a look at the corresponding Cargo.toml file as shown in Listing 1-1.
# ANCHOR: All
[package]
# ANCHOR: Name
name = "dces_shared"
# ANCHOR_END: Name
version = "0.4.0"
authors = [
"Florian Blasius <flovanpt@posteo.de>",
"Ralf Zerres <ralf.zerres.de@gmail.com>",
]
description = "DCES - Shared example"
documentation = "https://doc.redox-os.org/dces-guide"
repository = "https://gitlab.redox-os.org/redox-os/dces-guide/"
readme = "README.md"
license = "MIT"
keywords = [
"dces",
"ecs",
]
edition = "2021"
[profile.dev]
opt-level = 1
[dependencies]
dces = { git = "https://gitlab.redox-os.org/redox-os/dces-rust.git", branch = "develop" }
[[bin]]
# ANCHOR: Name
name = "dces_shared"
# ANCHOR_END: Name
path = "src/main.rs"
# ANCHOR_END: All
Program source code
All of the DCES specific code that is needed to build the dces_shared example is shown in Listing 1-2, that is encode in src/main.rs.
Enter the following commands inside the terminal window to compile and run in debug mode:
$ cargo run --example shared
The following output should be printed inside your console window:
entity: 0; name: Button; width: 6; height: 6
entity: 1; name: CheckBox; width: 6; height: 6
Recap and annotation
The anatomy of the dces_shared
application
Let’s review the relevant parts of the dces_shared application.
A more in depth view of a typical DCES
application is documented
inside the annotated dces_basic source.
Following code block extracts the implementation of the PrintSystem:
impl System<EntityStore> for PrintSystem {
fn run(&self, ecm: &mut EntityComponentManager<EntityStore>, _: &mut Resources) {
let (e_store, c_store) = ecm.stores();
for entity in &e_store.inner {
if let Ok(name) = c_store.get::<Name>("name", *entity) {
if let Ok(size) = c_store.get::<Size>("size", *entity) {
println!(
"entity: {}; name: {}; width: {}; height: {}",
entity.0, name.0, size.width, size.height
);
}
}
}
}
}
The values of the component keys "name"
, "width"
and "height"
will be processed as already documented.
The new part is inside the handling of the Size-Structure to a
component. Inside the main function, when we do attach the component
“size” with ComponentBuilder inside the second entity, we make use
of the with_shared
method. This method is able to borrow the already
assigned structure “size”. Therefore it will reference the given values.
.with_shared::<Size>("size", source)
Complete example source
Find attached the complete source code for our dces_shared example.
use dces::prelude::*;
#[derive(Default)]
struct Size {
width: u32,
height: u32,
}
#[derive(Default)]
struct Name(String);
#[derive(Default)]
struct Depth(u32);
pub struct SizeSystem {
source: Entity,
}
impl System<EntityStore> for SizeSystem {
fn run(&self, ecm: &mut EntityComponentManager<EntityStore>, _: &mut Resources) {
if let Ok(comp) = ecm
.component_store_mut()
.get_mut::<Size>("size", self.source)
{
comp.width += 1;
comp.height += 1;
}
}
}
struct PrintSystem;
impl System<EntityStore> for PrintSystem {
fn run(&self, ecm: &mut EntityComponentManager<EntityStore>, _: &mut Resources) {
let (e_store, c_store) = ecm.stores();
for entity in &e_store.inner {
if let Ok(name) = c_store.get::<Name>("name", *entity) {
if let Ok(size) = c_store.get::<Size>("size", *entity) {
println!(
"entity: {}; name: {}; width: {}; height: {}",
entity.0, name.0, size.width, size.height
);
}
}
}
}
}
fn main() {
let mut world = World::from_entity_store(EntityStore::default());
let source = world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("Button")))
.with("depth", Depth(4))
.with(
"size",
Size {
width: 5,
height: 5,
},
)
.build(),
)
.build();
world
.create_entity()
.components(
ComponentBuilder::new()
.with("name", Name(String::from("CheckBox")))
.with("depth", Depth(1))
.with_shared::<Size>("size", source)
.build(),
)
.build();
world.create_system(PrintSystem).with_priority(1).build();
world
.create_system(SizeSystem { source })
.with_priority(0)
.build();
world.run();
}
Compiling and Running Are Separate Steps
The compiled dces_shared
with cargo will be placed the resulting
binary in the target subfolder of the project.
$ cargo build --release --bin dces_shared.rs
$ ../target/release/dces_shared
On Windows, you need to use backslash
as a path delimiter:
> cargo build --release --bin dces_shared.rs
> ..\target\release\dces_shared.exe
DCES Appendix
This is WIP
DCES Appendix - Keywords
This is WIP
DCES Appendix - Resources
This is WIP
Appendix D: Guide translations
For resources in languages other than English. This is work in progress; see the Translations label to help or let us know about a new translation!