mirror of
https://github.com/Reuh/ubiquitousse.git
synced 2025-10-27 09:09:30 +00:00
ecs: implement skip lists
This commit is contained in:
parent
0ea6117af9
commit
bd28610ff4
14 changed files with 936 additions and 639 deletions
|
|
@ -113,7 +113,7 @@
|
||||||
</div> <!-- id="main" -->
|
</div> <!-- id="main" -->
|
||||||
<div id="about">
|
<div id="about">
|
||||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||||
<i style="float:right;">Last updated 2022-10-07 12:40:59 </i>
|
<i style="float:right;">Last updated 2022-10-11 19:12:05 </i>
|
||||||
</div> <!-- id="about" -->
|
</div> <!-- id="about" -->
|
||||||
</div> <!-- id="container" -->
|
</div> <!-- id="container" -->
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -337,7 +337,7 @@
|
||||||
</div> <!-- id="main" -->
|
</div> <!-- id="main" -->
|
||||||
<div id="about">
|
<div id="about">
|
||||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||||
<i style="float:right;">Last updated 2022-10-07 12:40:59 </i>
|
<i style="float:right;">Last updated 2022-10-11 19:12:05 </i>
|
||||||
</div> <!-- id="about" -->
|
</div> <!-- id="about" -->
|
||||||
</div> <!-- id="container" -->
|
</div> <!-- id="container" -->
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,8 @@ Main differences include:</p>
|
||||||
<li>ability to nest systems (more organisation potential);</li>
|
<li>ability to nest systems (more organisation potential);</li>
|
||||||
<li>instanciation of systems for each world (no shared state) (several worlds can coexist at the same time easily);</li>
|
<li>instanciation of systems for each world (no shared state) (several worlds can coexist at the same time easily);</li>
|
||||||
<li>adding and removing entities is done instantaneously (no going isane over tiny-ecs cache issues);</li>
|
<li>adding and removing entities is done instantaneously (no going isane over tiny-ecs cache issues);</li>
|
||||||
<li>ability to add and remove components from entities after they were added to the world (more dynamic entities).</li>
|
<li>ability to add and remove components from entities after they were added to the world (more dynamic entities);</li>
|
||||||
|
<li>much better performance for ordered systems (entities are stored in a skip list internally).</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -83,6 +84,8 @@ if you don’t use them.</p>
|
||||||
<p>The module returns a table that contains several functions, <a href="../modules/ecs.html#world">world</a> or <a href="../modules/scene.html#">scene</a> are starting points
|
<p>The module returns a table that contains several functions, <a href="../modules/ecs.html#world">world</a> or <a href="../modules/scene.html#">scene</a> are starting points
|
||||||
to create your world.</p>
|
to create your world.</p>
|
||||||
|
|
||||||
|
<p>This library was designed to be reasonably fast; on my machine using LuaJIT, in the duration of a frame (1/60 seconds) about 40000 entities can be added to an unordered system or 8000 to an ordered system. Complexities are documented for each function.</p>
|
||||||
|
|
||||||
<p>No mandatory dependency.
|
<p>No mandatory dependency.
|
||||||
Optional dependency: <a href="../modules/ubiquitousse.html#scene">ubiquitousse.scene</a>, to allow quick creation of ECS-based scenes (<a href="../modules/ecs.html#scene">ecs.scene</a>).</p>
|
Optional dependency: <a href="../modules/ubiquitousse.html#scene">ubiquitousse.scene</a>, to allow quick creation of ECS-based scenes (<a href="../modules/ecs.html#scene">ecs.scene</a>).</p>
|
||||||
<h3>Usage:</h3>
|
<h3>Usage:</h3>
|
||||||
|
|
@ -140,6 +143,26 @@ end
|
||||||
</table>
|
</table>
|
||||||
<h3 class="doc-title"><a href="#Entity.Component">Components.</a></h3>
|
<h3 class="doc-title"><a href="#Entity.Component">Components.</a></h3>
|
||||||
<table class="function_list">
|
<table class="function_list">
|
||||||
|
<tr>
|
||||||
|
<td class="name" nowrap><a href="#Entity.first">Entity.first</a></td>
|
||||||
|
<td class="summary">First element of the highest layer linked list of entities: { entity, next_element, element_in_lower_layer }.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="name" nowrap><a href="#Entity.firstBase">Entity.firstBase</a></td>
|
||||||
|
<td class="summary">First element of the base layer.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="name" nowrap><a href="#Entity.previous">Entity.previous</a></td>
|
||||||
|
<td class="summary">List of hash map (one per skip listlayer) of entities in the system and their previous linked list element.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="name" nowrap><a href="#Entity.nLayers">Entity.nLayers</a></td>
|
||||||
|
<td class="summary">Number of layers in the skip list.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="name" nowrap><a href="#Entity.n">Entity.n</a></td>
|
||||||
|
<td class="summary">Number of elements in the skip list.</td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<h2><a href="#System_objects">System objects </a></h2>
|
<h2><a href="#System_objects">System objects </a></h2>
|
||||||
<table class="function_list">
|
<table class="function_list">
|
||||||
|
|
@ -519,6 +542,117 @@ component or if it doesn’t exist in the entity.
|
||||||
}</pre>
|
}</pre>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
<dt>
|
||||||
|
<a name = "Entity.first"></a>
|
||||||
|
<strong>Entity.first</strong>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
First element of the highest layer linked list of entities: { entity, next_element, element_in_lower_layer }.
|
||||||
|
The default entity <code>head</code> is always added as a first element to simplify algorithms; remember to skip it.
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>Fields:</h3>
|
||||||
|
<ul>
|
||||||
|
<li><span class="parameter">head</span>
|
||||||
|
|
||||||
|
|
||||||
|
</li>
|
||||||
|
<li><span class="parameter">nil</span>
|
||||||
|
|
||||||
|
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
<dt>
|
||||||
|
<a name = "Entity.firstBase"></a>
|
||||||
|
<strong>Entity.firstBase</strong>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
First element of the base layer.
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
<dt>
|
||||||
|
<a name = "Entity.previous"></a>
|
||||||
|
<strong>Entity.previous</strong>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
List of hash map (one per skip listlayer) of entities in the system and their previous linked list element.
|
||||||
|
Does not contain a key for the <code>head</code> entity.
|
||||||
|
This make each linked list layer effectively a doubly linked list, but with fast access to the previous element using this map (and therefore O(1) deletion).
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>Fields:</h3>
|
||||||
|
<ul>
|
||||||
|
<li><span class="parameter">{</span>
|
||||||
|
|
||||||
|
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
<dt>
|
||||||
|
<a name = "Entity.nLayers"></a>
|
||||||
|
<strong>Entity.nLayers</strong>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
Number of layers in the skip list.
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
<dt>
|
||||||
|
<a name = "Entity.n"></a>
|
||||||
|
<strong>Entity.n</strong>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
Number of elements in the skip list.
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
<h2 class="section-header has-description"><a name="System_objects"></a>System objects </h2>
|
<h2 class="section-header has-description"><a name="System_objects"></a>System objects </h2>
|
||||||
|
|
@ -1306,7 +1440,7 @@ avoid repeating your filters or allow controlling several system from a single p
|
||||||
If you do that, since <a href="../modules/ecs.html#System:remove">System:remove</a> will not search for entities in systems where they should have been filtered out, the added entities will not be removed
|
If you do that, since <a href="../modules/ecs.html#System:remove">System:remove</a> will not search for entities in systems where they should have been filtered out, the added entities will not be removed
|
||||||
when calling <a href="../modules/ecs.html#System:remove">System:remove</a> on a parent system or the world. The entity can be removed by calling <a href="../modules/ecs.html#System:remove">System:remove</a> on the system <a href="../modules/ecs.html#System:add">System:add</a> was called on.</p>
|
when calling <a href="../modules/ecs.html#System:remove">System:remove</a> on a parent system or the world. The entity can be removed by calling <a href="../modules/ecs.html#System:remove">System:remove</a> on the system <a href="../modules/ecs.html#System:add">System:add</a> was called on.</p>
|
||||||
|
|
||||||
<p> Complexity: O(1) per unordered system, O(entityCount) per ordered system.
|
<p> Complexity: O(1) per unordered system, O(log2(entityCount)) per ordered system.
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
@ -1349,7 +1483,7 @@ avoid repeating your filters or allow controlling several system from a single p
|
||||||
|
|
||||||
<p> If you intend to call this on a subsystem instead of the world, please read the warning in <a href="../modules/ecs.html#System:add">System:add</a>.</p>
|
<p> If you intend to call this on a subsystem instead of the world, please read the warning in <a href="../modules/ecs.html#System:add">System:add</a>.</p>
|
||||||
|
|
||||||
<p> Complexity: O(1) per system.
|
<p> Complexity: O(1) per unordered system, O(log2(entityCount)) per ordered system.
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
@ -1429,7 +1563,7 @@ avoid repeating your filters or allow controlling several system from a single p
|
||||||
<p> Will recalculate the entity position in the entity list for this system and its subsystems.
|
<p> Will recalculate the entity position in the entity list for this system and its subsystems.
|
||||||
Will skip entities that are not in the system.</p>
|
Will skip entities that are not in the system.</p>
|
||||||
|
|
||||||
<p> Complexity: O(entityCount) per system.
|
<p> Complexity: O(1) per unordered system, O(log2(entityCount)) per ordered system.
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
@ -1501,7 +1635,9 @@ avoid repeating your filters or allow controlling several system from a single p
|
||||||
<strong>System:iter ()</strong>
|
<strong>System:iter ()</strong>
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
Returns an iterator that iterate through the entties in this system, in order.
|
Returns an iterator that iterate through the entties in this system, in order. </p>
|
||||||
|
|
||||||
|
<p> Complexity: O(1) per iteration; O(entityCount) for the full iteration
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
@ -1525,9 +1661,9 @@ avoid repeating your filters or allow controlling several system from a single p
|
||||||
<strong>System:get (i)</strong>
|
<strong>System:get (i)</strong>
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
Get the <code>i</code>th entity in the system.
|
Get the <code>i</code>th entity in the system. </p>
|
||||||
This is a simple wrapper around <a href="../modules/ecs.html#System:iter">iter</a>; it <em>will</em> iterate over all the entities in the system in order until we reach the desired one.
|
|
||||||
Complexity: O(i)
|
<p> Complexity: O(i)
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
@ -1558,7 +1694,9 @@ avoid repeating your filters or allow controlling several system from a single p
|
||||||
<strong>System:clear ()</strong>
|
<strong>System:clear ()</strong>
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
Remove every entity from the system and its subsystems.
|
Remove every entity from the system and its subsystems. </p>
|
||||||
|
|
||||||
|
<p> Complexity: O(entityCount) per system
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
@ -1578,7 +1716,9 @@ avoid repeating your filters or allow controlling several system from a single p
|
||||||
<dd>
|
<dd>
|
||||||
Try to update the system and its subsystems. Should be called on every game update.</p>
|
Try to update the system and its subsystems. Should be called on every game update.</p>
|
||||||
|
|
||||||
<p> Subsystems are updated after their parent system.
|
<p> Subsystems are updated after their parent system.</p>
|
||||||
|
|
||||||
|
<p> Complexity: O(entityCount) per system if system:process is defined; O(1) per system otherwise.
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
@ -1605,7 +1745,9 @@ avoid repeating your filters or allow controlling several system from a single p
|
||||||
<dd>
|
<dd>
|
||||||
Try to draw the system and its subsystems. Should be called on every game draw.</p>
|
Try to draw the system and its subsystems. Should be called on every game draw.</p>
|
||||||
|
|
||||||
<p> Subsystems are drawn after their parent system.
|
<p> Subsystems are drawn after their parent system.</p>
|
||||||
|
|
||||||
|
<p> — Complexity: O(entityCount) per system if system:render is defined; O(1) per system otherwise.
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
@ -1629,7 +1771,9 @@ avoid repeating your filters or allow controlling several system from a single p
|
||||||
if the method exists and the entity is in the system. <code>c</code> is the system <a href="#Entity.Component">component</a>
|
if the method exists and the entity is in the system. <code>c</code> is the system <a href="#Entity.Component">component</a>
|
||||||
associated with the current system, and <code>e</code> is the <a href="../modules/ecs.html#Entity_objects">Entity</a>.</p>
|
associated with the current system, and <code>e</code> is the <a href="../modules/ecs.html#Entity_objects">Entity</a>.</p>
|
||||||
|
|
||||||
<p> Think of it as a way to perform custom callbacks issued from an entity event, similar to <a href="../modules/ecs.html#System:onAdd">System:onAdd</a>.
|
<p> Think of it as a way to perform custom callbacks issued from an entity event, similar to <a href="../modules/ecs.html#System:onAdd">System:onAdd</a>.</p>
|
||||||
|
|
||||||
|
<p> Complexity: O(1) per system
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
@ -1681,7 +1825,9 @@ its sibling systems (i.e. completely stop the propagation of the event).</li>
|
||||||
disable <a href="../modules/ecs.html#System:onUpdate">System:onUpdate</a> behaviour on the system and its subsystems).</p>
|
disable <a href="../modules/ecs.html#System:onUpdate">System:onUpdate</a> behaviour on the system and its subsystems).</p>
|
||||||
|
|
||||||
<p> <code>"capture"</code> would be for example used to prevent other systems from handling the event (for example to make sure an
|
<p> <code>"capture"</code> would be for example used to prevent other systems from handling the event (for example to make sure an
|
||||||
input event is handled only once by a single system).
|
input event is handled only once by a single system).</p>
|
||||||
|
|
||||||
|
<p> Complexity: O(1) per system
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
@ -1710,6 +1856,7 @@ its sibling systems (i.e. completely stop the propagation of the event).</li>
|
||||||
</dt>
|
</dt>
|
||||||
<dd>
|
<dd>
|
||||||
Remove all the entities and subsystems in this system.
|
Remove all the entities and subsystems in this system.
|
||||||
|
Complexity: O(entityCount) per system
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
@ -1729,7 +1876,7 @@ its sibling systems (i.e. completely stop the propagation of the event).</li>
|
||||||
</div> <!-- id="main" -->
|
</div> <!-- id="main" -->
|
||||||
<div id="about">
|
<div id="about">
|
||||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||||
<i style="float:right;">Last updated 2022-10-07 12:40:59 </i>
|
<i style="float:right;">Last updated 2022-10-11 19:12:05 </i>
|
||||||
</div> <!-- id="about" -->
|
</div> <!-- id="about" -->
|
||||||
</div> <!-- id="container" -->
|
</div> <!-- id="container" -->
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -238,6 +238,10 @@ end
|
||||||
<td class="summary">Set the state of this input and its children to a neutral position (i.e.</td>
|
<td class="summary">Set the state of this input and its children to a neutral position (i.e.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
<td class="name" nowrap><a href="#Input:set">Input:set (...)</a></td>
|
||||||
|
<td class="summary">Manually set the state of this input.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
<td class="name" nowrap><a href="#Input:setJoystick">Input:setJoystick (joystick)</a></td>
|
<td class="name" nowrap><a href="#Input:setJoystick">Input:setJoystick (joystick)</a></td>
|
||||||
<td class="summary">Set the joystick associated with this input.</td>
|
<td class="summary">Set the joystick associated with this input.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
@ -1181,6 +1185,31 @@ player.fire.event:bind(<span class="string">"pressed"</span>, <span class="keywo
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
<dt>
|
||||||
|
<a name = "Input:set"></a>
|
||||||
|
<strong>Input:set (...)</strong>
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
Manually set the state of this input.
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>Parameters:</h3>
|
||||||
|
<ul>
|
||||||
|
<li><span class="parameter">...</span>
|
||||||
|
|
||||||
|
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
<dt>
|
<dt>
|
||||||
<a name = "Input:setJoystick"></a>
|
<a name = "Input:setJoystick"></a>
|
||||||
|
|
@ -1694,7 +1723,7 @@ player.fire.event:bind(<span class="string">"pressed"</span>, <span class="keywo
|
||||||
</div> <!-- id="main" -->
|
</div> <!-- id="main" -->
|
||||||
<div id="about">
|
<div id="about">
|
||||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||||
<i style="float:right;">Last updated 2022-10-07 12:40:59 </i>
|
<i style="float:right;">Last updated 2022-10-11 19:12:05 </i>
|
||||||
</div> <!-- id="about" -->
|
</div> <!-- id="about" -->
|
||||||
</div> <!-- id="container" -->
|
</div> <!-- id="container" -->
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -2066,7 +2066,7 @@ end
|
||||||
Level background. </p>
|
Level background. </p>
|
||||||
|
|
||||||
<p> If there is a background image, <code>background.image</code> contains a table <code>{image=image, x=number, y=number, sx=number, sy=number}</code>
|
<p> If there is a background image, <code>background.image</code> contains a table <code>{image=image, x=number, y=number, sx=number, sy=number}</code>
|
||||||
where <a href="../modules/ldtk.html#Tileset.image">image</a> is the LÖVE image (or image filepath if LÖVE not available) <a href="../modules/ldtk.html#Tile.x">x</a> and <a href="../modules/ldtk.html#Tile.y">y</a> are the top-left position,
|
where <a href="../modules/ldtk.html#Tileset.image">image</a> is the LÖVE image (or image filepath if LÖVE not available) <a href="../modules/ldtk.html#Entity.x">x</a> and <a href="../modules/ldtk.html#Tile.y">y</a> are the top-left position,
|
||||||
and <a href="../modules/ldtk.html#Entity.sx">sx</a> and <a href="../modules/ldtk.html#Entity.sy">sy</a> the horizontal and vertical scale factors.
|
and <a href="../modules/ldtk.html#Entity.sx">sx</a> and <a href="../modules/ldtk.html#Entity.sy">sy</a> the horizontal and vertical scale factors.
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
@ -2142,7 +2142,7 @@ end
|
||||||
<li>Enum are converted into a Lua string giving the currently selected enum value.</li>
|
<li>Enum are converted into a Lua string giving the currently selected enum value.</li>
|
||||||
<li>Filepath are converted into a Lua string giving the file path.</li>
|
<li>Filepath are converted into a Lua string giving the file path.</li>
|
||||||
<li>Arrays are converted into a Lua table with the elements in it as a list.</li>
|
<li>Arrays are converted into a Lua table with the elements in it as a list.</li>
|
||||||
<li>Points are converted into a Lua table with the fields <a href="../modules/ldtk.html#Tile.x">x</a> and <a href="../modules/ldtk.html#Tile.y">y</a>, in pixels: <code>{ x=number, y=number }</code>.</li>
|
<li>Points are converted into a Lua table with the fields <a href="../modules/ldtk.html#Entity.x">x</a> and <a href="../modules/ldtk.html#Tile.y">y</a>, in pixels: <code>{ x=number, y=number }</code>.</li>
|
||||||
<li>Colors are converted into a Lua table with the red, green and blue components in [0-1] as a list: <code>{r,g,b}</code>.</li>
|
<li>Colors are converted into a Lua table with the red, green and blue components in [0-1] as a list: <code>{r,g,b}</code>.</li>
|
||||||
<li>Tiles are converted into a Lua table { tileset = associated tileset object, quad = associated quad } where <a href="../modules/ldtk.html#Tile.quad">quad</a> is a LÖVE Quad if LÖVE is available, otherwise a table <code>{ x, y, width, height }</code>.</li>
|
<li>Tiles are converted into a Lua table { tileset = associated tileset object, quad = associated quad } where <a href="../modules/ldtk.html#Tile.quad">quad</a> is a LÖVE Quad if LÖVE is available, otherwise a table <code>{ x, y, width, height }</code>.</li>
|
||||||
<li>EntityRef are converted into a Lua table { level = level, layerIid = layer IID, entityIid = entity IID, entity = see explanation }. If the entity being refernced belongs to another level and this level is not loaded, <code>entity</code> will be nil; otherwise (same level or the other level is also loaded), it will contain the entity.</li>
|
<li>EntityRef are converted into a Lua table { level = level, layerIid = layer IID, entityIid = entity IID, entity = see explanation }. If the entity being refernced belongs to another level and this level is not loaded, <code>entity</code> will be nil; otherwise (same level or the other level is also loaded), it will contain the entity.</li>
|
||||||
|
|
@ -2170,7 +2170,7 @@ end
|
||||||
</div> <!-- id="main" -->
|
</div> <!-- id="main" -->
|
||||||
<div id="about">
|
<div id="about">
|
||||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||||
<i style="float:right;">Last updated 2022-10-07 12:40:59 </i>
|
<i style="float:right;">Last updated 2022-10-11 19:12:05 </i>
|
||||||
</div> <!-- id="about" -->
|
</div> <!-- id="about" -->
|
||||||
</div> <!-- id="container" -->
|
</div> <!-- id="container" -->
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -703,7 +703,7 @@
|
||||||
</div> <!-- id="main" -->
|
</div> <!-- id="main" -->
|
||||||
<div id="about">
|
<div id="about">
|
||||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||||
<i style="float:right;">Last updated 2022-10-07 12:40:59 </i>
|
<i style="float:right;">Last updated 2022-10-11 19:12:05 </i>
|
||||||
</div> <!-- id="about" -->
|
</div> <!-- id="about" -->
|
||||||
</div> <!-- id="container" -->
|
</div> <!-- id="container" -->
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -788,7 +788,7 @@ signal.event:bind("keypressed", function(key, scancode) print("pr
|
||||||
</div> <!-- id="main" -->
|
</div> <!-- id="main" -->
|
||||||
<div id="about">
|
<div id="about">
|
||||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||||
<i style="float:right;">Last updated 2022-10-07 12:40:59 </i>
|
<i style="float:right;">Last updated 2022-10-11 19:12:05 </i>
|
||||||
</div> <!-- id="about" -->
|
</div> <!-- id="about" -->
|
||||||
</div> <!-- id="container" -->
|
</div> <!-- id="container" -->
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -1154,7 +1154,7 @@
|
||||||
</div> <!-- id="main" -->
|
</div> <!-- id="main" -->
|
||||||
<div id="about">
|
<div id="about">
|
||||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||||
<i style="float:right;">Last updated 2022-10-07 12:40:59 </i>
|
<i style="float:right;">Last updated 2022-10-11 19:12:05 </i>
|
||||||
</div> <!-- id="about" -->
|
</div> <!-- id="about" -->
|
||||||
</div> <!-- id="container" -->
|
</div> <!-- id="container" -->
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -394,7 +394,7 @@ the repository to save you a few seconds.</p>
|
||||||
</div> <!-- id="main" -->
|
</div> <!-- id="main" -->
|
||||||
<div id="about">
|
<div id="about">
|
||||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||||
<i style="float:right;">Last updated 2022-10-07 12:40:59 </i>
|
<i style="float:right;">Last updated 2022-10-11 19:12:05 </i>
|
||||||
</div> <!-- id="about" -->
|
</div> <!-- id="about" -->
|
||||||
</div> <!-- id="container" -->
|
</div> <!-- id="container" -->
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -785,7 +785,7 @@
|
||||||
</div> <!-- id="main" -->
|
</div> <!-- id="main" -->
|
||||||
<div id="about">
|
<div id="about">
|
||||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||||
<i style="float:right;">Last updated 2022-10-07 12:40:59 </i>
|
<i style="float:right;">Last updated 2022-10-11 19:12:05 </i>
|
||||||
</div> <!-- id="about" -->
|
</div> <!-- id="about" -->
|
||||||
</div> <!-- id="container" -->
|
</div> <!-- id="container" -->
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@
|
||||||
</div> <!-- id="main" -->
|
</div> <!-- id="main" -->
|
||||||
<div id="about">
|
<div id="about">
|
||||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||||
<i style="float:right;">Last updated 2022-10-07 12:40:59 </i>
|
<i style="float:right;">Last updated 2022-10-11 19:12:05 </i>
|
||||||
</div> <!-- id="about" -->
|
</div> <!-- id="about" -->
|
||||||
</div> <!-- id="container" -->
|
</div> <!-- id="container" -->
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@
|
||||||
</div> <!-- id="main" -->
|
</div> <!-- id="main" -->
|
||||||
<div id="about">
|
<div id="about">
|
||||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.6</a></i>
|
||||||
<i style="float:right;">Last updated 2022-10-07 12:40:59 </i>
|
<i style="float:right;">Last updated 2022-10-11 19:12:05 </i>
|
||||||
</div> <!-- id="about" -->
|
</div> <!-- id="about" -->
|
||||||
</div> <!-- id="container" -->
|
</div> <!-- id="container" -->
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
294
ecs/ecs.can
294
ecs/ecs.can
|
|
@ -6,7 +6,8 @@ Main differences include:
|
||||||
* ability to nest systems (more organisation potential);
|
* ability to nest systems (more organisation potential);
|
||||||
* instanciation of systems for each world (no shared state) (several worlds can coexist at the same time easily);
|
* instanciation of systems for each world (no shared state) (several worlds can coexist at the same time easily);
|
||||||
* adding and removing entities is done instantaneously (no going isane over tiny-ecs cache issues);
|
* adding and removing entities is done instantaneously (no going isane over tiny-ecs cache issues);
|
||||||
* ability to add and remove components from entities after they were added to the world (more dynamic entities).
|
* ability to add and remove components from entities after they were added to the world (more dynamic entities);
|
||||||
|
* much better performance for ordered systems (entities are stored in a skip list internally).
|
||||||
|
|
||||||
And a fair amount of other quality-of-life features.
|
And a fair amount of other quality-of-life features.
|
||||||
|
|
||||||
|
|
@ -17,6 +18,8 @@ if you don't use them.
|
||||||
The module returns a table that contains several functions, `world` or `scene` are starting points
|
The module returns a table that contains several functions, `world` or `scene` are starting points
|
||||||
to create your world.
|
to create your world.
|
||||||
|
|
||||||
|
This library was designed to be reasonably fast; on my machine using LuaJIT, in the duration of a frame (1/60 seconds) about 40000 entities can be added to an unordered system or 8000 to an ordered system. Complexities are documented for each function.
|
||||||
|
|
||||||
No mandatory dependency.
|
No mandatory dependency.
|
||||||
Optional dependency: `ubiquitousse.scene`, to allow quick creation of ECS-based scenes (`ecs.scene`).
|
Optional dependency: `ubiquitousse.scene`, to allow quick creation of ECS-based scenes (`ecs.scene`).
|
||||||
|
|
||||||
|
|
@ -54,8 +57,7 @@ if not loaded then scene = nil end
|
||||||
|
|
||||||
let ecs
|
let ecs
|
||||||
|
|
||||||
-- TODO: Implement a skip list for faster search.
|
-- TODO: better control over system order: process, draw, methods? (for lag reasons and dependencies)
|
||||||
-- better control over system order: process, draw, methods? (for lag reasons and dependencies)
|
|
||||||
|
|
||||||
--- Entities are regular tables that get processed by `System`s.
|
--- Entities are regular tables that get processed by `System`s.
|
||||||
--
|
--
|
||||||
|
|
@ -98,9 +100,6 @@ local sprite = {
|
||||||
}
|
}
|
||||||
]]--
|
]]--
|
||||||
|
|
||||||
--- Special value used as the first element of each system's linked list of entities.
|
|
||||||
let head = {}
|
|
||||||
|
|
||||||
--- Recursively remove subsystems from a system.
|
--- Recursively remove subsystems from a system.
|
||||||
let recDestroySystems = (system)
|
let recDestroySystems = (system)
|
||||||
for i=#system.systems, 1, -1 do
|
for i=#system.systems, 1, -1 do
|
||||||
|
|
@ -122,17 +121,6 @@ let recCallOnRemoveFromWorld = (world, systems)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Iterate through the next entity, based on state s: { previousLinkedListItem }
|
|
||||||
let nextEntity = (s)
|
|
||||||
if s[1] then
|
|
||||||
let var = s[1][1]
|
|
||||||
s[1] = s[1][2]
|
|
||||||
return var
|
|
||||||
else
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Recursively copy content of a into b if it isn't already present.
|
--- Recursively copy content of a into b if it isn't already present.
|
||||||
-- Don't copy keys, will preserve metatable but not copy them.
|
-- Don't copy keys, will preserve metatable but not copy them.
|
||||||
let copy = (a, b, cache={})
|
let copy = (a, b, cache={})
|
||||||
|
|
@ -156,6 +144,149 @@ let copy = (a, b, cache={})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Skip list implementation ---
|
||||||
|
-- Well technically it's a conbination of a skip list (for ordering) and a hash map (for that sweet O(1) search). Takes more memory but oh so efficient.
|
||||||
|
|
||||||
|
--- Special value used as the first element of each linked list.
|
||||||
|
let head = {}
|
||||||
|
|
||||||
|
--- Create a new linked list.
|
||||||
|
let skipNew = ()
|
||||||
|
let s = {
|
||||||
|
--- First element of the highest layer linked list of entities: { entity, next_element, element_in_lower_layer }.
|
||||||
|
-- The default entity `head` is always added as a first element to simplify algorithms; remember to skip it.
|
||||||
|
first = { head, nil },
|
||||||
|
--- First element of the base layer.
|
||||||
|
firstBase = nil,
|
||||||
|
--- List of hash map (one per skip listlayer) of entities in the system and their previous linked list element.
|
||||||
|
-- Does not contain a key for the `head` entity.
|
||||||
|
-- This make each linked list layer effectively a doubly linked list, but with fast access to the previous element using this map (and therefore O(1) deletion).
|
||||||
|
previous = { {} },
|
||||||
|
--- Number of layers in the skip list.
|
||||||
|
nLayers = 1,
|
||||||
|
--- Number of elements in the skip list.
|
||||||
|
n = 0
|
||||||
|
}
|
||||||
|
s.firstBase = s.first
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Iterate through the next entity in a linked list, based on state s: { previousLinkedListItem }
|
||||||
|
let nextEntity = (s)
|
||||||
|
if s[1] then
|
||||||
|
let var = s[1][1]
|
||||||
|
s[1] = s[1][2]
|
||||||
|
return var
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--- Returns an iterator over all the elements of the skip list.
|
||||||
|
-- Complexity: O(n) like expected
|
||||||
|
let skipIter = :()
|
||||||
|
return nextEntity, { @firstBase[2] }
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Add new layers (if needed) in order to target O(log2(n)) complexity for skip list operations.
|
||||||
|
-- i.e. add layers until we have log2(n) layers
|
||||||
|
-- Complexity: O(log2(n)) if you never called it before, but you should call it with every insert for O(1)
|
||||||
|
let skipAddLayers = :()
|
||||||
|
while @n > 2^@nLayers do
|
||||||
|
@first = { head, nil, @first }
|
||||||
|
table.insert(@previous, {})
|
||||||
|
@nLayers += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- 1/2 chance of being true, 1/2 of being false! How exciting!
|
||||||
|
let coinFlip = ()
|
||||||
|
return math.random(0,1) == 1
|
||||||
|
end
|
||||||
|
--- Insert an element into the skip list using system:compare for ordering.
|
||||||
|
-- Behavior undefined if e is already in the skip list.
|
||||||
|
-- Complexity: if luck is on your side, O(log2(n)); O(n) if the universe hates you; O(1) if compare always returns true and nLayers = 1
|
||||||
|
let skipInsert = :(system, e)
|
||||||
|
-- find previous entity in each layer
|
||||||
|
let prevLayer = {}
|
||||||
|
let prev = @first -- no need to process first entity as it is the special `head` entity
|
||||||
|
for i=@nLayers, 1, -1 do
|
||||||
|
while true do
|
||||||
|
-- next is end of layer or greater entity: select this prev entity
|
||||||
|
if prev[2] == nil or system:compare(e, prev[2][1]) then
|
||||||
|
prevLayer[i] = prev
|
||||||
|
-- not on base layer: go down a layer, for loop will continue
|
||||||
|
if prev[3] then
|
||||||
|
prev = prev[3] -- same entity on lower layer
|
||||||
|
break
|
||||||
|
end
|
||||||
|
break
|
||||||
|
-- next entity on current layer
|
||||||
|
else
|
||||||
|
prev = prev[2]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- add to each layer
|
||||||
|
let inLowerLayer
|
||||||
|
for i=1, @nLayers do
|
||||||
|
prev = prevLayer[i]
|
||||||
|
if i == 1 or coinFlip() then -- always present in base layer, otherwise 1/2 chance
|
||||||
|
let nxt = prev[2]
|
||||||
|
prev[2] = { e, nxt, inLowerLayer }
|
||||||
|
@previous[i][e] = prev
|
||||||
|
if nxt then
|
||||||
|
@previous[i][nxt[1]] = prev[2]
|
||||||
|
end
|
||||||
|
inLowerLayer = prev[2]
|
||||||
|
else
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@n += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Remove an element from the skip list.
|
||||||
|
-- Behavior undefined if e is not in the skip list.
|
||||||
|
-- Complexity: O(nLayers) at most, which should be O(log2(n)) if you called skipAddLayers often enough
|
||||||
|
let skipDelete = :(e)
|
||||||
|
-- remove from each layer
|
||||||
|
for i=1, @nLayers do
|
||||||
|
let previous = @previous[i]
|
||||||
|
if previous[e] then
|
||||||
|
let prev = previous[e]
|
||||||
|
prev[2] = prev[2][2]
|
||||||
|
previous[e] = nil
|
||||||
|
if prev[2] then
|
||||||
|
previous[prev[2][1]] = prev
|
||||||
|
end
|
||||||
|
else
|
||||||
|
break -- won't appear on higher layers either
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@n -= 1
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Reorder an element into the skip list.
|
||||||
|
-- Behavior undefined if e is not in the skip list.
|
||||||
|
-- Complexity: if luck is on your side, O(log2(n)); O(n) if the universe hates you; O(1) if compare always returns true and nLayers = 1
|
||||||
|
let skipReorder = :(system, e)
|
||||||
|
skipDelete(@, e)
|
||||||
|
skipInsert(@, system, e)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the ith element of the skip list.
|
||||||
|
-- Complexity: O(n)
|
||||||
|
let skipIndex = :(i)
|
||||||
|
local n = 1
|
||||||
|
for e in skipIter(@) do
|
||||||
|
if n == i then
|
||||||
|
return e
|
||||||
|
end
|
||||||
|
n += 1
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
--[[-- Systems and Worlds.
|
--[[-- Systems and Worlds.
|
||||||
Systems are what do the processing on your entities. A system contains a list of entities; the entities in this list are selected
|
Systems are what do the processing on your entities. A system contains a list of entities; the entities in this list are selected
|
||||||
using a `filter`, and the system will only operate on those filtered entities.
|
using a `filter`, and the system will only operate on those filtered entities.
|
||||||
|
|
@ -385,14 +516,12 @@ let system_mt = {
|
||||||
|
|
||||||
--- Private fields ---
|
--- Private fields ---
|
||||||
|
|
||||||
--- First element of the linked list of entities: { entity, next_element }.
|
--- Hash map of the entities currently in the system.
|
||||||
-- The default entity `head` is always added as a first element to simplify algorithms; remember to skip it.
|
-- Used to quickly check if an entity is present of not in this system.
|
||||||
|
-- This is actually the _skiplist.previous[1] table.
|
||||||
-- @local
|
-- @local
|
||||||
_first = nil,
|
_has = nil,
|
||||||
--- Hash map of entities in the system and their previous linked list element. Does not contain a key for the `head` entity.
|
|
||||||
-- This make the list effectively a doubly linked list, but with fast access to the previous element using this map (and therefore O(1) deletion).
|
|
||||||
-- @local
|
|
||||||
_previous = nil,
|
|
||||||
--- Amount of time waited since last update (if interval is set).
|
--- Amount of time waited since last update (if interval is set).
|
||||||
-- @local
|
-- @local
|
||||||
_waited = 0,
|
_waited = 0,
|
||||||
|
|
@ -412,37 +541,27 @@ let system_mt = {
|
||||||
-- If you do that, since `System:remove` will not search for entities in systems where they should have been filtered out, the added entities will not be removed
|
-- If you do that, since `System:remove` will not search for entities in systems where they should have been filtered out, the added entities will not be removed
|
||||||
-- when calling `System:remove` on a parent system or the world. The entity can be removed by calling `System:remove` on the system `System:add` was called on.
|
-- when calling `System:remove` on a parent system or the world. The entity can be removed by calling `System:remove` on the system `System:add` was called on.
|
||||||
--
|
--
|
||||||
-- Complexity: O(1) per unordered system, O(entityCount) per ordered system.
|
-- Complexity: O(1) per unordered system, O(log2(entityCount)) per ordered system.
|
||||||
-- @tparam Entity e entity to add
|
-- @tparam Entity e entity to add
|
||||||
-- @tparam Entity... ... other entities to add
|
-- @tparam Entity... ... other entities to add
|
||||||
-- @treturn Entity,... `e,...` the function arguments
|
-- @treturn Entity,... `e,...` the function arguments
|
||||||
add = :(e, ...)
|
add = :(e, ...)
|
||||||
if e ~= nil and not @_previous[e] and @filter(e) then
|
if e ~= nil and not @_has[e] and @filter(e) then
|
||||||
-- copy default system component
|
-- copy default system component
|
||||||
if @component and @default then
|
if @component and @default then
|
||||||
copy({ [@component] = @default }, e)
|
copy({ [@component] = @default }, e)
|
||||||
end
|
end
|
||||||
-- add to linked list
|
-- ordered system: add new layer if needed
|
||||||
let entity = @_first
|
if @compare ~= system_mt.compare then
|
||||||
while entity[2] ~= nil do -- no need to process first entity as it is the special `head` entity
|
skipAddLayers(@_skiplist)
|
||||||
if @compare(e, entity[2][1]) then
|
|
||||||
let nxt = entity[2]
|
|
||||||
entity[2] = { e, nxt }
|
|
||||||
@_previous[e] = entity
|
|
||||||
@_previous[nxt[1]] = entity[2]
|
|
||||||
break
|
|
||||||
end
|
|
||||||
entity = entity[2]
|
|
||||||
end
|
|
||||||
if entity[2] == nil then
|
|
||||||
entity[2] = { e, nil }
|
|
||||||
@_previous[e] = entity
|
|
||||||
end
|
end
|
||||||
|
-- add to skip list
|
||||||
|
skipInsert(@_skiplist, @, e)
|
||||||
-- notify addition
|
-- notify addition
|
||||||
@entityCount += 1
|
@entityCount += 1
|
||||||
@onAdd(e, e[@component])
|
@onAdd(e, e[@component])
|
||||||
-- add to subsystems (if it wasn't immediately removed in onAdd)
|
-- add to subsystems (if it wasn't immediately removed in onAdd)
|
||||||
if @_previous[e] then
|
if @_has[e] then
|
||||||
for _, s in ipairs(@systems) do
|
for _, s in ipairs(@systems) do
|
||||||
s:add(e)
|
s:add(e)
|
||||||
end
|
end
|
||||||
|
|
@ -462,27 +581,21 @@ let system_mt = {
|
||||||
--
|
--
|
||||||
-- If you intend to call this on a subsystem instead of the world, please read the warning in `System:add`.
|
-- If you intend to call this on a subsystem instead of the world, please read the warning in `System:add`.
|
||||||
--
|
--
|
||||||
-- Complexity: O(1) per system.
|
-- Complexity: O(1) per unordered system, O(log2(entityCount)) per ordered system.
|
||||||
-- @tparam Entity e entity to remove
|
-- @tparam Entity e entity to remove
|
||||||
-- @tparam Entity... ... other entities to remove
|
-- @tparam Entity... ... other entities to remove
|
||||||
-- @treturn Entity,... `e,...` the function arguments
|
-- @treturn Entity,... `e,...` the function arguments
|
||||||
remove = :(e, ...)
|
remove = :(e, ...)
|
||||||
if e ~= nil then
|
if e ~= nil then
|
||||||
if @_previous[e] then
|
if @_has[e] then
|
||||||
-- remove from subsystems
|
-- remove from subsystems
|
||||||
for _, s in ipairs(@systems) do
|
for _, s in ipairs(@systems) do
|
||||||
s:remove(e)
|
s:remove(e)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if @_previous[e] then -- recheck in case it was removed already from a subsystem onRemove callback
|
if @_has[e] then -- recheck in case it was removed already from a subsystem onRemove callback
|
||||||
-- remove from linked list
|
skipDelete(@_skiplist, e)
|
||||||
let prev = @_previous[e]
|
|
||||||
prev[2] = prev[2][2]
|
|
||||||
if prev[2] then
|
|
||||||
@_previous[prev[2][1]] = prev
|
|
||||||
end
|
|
||||||
-- notify removal
|
-- notify removal
|
||||||
@_previous[e] = nil
|
|
||||||
@entityCount -= 1
|
@entityCount -= 1
|
||||||
@onRemove(e, e[@component])
|
@onRemove(e, e[@component])
|
||||||
end
|
end
|
||||||
|
|
@ -504,9 +617,9 @@ let system_mt = {
|
||||||
-- @treturn Entity,... `e,...` the function arguments
|
-- @treturn Entity,... `e,...` the function arguments
|
||||||
refresh = :(e, ...)
|
refresh = :(e, ...)
|
||||||
if e ~= nil then
|
if e ~= nil then
|
||||||
if not @_previous[e] then
|
if not @_has[e] then
|
||||||
@add(e)
|
@add(e)
|
||||||
elseif @_previous[e] then
|
else
|
||||||
if not @filter(e) then
|
if not @filter(e) then
|
||||||
@remove(e)
|
@remove(e)
|
||||||
else
|
else
|
||||||
|
|
@ -527,35 +640,13 @@ let system_mt = {
|
||||||
-- Will recalculate the entity position in the entity list for this system and its subsystems.
|
-- Will recalculate the entity position in the entity list for this system and its subsystems.
|
||||||
-- Will skip entities that are not in the system.
|
-- Will skip entities that are not in the system.
|
||||||
--
|
--
|
||||||
-- Complexity: O(entityCount) per system.
|
-- Complexity: O(1) per unordered system, O(log2(entityCount)) per ordered system.
|
||||||
-- @tparam Entity e entity to reorder
|
-- @tparam Entity e entity to reorder
|
||||||
-- @tparam Entity... ... other entities to reorder
|
-- @tparam Entity... ... other entities to reorder
|
||||||
-- @treturn Entity,... `e,...` the function arguments
|
-- @treturn Entity,... `e,...` the function arguments
|
||||||
reorder = :(e, ...)
|
reorder = :(e, ...)
|
||||||
if e ~= nil and @_previous[e] then
|
if e ~= nil and @_has[e] then
|
||||||
let prev = @_previous[e] -- { prev, { e, next } }
|
skipReorder(@_skiplist, @, e)
|
||||||
let next = prev[2][2]
|
|
||||||
-- remove e from linked list
|
|
||||||
prev[2] = next
|
|
||||||
if next then
|
|
||||||
@_previous[next[1]] = prev
|
|
||||||
end
|
|
||||||
-- find position so that prev < e <= next
|
|
||||||
while prev[1] ~= head and @compare(e, prev[1]) do -- ensure prev < e
|
|
||||||
next = prev
|
|
||||||
prev = @_previous[prev[1]]
|
|
||||||
end
|
|
||||||
while next ~= nil and not @compare(e, next[1]) do -- ensure e <= next
|
|
||||||
prev = next
|
|
||||||
next = next[2]
|
|
||||||
end
|
|
||||||
-- reinsert e in linked list
|
|
||||||
let new = { e, next }
|
|
||||||
@_previous[e] = prev
|
|
||||||
if next then
|
|
||||||
@_previous[next[1]] = new
|
|
||||||
end
|
|
||||||
prev[2] = new
|
|
||||||
-- Reorder in subsystems
|
-- Reorder in subsystems
|
||||||
for _, s in ipairs(@systems) do
|
for _, s in ipairs(@systems) do
|
||||||
s:reorder(e)
|
s:reorder(e)
|
||||||
|
|
@ -574,7 +665,7 @@ let system_mt = {
|
||||||
-- @tparam Entity... ... other entities that may be in the system
|
-- @tparam Entity... ... other entities that may be in the system
|
||||||
-- @treturn boolean `true` if every entity is in the system
|
-- @treturn boolean `true` if every entity is in the system
|
||||||
has = :(e, ...)
|
has = :(e, ...)
|
||||||
let has = e == nil or not not @_previous[e]
|
let has = e == nil or not not @_has[e]
|
||||||
if ... then
|
if ... then
|
||||||
return has and @has(...)
|
return has and @has(...)
|
||||||
else
|
else
|
||||||
|
|
@ -582,28 +673,25 @@ let system_mt = {
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
--- Returns an iterator that iterate through the entties in this system, in order.
|
--- Returns an iterator that iterate through the entties in this system, in order.
|
||||||
|
--
|
||||||
|
-- Complexity: O(1) per iteration; O(entityCount) for the full iteration
|
||||||
-- @treturn iterator iterator over the entities in this system
|
-- @treturn iterator iterator over the entities in this system
|
||||||
iter = :()
|
iter = :()
|
||||||
return nextEntity, { @_first[2] }
|
return skipIter(@_skiplist)
|
||||||
end,
|
end,
|
||||||
--- Get the `i`th entity in the system.
|
--- Get the `i`th entity in the system.
|
||||||
-- This is a simple wrapper around `iter`; it _will_ iterate over all the entities in the system in order until we reach the desired one.
|
--
|
||||||
-- Complexity: O(i)
|
-- Complexity: O(i)
|
||||||
-- @tparam number i the index of the entity
|
-- @tparam number i the index of the entity
|
||||||
-- @treturn Entity the entity; `nil` if there is no such entity in the system
|
-- @treturn Entity the entity; `nil` if there is no such entity in the system
|
||||||
get = :(i)
|
get = :(i)
|
||||||
local n = 1
|
return skipIndex(@_skiplist, i)
|
||||||
for e in @iter() do
|
|
||||||
if n == i then
|
|
||||||
return e
|
|
||||||
end
|
|
||||||
n += 1
|
|
||||||
end
|
|
||||||
return nil
|
|
||||||
end,
|
end,
|
||||||
--- Remove every entity from the system and its subsystems.
|
--- Remove every entity from the system and its subsystems.
|
||||||
|
--
|
||||||
|
-- Complexity: O(entityCount) per system
|
||||||
clear = :()
|
clear = :()
|
||||||
for e in @iter() do
|
for e in skipIter(@_skiplist) do
|
||||||
@remove(e)
|
@remove(e)
|
||||||
end
|
end
|
||||||
for _, s in ipairs(@systems) do
|
for _, s in ipairs(@systems) do
|
||||||
|
|
@ -613,6 +701,8 @@ let system_mt = {
|
||||||
--- Try to update the system and its subsystems. Should be called on every game update.
|
--- Try to update the system and its subsystems. Should be called on every game update.
|
||||||
--
|
--
|
||||||
-- Subsystems are updated after their parent system.
|
-- Subsystems are updated after their parent system.
|
||||||
|
--
|
||||||
|
-- Complexity: O(entityCount) per system if system:process is defined; O(1) per system otherwise.
|
||||||
-- @number dt delta-time since last update
|
-- @number dt delta-time since last update
|
||||||
update = :(dt)
|
update = :(dt)
|
||||||
if @active then
|
if @active then
|
||||||
|
|
@ -624,7 +714,7 @@ let system_mt = {
|
||||||
end
|
end
|
||||||
@onUpdate(dt)
|
@onUpdate(dt)
|
||||||
if @process ~= system_mt.process then
|
if @process ~= system_mt.process then
|
||||||
for e in @iter() do
|
for e in skipIter(@_skiplist) do
|
||||||
@process(e, e[@component], dt)
|
@process(e, e[@component], dt)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -640,11 +730,13 @@ let system_mt = {
|
||||||
--- Try to draw the system and its subsystems. Should be called on every game draw.
|
--- Try to draw the system and its subsystems. Should be called on every game draw.
|
||||||
--
|
--
|
||||||
-- Subsystems are drawn after their parent system.
|
-- Subsystems are drawn after their parent system.
|
||||||
|
--
|
||||||
|
-- -- Complexity: O(entityCount) per system if system:render is defined; O(1) per system otherwise.
|
||||||
draw = :()
|
draw = :()
|
||||||
if @visible then
|
if @visible then
|
||||||
@onDraw()
|
@onDraw()
|
||||||
if @render ~= system_mt.render then
|
if @render ~= system_mt.render then
|
||||||
for e in @iter() do
|
for e in skipIter(@_skiplist) do
|
||||||
@render(e, e[@component])
|
@render(e, e[@component])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -661,16 +753,18 @@ let system_mt = {
|
||||||
-- associated with the current system, and `e` is the `Entity`.
|
-- associated with the current system, and `e` is the `Entity`.
|
||||||
--
|
--
|
||||||
-- Think of it as a way to perform custom callbacks issued from an entity event, similar to `System:onAdd`.
|
-- Think of it as a way to perform custom callbacks issued from an entity event, similar to `System:onAdd`.
|
||||||
|
--
|
||||||
|
-- Complexity: O(1) per system
|
||||||
-- @tparam string name name of the callback
|
-- @tparam string name name of the callback
|
||||||
-- @tparam Entity e the entity to perform the callback on
|
-- @tparam Entity e the entity to perform the callback on
|
||||||
-- @param ... other arguments to pass to the callback
|
-- @param ... other arguments to pass to the callback
|
||||||
callback = :(name, e, ...)
|
callback = :(name, e, ...)
|
||||||
-- call callback
|
-- call callback
|
||||||
if @_previous[e] and @[name] then
|
if @_has[e] and @[name] then
|
||||||
@[name](@, e, e[@component], ...)
|
@[name](@, e, e[@component], ...)
|
||||||
end
|
end
|
||||||
-- callback on subsystems (if it wasn't removed during the callback)
|
-- callback on subsystems (if it wasn't removed during the callback)
|
||||||
if @_previous[e] then
|
if @_has[e] then
|
||||||
for _, ss in ipairs(@systems) do
|
for _, ss in ipairs(@systems) do
|
||||||
ss:callback(name, e, ...)
|
ss:callback(name, e, ...)
|
||||||
end
|
end
|
||||||
|
|
@ -695,6 +789,7 @@ let system_mt = {
|
||||||
-- `"capture"` would be for example used to prevent other systems from handling the event (for example to make sure an
|
-- `"capture"` would be for example used to prevent other systems from handling the event (for example to make sure an
|
||||||
-- input event is handled only once by a single system).
|
-- input event is handled only once by a single system).
|
||||||
--
|
--
|
||||||
|
-- Complexity: O(1) per system
|
||||||
-- @tparam string name name of the callback
|
-- @tparam string name name of the callback
|
||||||
-- @param ... other arguments to pass to the callback
|
-- @param ... other arguments to pass to the callback
|
||||||
emit = :(name, ...)
|
emit = :(name, ...)
|
||||||
|
|
@ -713,6 +808,7 @@ let system_mt = {
|
||||||
return status
|
return status
|
||||||
end,
|
end,
|
||||||
--- Remove all the entities and subsystems in this system.
|
--- Remove all the entities and subsystems in this system.
|
||||||
|
-- Complexity: O(entityCount) per system
|
||||||
destroy = :()
|
destroy = :()
|
||||||
recCallOnRemoveFromWorld(@world, { @ })
|
recCallOnRemoveFromWorld(@world, { @ })
|
||||||
recDestroySystems({ systems = { @ } })
|
recDestroySystems({ systems = { @ } })
|
||||||
|
|
@ -736,8 +832,7 @@ let recInstanciateSystems = (world, systems)
|
||||||
world = world,
|
world = world,
|
||||||
w = world,
|
w = world,
|
||||||
s = world.s,
|
s = world.s,
|
||||||
_first = { head },
|
_skiplist = skipNew()
|
||||||
_previous = {},
|
|
||||||
}, {
|
}, {
|
||||||
__index = :(k)
|
__index = :(k)
|
||||||
if s[k] ~= nil then
|
if s[k] ~= nil then
|
||||||
|
|
@ -747,6 +842,7 @@ let recInstanciateSystems = (world, systems)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
system._has = system._skiplist.previous[1]
|
||||||
-- create filter
|
-- create filter
|
||||||
if type(s.filter) == "string" then
|
if type(s.filter) == "string" then
|
||||||
system.filter = (_, e) return e[s.filter] ~= nil end
|
system.filter = (_, e) return e[s.filter] ~= nil end
|
||||||
|
|
@ -791,9 +887,9 @@ ecs = {
|
||||||
let world = setmetatable({
|
let world = setmetatable({
|
||||||
filter = ecs.all(),
|
filter = ecs.all(),
|
||||||
s = {},
|
s = {},
|
||||||
_first = { head },
|
_skiplist = skipNew(),
|
||||||
_previous = {}
|
|
||||||
}, { __index = system_mt })
|
}, { __index = system_mt })
|
||||||
|
world._has = world._skiplist.previous[1]
|
||||||
world.world = world
|
world.world = world
|
||||||
world.w = world
|
world.w = world
|
||||||
world.systems = recInstanciateSystems(world, {...})
|
world.systems = recInstanciateSystems(world, {...})
|
||||||
|
|
|
||||||
1051
ecs/ecs.lua
1051
ecs/ecs.lua
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue