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