Skip to content

Commit

Permalink
deploy: 47a3b0f
Browse files Browse the repository at this point in the history
  • Loading branch information
ten3roberts committed Oct 28, 2023
1 parent 043f474 commit 5646bb5
Show file tree
Hide file tree
Showing 8 changed files with 243 additions and 77 deletions.
Binary file modified asteroids/asteroids.wasm
Binary file not shown.
2 changes: 1 addition & 1 deletion guide/diving_deeper/dynamic_components.html
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ <h2 id="relations"><a class="header" href="#relations">Relations</a></h2>
assert!(world.get(child, child_of(parent)).is_err());

<span class="boring">}</span></code></pre></pre>
<p>When despawning either the relation component or object entity, the &quot;parent&quot;,
<p>When despawning either the relation component or target entity, the &quot;parent&quot;,
the component is removed from all entities.</p>

</main>
Expand Down
153 changes: 118 additions & 35 deletions guide/fundamentals/relations.html
Original file line number Diff line number Diff line change
Expand Up @@ -172,20 +172,20 @@ <h1 class="menu-title">Flax Guide</h1>
<div id="content" class="content">
<main>
<h1 id="relations"><a class="header" href="#relations">Relations</a></h1>
<p>A relation is a component which <em>links</em> to another <code>Entity</code>, similar to a foreign key in a database.</p>
<p>The linked entity is referred to as the <code>object</code> of a relation, while the entity the component is attached to is called the <code>subject</code>.</p>
<p>A relation is a component which <em>links</em> to another <code>Entity</code>, similar to a foreign key in a database. This can be used to construct different kinds of graphs and trees inside the ECS.</p>
<p>The links between entities are managed by the ECS itself and will always be valid, see <a href="#lifetime">Lifetime</a>.</p>
<p>The linked entity is referred to as the <code>target</code> of a relation, while the entity the component is attached to is called the <code>subject</code>.</p>
<p>This allows forming hierarchies such as <em>parent-child</em> relations for transforms and UI, as well as arbitrary graphs.</p>
<p>A relation is used as a <em>parameterized</em> component, which requires an <code>Entity</code> to be fully instantiated.</p>
<p>See the <a href="https://docs.rs/flax/latest/flax/components/fn.child_of.html"><code>child_of</code></a> relation for an example of a parent-child relation which uses the parent entity as the relation's <em>target</em>.</p>
<p>Relations are most easily declared using the
<a href="https://docs.rs/flax/latest/flax/macro.component.html">component</a> macro.</p>
<a href="https://docs.rs/flax/latest/flax/macro.component.html">component</a> macro, but can be constructed dynamically as well. See <a href="../diving_deeper/dynamic_components.html">dynamic_components</a></p>
<p>For example, declaring a child relationship that connects to a parent can be done like so:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span> component! {
spring_joint(other): f32 =&gt; [Debuggable],
child_of(id): (),
}

let mut world = World::new();

let parent = Entity::builder()
.set(name(), &quot;Parent&quot;.into())
.spawn(&amp;mut world);
Expand All @@ -199,13 +199,11 @@ <h1 id="relations"><a class="header" href="#relations">Relations</a></h1>
.set(name(), &quot;Child2&quot;.into())
.set_default(child_of(parent))
.spawn(&amp;mut world);

<span class="boring">}</span></code></pre></pre>
<p>Important to note is that the same <code>child_of</code> component with different <code>object</code>
arguments are distinct, and can as such exist on an entity at the same time,
allowing many-many relationships between entities;</p>
<p>There is no limitation of the number of relations an entity can have. As such,
an entity can have multiple relations to other entities, allowing for any kind of graphs inside the ecs.</p>
<p>The parameter to the component function determines the target entity of the relation.</p>
<p>Since the value of the relation in this case is <code>()</code>, <code>set_default</code> can be used as a shorthand over <code>set</code></p>
<p>Two relations of the same type but with different <em>targets</em> behave like two separate components and will not interfere. This allows having many-to-many relationships between entities, if so desired.</p>
<p>This allows constructing many different kinds of graphs inside the ECS.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span> let parent2 = Entity::builder()
Expand All @@ -216,13 +214,12 @@ <h1 id="relations"><a class="header" href="#relations">Relations</a></h1>

