Amélioration du système

This commit is contained in:
Tipragot 2023-10-22 22:19:43 +02:00
parent 9d80c111e9
commit ac19222744
2 changed files with 76 additions and 62 deletions

87
ecs.py
View file

@ -3,55 +3,66 @@ from typing import Iterator
class World: class World:
def __init__(self): def __init__(self):
self.to_apply: set[Entity] = set()
self.entities: set[Entity] = set() self.entities: set[Entity] = set()
self.mapping: dict[type, set[Entity]] = {} self.mapping: dict[type, set[Entity]] = {}
def create_entity(self, *components):
return Entity(self, *components)
def remove_entity(self, entity: 'Entity'):
entity._deleted = True
self.to_apply.add(entity)
def apply(self):
for entity in self.to_apply:
if entity._deleted:
self.entities.remove(entity)
for component_type in entity._components:
self.mapping[component_type].remove(entity)
else:
self.entities.add(entity)
for component_type, component in entity._to_apply:
if component is None:
del entity._components[component_type]
self.mapping[component_type].remove(entity)
else:
entity._components[component_type] = component
self.mapping.setdefault(component_type, set()).add(entity)
entity._to_apply.clear()
def query(self, *needed: type, without: tuple[type] = []) -> Iterator['Entity']: def query(self, *needed: type, without: tuple[type] = []) -> Iterator['Entity']:
if not needed: if not needed:
for entity in self.entities: for entity in self.entities:
for without_type in without: if all(without_type not in entity for without_type in without):
if without_type in entity:
break
else:
yield entity yield entity
else: else:
first_component = needed[0] for entity in self.mapping.get(needed[0], set()):
for entity in self.mapping.get(first_component, set()): if all(entity in self.mapping.get(component_type, set()) for component_type in needed[1:]) and \
for component_type in needed[1:]: all(without_type not in entity for without_type in without):
if entity not in self.mapping.get(component_type, set()): yield entity
break
else:
for without_type in without:
if without_type in entity:
break
else:
yield entity
class Entity: class Entity:
def __init__(self, world: World): def __init__(self, world: World, *components):
self.world = world self._world = world
self.world.entities.add(self) self._to_apply: list[tuple[type, object]] = [(type(component), component) for component in components]
self.components: dict[type, object] = {} self._components: dict[type, object] = {}
self._deleted = False
self._world.to_apply.add(self)
def __getitem__(self, component_type): def set(self, *components):
return self.components[component_type] for component in components:
self._to_apply.append((type(component), component))
self._world.to_apply.add(self)
def __setitem__(self, component_type, component): def remove(self, *component_types: type):
self.components[component_type] = component for component_type in component_types:
self.world.mapping.setdefault(component_type, set()).add(self) if component_type in self._components:
self._to_apply.append((component_type, None))
self._world.to_apply.add(self)
def __delitem__(self, component_type): def __getitem__(self, component_type: type) -> object:
del self.components[component_type] return self._components[component_type]
self.world.mapping[component_type].remove(self)
if len(self.world.mapping[component_type]) == 0:
del self.world.mapping[component_type]
def __contains__(self, component_type): def __contains__(self, component_type: type) -> bool:
return component_type in self.components return component_type in self._components
def __del__(self): # TODO: Réparer ça marche pas car il n'est pas détruit car il est toujours dans World
self.world.entities.remove(self)
for component_type in self.components:
self.world.mapping[component_type].remove(self)
if len(self.world.mapping[component_type]) == 0:
del self.world.mapping[component_type]

45
main.py
View file

@ -1,31 +1,20 @@
from ecs import World, Entity from ecs import World
# Création de composants pouvant être ajouté a des entitées # Création de composants pouvant être ajouté a des entitées
class Name(str): class Name(str): pass
pass class Age(int): pass
class Age(int):
pass
# Création d'un monde # Création d'un monde
world = World() world = World()
# Création d'une entité # Création de plusieurs entités
david = Entity(world) david = world.create_entity(Name("David"), Age(25))
david[Name] = Name("David") fred = world.create_entity(Name("Fred"), Age(30))
david[Age] = Age(25) paul_sans_age = world.create_entity(Name("Paul"))
age_tout_cour = world.create_entity(Age(14))
# Création d'une autre entité # On applique les moddifications
fred = Entity(world) world.apply()
fred[Name] = Name("Fred")
fred[Age] = Age(30)
# Création d'une autre entité
paul_sans_age = Entity(world)
paul_sans_age[Name] = Name("Paul")
# Création d'une autre entité
age_tout_cour = Entity(world)
age_tout_cour[Age] = Age(14)
print("Récupération de toutes les entitées qui ont un nom") print("Récupération de toutes les entitées qui ont un nom")
for entity in world.query(Name): for entity in world.query(Name):
@ -35,6 +24,12 @@ print("Récupération de toutes les entitées qui ont un age")
for entity in world.query(Age): for entity in world.query(Age):
print(entity[Age]) print(entity[Age])
# On change l'age de Fred
fred.set(Age(45))
# On applique les moddifications
world.apply()
print("Récupération de toutes les entités qui ont un nom et un age") print("Récupération de toutes les entités qui ont un nom et un age")
for entity in world.query(Name, Age): for entity in world.query(Name, Age):
print(entity[Name], entity[Age]) print(entity[Name], entity[Age])
@ -47,3 +42,11 @@ print("Récupération de toutes les entités qui ont un age mais pas de nom")
for entity in world.query(Age, without=(Name,)): for entity in world.query(Age, without=(Name,)):
print(entity[Age]) print(entity[Age])
print("Récupération de toutes les entités")
for entity in world.query():
if Name in entity:
print(entity[Name], end=" ")
if Age in entity:
print(entity[Age], end=" ")
print()