Closed UplinkPhobia closed 1 year ago
Why not use a Enemy
component ? You can call itertools.chain
to select multiple tags.
from itertools import chain
from esper import World
class Ally:
pass
class Enemy:
pass
class Position:
pass
world = World()
query = world.get_components
for entity, (_, pos) in chain(query(Ally, Position), query(Enemy, Position)):
pass
I would also suggest "tagging" Components, like Player
and Enemy
. This would likely be faster to query internally as well.
I'm new when it comes to ECS so I might be wrong, but this doesn't feel like the philosophy of ECS to define entities by what they are not, instead of by what they are.
On top of that, it also doesn't work so well when the filters are not so obviously "reversible". What is not a player isn't necessarily an enemy, and I wouldn't know what kind of tag to use if I want to define "something that is not a dog".
That is true. I don't think every entity would have the Enemy
Component - just actual enemies.
In my own projects, enemies typically already have some other type of Component that can be used to differentiate them in some way. An EnemyAI
or Target
Component, etc., but the idea is the same.
I also tend to find that if made genericly enough, Processors usually don't need to know if an entity is a Player or not during initial iteration. For example, a LifeProcessor
might handle removing HP from all Life Components, adding a Flash
or Blink
component, and handling cases where HP falls below 0. This last part is the only time where it needs to know if it's a player or not, since you would trigger a game over instead of showing an entity death animation.
life.hp -= damage.amount
if life.hp <= 0:
if self.world.has_component(ent, Player):
# game over
else:
self.world.add_component(ent, Blink())
# etc
It might help if you can describe what the Processor you're making does.
I am not making a Processor yet as I was trying to understand the library properly to have a proper structure of components and processors. Depending on the availability of a negative filter, I might need to adjust the components and I was trying to anticipate it, thus this issue.
But I understand your point of view and the logic behind it, so I'll just close the issue. If I find a situation where it seems impossible to solve without this feature, I might reopen it.
Thanks!
Hello,
Would it be possible to add a way to select entities based on components that they must not possess? If I want to select, for example, all entities except the player, I have to select them all, then make a specific case to check that the entity I'm looking at doesn't have a "player" component. It feels like an unnecessary step, since the
get_components
function is already doing the job of selecting entities.It would be nice to have something along the lines of
World.get_components(self, *component_types: _Type[_Any], denied_component_types: tuple = None)
to allow such a filter at query time.I do not know if this poses any design or performance issue, however, so I hope this issue isn't completely absurd.