microecs 0.2.4__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {microecs-0.2.4 → microecs-0.3.0}/PKG-INFO +6 -6
- {microecs-0.2.4 → microecs-0.3.0}/README.md +5 -5
- {microecs-0.2.4 → microecs-0.3.0}/microecs/world.py +22 -8
- {microecs-0.2.4 → microecs-0.3.0}/microecs.egg-info/PKG-INFO +6 -6
- {microecs-0.2.4 → microecs-0.3.0}/setup.py +1 -1
- {microecs-0.2.4 → microecs-0.3.0}/LICENSE.TXT +0 -0
- {microecs-0.2.4 → microecs-0.3.0}/microecs/__init__.py +0 -0
- {microecs-0.2.4 → microecs-0.3.0}/microecs/component.py +0 -0
- {microecs-0.2.4 → microecs-0.3.0}/microecs/pool.py +0 -0
- {microecs-0.2.4 → microecs-0.3.0}/microecs/query_result.py +0 -0
- {microecs-0.2.4 → microecs-0.3.0}/microecs/utils.py +0 -0
- {microecs-0.2.4 → microecs-0.3.0}/microecs.egg-info/SOURCES.txt +0 -0
- {microecs-0.2.4 → microecs-0.3.0}/microecs.egg-info/dependency_links.txt +0 -0
- {microecs-0.2.4 → microecs-0.3.0}/microecs.egg-info/requires.txt +0 -0
- {microecs-0.2.4 → microecs-0.3.0}/microecs.egg-info/top_level.txt +0 -0
- {microecs-0.2.4 → microecs-0.3.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: microecs
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: MicroECS: Minimal Entity Component System (ECS) in python and numpy
|
|
5
5
|
Home-page: https://gitlab.com/meehai/microecs
|
|
6
6
|
License: MIT
|
|
@@ -43,7 +43,7 @@ from microecs import World, Component
|
|
|
43
43
|
|
|
44
44
|
# components
|
|
45
45
|
class HasPosition(Component):
|
|
46
|
-
position: np.ndarray = field(metadata={"shape": (2, ), "dtype": "float32"})
|
|
46
|
+
position: np.ndarray = field(metadata={"shape": (2, ), "dtype": "float32"}) # 'shape' + 'dtype' are always required
|
|
47
47
|
class HasVelocity(Component):
|
|
48
48
|
velocity: np.ndarray = field(metadata={"shape": (2, ), "dtype": "float32"})
|
|
49
49
|
class HasColor(Component):
|
|
@@ -51,14 +51,14 @@ class HasColor(Component):
|
|
|
51
51
|
|
|
52
52
|
# systems: Note they are a convention!
|
|
53
53
|
class RenderSystem:
|
|
54
|
-
def __call__(self, world: World):
|
|
55
|
-
query_result = world.
|
|
54
|
+
def __call__(self, world: World):
|
|
55
|
+
query_result = world.query(HasPosition, HasColor, exclude=[]) # contiguous-like view of all entities matching
|
|
56
56
|
for position, color in zip(query_result.position, query_result.color): # draw each entity
|
|
57
57
|
DrawEntity(position, color)
|
|
58
58
|
|
|
59
59
|
class MotionSystem:
|
|
60
|
-
def __call__(self, world: World):
|
|
61
|
-
qr = world.
|
|
60
|
+
def __call__(self, world: World):
|
|
61
|
+
qr = world.query(HasPosition, HasVelocity) # 'exclude' is optional
|
|
62
62
|
qr.position[:] = qr.position + qr.velocity * DT # writes back to all the underlying pools using numpy's rules
|
|
63
63
|
# Alternative for per-pool update. Less ergonomic, but maybe faster in extreme cases as it avoids the _Field obj
|
|
64
64
|
for pool in qr.pool_list:
|
|
@@ -31,7 +31,7 @@ from microecs import World, Component
|
|
|
31
31
|
|
|
32
32
|
# components
|
|
33
33
|
class HasPosition(Component):
|
|
34
|
-
position: np.ndarray = field(metadata={"shape": (2, ), "dtype": "float32"})
|
|
34
|
+
position: np.ndarray = field(metadata={"shape": (2, ), "dtype": "float32"}) # 'shape' + 'dtype' are always required
|
|
35
35
|
class HasVelocity(Component):
|
|
36
36
|
velocity: np.ndarray = field(metadata={"shape": (2, ), "dtype": "float32"})
|
|
37
37
|
class HasColor(Component):
|
|
@@ -39,14 +39,14 @@ class HasColor(Component):
|
|
|
39
39
|
|
|
40
40
|
# systems: Note they are a convention!
|
|
41
41
|
class RenderSystem:
|
|
42
|
-
def __call__(self, world: World):
|
|
43
|
-
query_result = world.
|
|
42
|
+
def __call__(self, world: World):
|
|
43
|
+
query_result = world.query(HasPosition, HasColor, exclude=[]) # contiguous-like view of all entities matching
|
|
44
44
|
for position, color in zip(query_result.position, query_result.color): # draw each entity
|
|
45
45
|
DrawEntity(position, color)
|
|
46
46
|
|
|
47
47
|
class MotionSystem:
|
|
48
|
-
def __call__(self, world: World):
|
|
49
|
-
qr = world.
|
|
48
|
+
def __call__(self, world: World):
|
|
49
|
+
qr = world.query(HasPosition, HasVelocity) # 'exclude' is optional
|
|
50
50
|
qr.position[:] = qr.position + qr.velocity * DT # writes back to all the underlying pools using numpy's rules
|
|
51
51
|
# Alternative for per-pool update. Less ergonomic, but maybe faster in extreme cases as it avoids the _Field obj
|
|
52
52
|
for pool in qr.pool_list:
|
|
@@ -36,7 +36,7 @@ class World:
|
|
|
36
36
|
self._live_ids: set[EntityId] = set() # 'eager' mode ids so e.g. calling remove_entity twice before update fails
|
|
37
37
|
# command buffer management. {add/remove}_{entity/component} are lazy. Taken into account after update().
|
|
38
38
|
self._command_buffer: list[Callable] = []
|
|
39
|
-
self._cache: dict[PoolKey, QueryResult] = {}
|
|
39
|
+
self._cache: dict[tuple[PoolKey, PoolKey], QueryResult] = {} # include+exclude key
|
|
40
40
|
logger.debug(f"Created scene with components: {self.component_names}")
|
|
41
41
|
|
|
42
42
|
# public api
|
|
@@ -85,20 +85,34 @@ class World:
|
|
|
85
85
|
assert component in self.component_types, f"Component '{component}' not in {self.component_types}"
|
|
86
86
|
self._command_buffer.append(partial(self._do_remove_component, entity_id=entity_id, component=component))
|
|
87
87
|
|
|
88
|
-
def
|
|
89
|
-
"""
|
|
88
|
+
def query(self, *include: ComponentType, exclude: list[ComponentType] | None = None) -> QueryResult:
|
|
89
|
+
"""
|
|
90
|
+
Queries the world for entities that match the include set of components.
|
|
91
|
+
Syntax: `world.query(A, B, exclude=[C, D])` is, in logic form, a chain of 'ands': `A & B & ~C & ~D`.
|
|
92
|
+
Return: A `QueryResult` object with the entities that have all the requested components. Has `EntityIds` too.
|
|
93
|
+
"""
|
|
94
|
+
|
|
90
95
|
# Note: we can cache the queries. The only time it can get invalidated (via public API) is at update().
|
|
91
|
-
|
|
96
|
+
include_key = self._make_key(include)
|
|
97
|
+
exclude_key = self._make_key(exclude or [])
|
|
98
|
+
if (key := (include_key, exclude_key)) in self._cache:
|
|
92
99
|
return self._cache[key]
|
|
93
100
|
|
|
101
|
+
# archetype_key = (1 0 0 1 1) &
|
|
102
|
+
# key = (1 0 0 0 1)
|
|
103
|
+
# -> (1 0 0 0 1) OK
|
|
104
|
+
# but
|
|
105
|
+
# archetype_key = (1 0 0 1 1) &
|
|
106
|
+
# key = (1 0 1 0 0)
|
|
107
|
+
# -> (1 0 0 0 0) NOT OK
|
|
94
108
|
res = []
|
|
95
109
|
for archetype_key, archetype_pool in self.pools.items():
|
|
96
|
-
if (archetype_key &
|
|
110
|
+
if (archetype_key & include_key) == include_key and (archetype_key & exclude_key) == 0:
|
|
97
111
|
res.append(archetype_pool)
|
|
98
112
|
|
|
99
|
-
field_names
|
|
100
|
-
field_shapes = dict(zip(field_names, sum([self.component_to_shapes[c] for c in
|
|
101
|
-
field_dtypes = dict(zip(field_names, sum([self.component_to_dtypes[c] for c in
|
|
113
|
+
field_names = sum([self.component_to_field_names[c] for c in include], [])
|
|
114
|
+
field_shapes = dict(zip(field_names, sum([self.component_to_shapes[c] for c in include], [])))
|
|
115
|
+
field_dtypes = dict(zip(field_names, sum([self.component_to_dtypes[c] for c in include], [])))
|
|
102
116
|
entity_ids = np.array(sum((self._pool_ids[p] for p in res), []), dtype="int64")
|
|
103
117
|
|
|
104
118
|
self._cache[key] = QueryResult(res, field_shapes=field_shapes, field_dtypes=field_dtypes, entity_ids=entity_ids)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: microecs
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: MicroECS: Minimal Entity Component System (ECS) in python and numpy
|
|
5
5
|
Home-page: https://gitlab.com/meehai/microecs
|
|
6
6
|
License: MIT
|
|
@@ -43,7 +43,7 @@ from microecs import World, Component
|
|
|
43
43
|
|
|
44
44
|
# components
|
|
45
45
|
class HasPosition(Component):
|
|
46
|
-
position: np.ndarray = field(metadata={"shape": (2, ), "dtype": "float32"})
|
|
46
|
+
position: np.ndarray = field(metadata={"shape": (2, ), "dtype": "float32"}) # 'shape' + 'dtype' are always required
|
|
47
47
|
class HasVelocity(Component):
|
|
48
48
|
velocity: np.ndarray = field(metadata={"shape": (2, ), "dtype": "float32"})
|
|
49
49
|
class HasColor(Component):
|
|
@@ -51,14 +51,14 @@ class HasColor(Component):
|
|
|
51
51
|
|
|
52
52
|
# systems: Note they are a convention!
|
|
53
53
|
class RenderSystem:
|
|
54
|
-
def __call__(self, world: World):
|
|
55
|
-
query_result = world.
|
|
54
|
+
def __call__(self, world: World):
|
|
55
|
+
query_result = world.query(HasPosition, HasColor, exclude=[]) # contiguous-like view of all entities matching
|
|
56
56
|
for position, color in zip(query_result.position, query_result.color): # draw each entity
|
|
57
57
|
DrawEntity(position, color)
|
|
58
58
|
|
|
59
59
|
class MotionSystem:
|
|
60
|
-
def __call__(self, world: World):
|
|
61
|
-
qr = world.
|
|
60
|
+
def __call__(self, world: World):
|
|
61
|
+
qr = world.query(HasPosition, HasVelocity) # 'exclude' is optional
|
|
62
62
|
qr.position[:] = qr.position + qr.velocity * DT # writes back to all the underlying pools using numpy's rules
|
|
63
63
|
# Alternative for per-pool update. Less ergonomic, but maybe faster in extreme cases as it avoids the _Field obj
|
|
64
64
|
for pool in qr.pool_list:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|