tracing::info!(&quot;World: {world:#?}&quot;);

// Connect child1 with two entities via springs of different strength
world.set(child1, spring_joint(child2), 1.5)?;
world.set(child1, spring_joint(parent2), 7.4)?;
// Give child1 yet one more parent
world.set(child1, child_of(parent2), ())?;

tracing::info!(
&quot;Connections from child1({child1}): {:?}&quot;,
Query::new(relations_like(spring_joint))
Query::new(relations_like(child_of))
.borrow(&amp;world)
.get(child1)?
.collect_vec()
Expand All @@ -234,40 +231,126 @@ <h2 id="queries"><a class="header" href="#queries">Queries</a></h2>
used to exclude components.</p>
<p>See the <a href="../query/graphs.html">Graphs</a> chapter in queries.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span>
<span class="boring">fn main() {
</span> let children_of_parent = Query::new(entity_ids())
</span><span class="boring">fn main() {
</span> // Mathes a relation exactly
let children_of_parent: Vec&lt;Entity&gt; = Query::new(entity_ids())
.with(child_of(parent))
.borrow(&amp;world)
.iter()
.collect_vec();
.collect_vec(&amp;world);

tracing::info!(&quot;Children: {children_of_parent:?}&quot;);

let all_children = Query::new(entity_ids())
// Matches a relation with any parent
let all_children: Vec&lt;Entity&gt; = Query::new(entity_ids())
.filter(child_of.with_relation())
.borrow(&amp;world)
.iter()
.collect_vec();
.collect_vec(&amp;world);

tracing::info!(&quot;Children: {all_children:?}&quot;);

let roots = Query::new(entity_ids())
.filter(child_of.without_relation())
.borrow(&amp;world)
.iter()
.collect_vec();
.collect_vec(&amp;world);

tracing::info!(&quot;Roots: {roots:?}&quot;);
<span class="boring">}</span></code></pre></pre>
<h2 id="associated-values"><a class="header" href="#associated-values">Associated values</a></h2>
<p>In addition to linking between entities, a relation can also store additional data just like a component. This can be used to create weighted graphs or storing other additional information such as physical joint parameters.</p>
<p>Since relations behave like separate components, each value on a relation is specific to that link, and as such saves you the hassle of managing a separate list of values for each connection on an entity.</p>
<p>The following shows a more complete example of how to traverse and calculate the forces between entities connected via springs using hook's law.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span> struct Spring {
strength: f32,
length: f32,
}

impl Spring {
fn new(strength: f32, length: f32) -&gt; Self {
Self { strength, length }
}
}
component! {
spring_joint(id): Spring,
position: Vec2,
}

let id1 = Entity::builder()
.set(name(), &quot;a&quot;.into())
.set(position(), vec2(1.0, 4.0))
.spawn(&amp;mut world);

// Connect id2 to id1 with a spring of strength 2.0
let id2 = Entity::builder()
.set(name(), &quot;b&quot;.into())
.set(spring_joint(id1), Spring::new(2.0, 1.0))
.set(position(), vec2(2.0, 0.0))
.spawn(&amp;mut world);

let _id3 = Entity::builder()
.set(name(), &quot;c&quot;.into())
.set(spring_joint(id1), Spring::new(2.0, 3.0))
.set(position(), vec2(2.0, 3.0))
.spawn(&amp;mut world);

let _id4 = Entity::builder()
.set(name(), &quot;d&quot;.into())
.set(spring_joint(id2), Spring::new(5.0, 0.5))
.set(position(), vec2(1.0, 0.0))
.spawn(&amp;mut world);

let mut query = Query::new((entity_ids(), name().cloned(), position()))
.with_strategy(Dfs::new(spring_joint));

query
.borrow(&amp;world)
.traverse(&amp;None, |(id, name, &amp;pos), strength, parent| {
if let (Some(spring), Some((parent_name, parent_pos))) = (strength, parent) {
let distance = pos.distance(*parent_pos) - spring.length;
let force = distance * spring.strength;
tracing::info!(&quot;spring acting with {force:.1}N between {parent_name} and {name}&quot;);
} else {
tracing::info!(%id, name, &quot;root&quot;);
}

Some((name, pos))
});
<span class="boring">}</span></code></pre></pre>
<h1 id="exclusive-relations"><a class="header" href="#exclusive-relations">Exclusive relations</a></h1>
<p>Relations can be declared as exclusive, which means that only one relation of that type can exist on an entity at a time. This is useful for cases where you want to have a single parent or outgoing connection. </p>
<p><strong>Note</strong>: This does not prevent multiple entities from referencing the same entity, but rather an entity referencing multiple entities.</p>
<p>When a new relation is added to an entity, any existing relation of the same type will be removed.</p>
<p>This is the case for the included <a href="https://docs.rs/flax/latest/flax/components/fn.child_of.html"><code>child_of</code></a> relation.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span> component! {
child_of(parent): () =&gt; [ Exclusive ],
}

let id1 = Entity::builder().spawn(&amp;mut world);
let id2 = Entity::builder().spawn(&amp;mut world);

let id3 = Entity::builder()
.set_default(child_of(id1))
.spawn(&amp;mut world);

let entity = world.entity_mut(id3).unwrap();

tracing::info!(
&quot;relations of {id3}: {:?}&quot;,
entity.relations(child_of).map(|v| v.0).collect_vec()
);

world.set(id3, child_of(id2), ()).unwrap();

let entity = world.entity_mut(id3).unwrap();
tracing::info!(
&quot;relations of {id3}: {:?}&quot;,
entity.relations(child_of).map(|v| v.0).collect_vec()
);
<span class="boring">}</span></code></pre></pre>
<h2 id="lifetime"><a class="header" href="#lifetime">Lifetime</a></h2>
<p>When an entity is despawned, all relations to it present on other components
will be removed and dropped. As such, no entity will have a relation to an
entity which does not exist.</p>
<p>Relations are managed by the ECS and will automatically be cleaned up. When an entity is despawned all relations which reference it will be removed from the ECS. As such, a relation will never point to an invalid entity.</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span>
<span class="boring">fn main() {
</span><span class="boring">fn main() {
</span> tracing::info!(
&quot;has relation to: {parent2}: {}&quot;,
world.has(child1, child_of(parent2))
Expand Down
2 changes: 1 addition & 1 deletion guide/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ <h2 id="what-is-an-ecs"><a class="header" href="#what-is-an-ecs">What is an ECS<
and new functionality can be added to existing entities and components.</p>
<h2 id="how-it-works"><a class="header" href="#how-it-works">How it works</a></h2>
<p>In Flax, there are 3 fundamental building blocks.</p>
<p><a href="https://docs.rs/flax/latest/flax/struct.Entity.html">Entity</a>. A unique identifier for the objects of the program. Has a managed lifecycle.</p>
<p><a href="https://docs.rs/flax/latest/flax/struct.Entity.html">Entity</a>. A unique identifier for the entities of the program. Has a managed lifecycle.</p>
<p><a href="https://docs.rs/flax/latest/flax/struct.Component.html">Component</a>, data which
can be added to an Entity. Has a unique Id, which works as the key for storing
and retrieving the value, and a strongly typed value.</p>
Expand Down
2 changes: 1 addition & 1 deletion guide/introduction.html
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ <h2 id="what-is-an-ecs"><a class="header" href="#what-is-an-ecs">What is an ECS<
and new functionality can be added to existing entities and components.</p>
<h2 id="how-it-works"><a class="header" href="#how-it-works">How it works</a></h2>
<p>In Flax, there are 3 fundamental building blocks.</p>
<p><a href="https://docs.rs/flax/latest/flax/struct.Entity.html">Entity</a>. A unique identifier for the objects of the program. Has a managed lifecycle.</p>
<p><a href="https://docs.rs/flax/latest/flax/struct.Entity.html">Entity</a>. A unique identifier for the entities of the program. Has a managed lifecycle.</p>
<p><a href="https://docs.rs/flax/latest/flax/struct.Component.html">Component</a>, data which
can be added to an Entity. Has a unique Id, which works as the key for storing
and retrieving the value, and a strongly typed value.</p>
Expand Down
Loading

0 comments on commit 5646bb5

Please sign in to comment.