Comments (12)
@baudren, I've not used Entitas myself, but I did watch the video and look over the documentation.
Unless I'm missing something, it seems like the main purpose of the Entitas Groups is query performance. In esper, there is both an _entities and _components database "under the hood" (thanks to @SpotlightKid). This means that querying for single Components doesn't require iterating over everything. Multiple Component queries, likewise, are also very efficient. My understanding is that the Entitas Groups mainly serve the same purpose, in which case there is probably no benefit to implimenting this concept in esper. Please correct me if I'm wrong on this.
Is the main purpose you have to simply add/remove components from an entity within a Processor (System)? Each Processor in esper has a reference to the World, so something like this following is already possible:
def process(self):
for ent, (vel, jmp) in self.world.get_components(Velocity, Jump):
if vel.y == 0:
vel.y = jmp.power
self.world.remove_component(ent, Jump)
Is this what you mean, or something else? Sorry if I'm not following, but I've not had any need for this type of pattern in my use of ECS in the past.
All that said, esper is considered feature complete, but it is still open to improvements at this point. Particularly, and performance improvements. Additional features will certainly be considered providing they do not impact performance negatively, do not require external dependencies, and fall within the scope of the project. A lightweight (optional) event system might be a possibility, but I'm still experimenting with other things at the moment.
from esper.
Thanks for the answer, @benmoran56. No, the usage is different from what you presented. The groups serve two purposes, as far as I can tell: one of performance (already taken care of by @SpotlightKid 's implementation), and one of reactivity.
Briefly, the reactivity allows you to trigger a part of a processor out of the responsibility chain of the processors. For instance, triggering some particle effects thanks to your particle processor when triggering an attack animation. If you would add some entities with a particle components, in a turn
As an example of reactivity, consider a simple battle system, where players can perform attacks which emit particles on hit, because graphics are nice, sometimes. You are within a turn of your system, where a player just attacked, so you created a bunch of particles. These should be treated by your ParticleProcessor
, but it sits at the end of the line of processors, and you are still within your TurnProcessor
because you can still perform some actions.
If the ParticleProcessor
can define a react
method to whenever a certain group of entities gets new members with InstantParticleComponent
, it can be processed at any time during your Processor chain, without either system knowing about each other.
An equivalent way of doing it would be to use a publisher/subscriber pattern, where the TurnProcessor
would fire an event, to be received and processed by the ParticleProcessor
. But using a group as a way of receiving these events (onEntityAdded
, onComponentRemoved
), you can obtain a well reactive interface without coupling the processors.
Let me know if it makes more sense, now :-)
from esper.
Oh I see what you mean now. I have to say I'm not very fond of this style of inter-Processor communication. I much prefer handling
It seems to me that any any possible react
methods would be better off as dedicated Processors
themselves. Tacking on a particle Emmiter
component that would later get picked up by a ParticleProcessor
is is how I've always done these types of things. If the ParticleProcessor
is already run, then it gets picked up on the next frame (which at 60fps would be only ~16ms delayed). I guess I'm not seeing the advantage of having instantaneous interaction with another Processor. In your example, are you talking about a World
that is only updated once per player turn? Whereas the next call to World.process
is waiting for user input?
The biggest hangup to implementing something like this would be that adding Groups
would likely have a negative impact on performance. The current component queries are as fast as we could make them, so additional group creation and updating would require some overhead.
A publisher/subscriber patter, simple event handler, would be possible to implement. It can be added as an optional thing, without any negative impact. I'm thinking something basic, such as this popular example here: http://www.valuedlessons.com/2008/04/events-in-python.html
from esper.
Yes, I am talking about a turn-based game, that waits for user input. But it can also bring value for other types of games.
To take the example introduced in entitas' unite talk, the score system has a standard update method, to display the score. But the changing of the score is done through watching the group of entities representing the bubbles. If one leaves this group, it add plus one to the score. If you don't have such a system, you would need the destroy-bubble system to somehow tag the entities that were deleted, for the score system to update it later, which introduces unnecessary components, at best.
So having a react method and a normal method would be a normal thing for a processor, whose goal is simply to regroup all code belonging to a certain responsibility.
About performance, that's probably true. For a turn-based game, it is not as crucial as it may be for you, but I understand the importance of making it as fast as possible.
And about just introducing a simple event handler, if it does not take advantage of the group watching, I am not sure that it would add enough functionality to warrant implementing it, but let me know what you think.
from esper.
Ok, all of your examples make a whole lot more sense now when put into that context.
Yes, performance is a top priority. Esper has to be usable in typical 60fps games, so maximizing the number of queries per ms is essential. I think it's pretty good at this, as it's much faster that other ES libraries out there. Still, I don't want to consider anything that would slow this down.
That said, I'm still open to this idea if it can be implemented optionally and without penalty if not used. Is this something you would like to try working on? I'd be happy to mock up ideas with you in another branch to see how it could look.
from esper.
Thanks for the offer. I will be implementing something that works for me on my code, but my top priority is not to keep dependencies minimal, but rather keep using libraries that make what I want so that I can actually write a game. So I am currently looking at pyzmq
with the tornado
event loop, which does not fit your definition of minimal, I think :)
You mention that it is much faster that other ES libraries - I know that there is no entitas port in python, but did you compare it to this framework? Or you meant compared to other python ES?
from esper.
I've not used it myself, but pyzmq looks like a nice library.
I've only compared esper to other Python ES libraries, such as ecs and ebs. From my benchmarks it's much faster. I'm not sure how it would stack up to Entitas, because I haven't used it and was unable to find any benchmarks with a quick Google. I am curious though. Esper is currently using Python dictionaries for the databases, which are quite fast as far as Python data types go. Other languages have the potential to be much faster with a more low level implementation, but I'm not sure how C# stacks up.
from esper.
I'm going to close this for now. If you want to revisit this in the future, please get in touch or open another issue to start a new conversation.
from esper.
I just had a quick throught on this today, and think there might be a simple solution to what you're trying to do. As it is, each Processor has access to the world. So, you could easily call any method in another Processor by doing something like the following:
for proc in self.world._processors:
if type(proc) is OtherProcessor:
proc.method()
Could you let me know if something like that would work, and would be useful? If so, I could easily add a small function to esper such as "self.world.get_processor(ProcessorType)", which could be used to easily call any processor's method: "self.world.get_processor(ProcessorType).method()"
I wouldn't use this for my own projects, but it would be just a few lines of code.
from esper.
Hey @benmoran56 , thanks for the idea. It indeed works, and is a small workaround that is useful for me. Would be cool if you implemented the method that you suggests, but it is perfectly usable as is.
Thanks again for giving a thought to the problem!
from esper.
Great, I'm glad that works for you. I went ahead and added a new World.get_processor method (which basically does the same as the above code). It's only a few lines, so no harm in adding it in if it can be useful. As I described above, you should now be able to do the following:
self.world.get_processor(ProcessorType).some_method()
from within your other Processor.
from esper.
Thanks!
from esper.
Related Issues (20)
- esper.current_world not usable as a module-level property HOT 2
- Initializing the world is not working HOT 1
- Avoid unnecessary multiple dict lookup inside `has_components` function
- Create an entity with a specific id HOT 4
- Try another ECS implementation - ecs_pattern library HOT 2
- Typing of world under the processor class HOT 3
- Testing esper HOT 4
- mypy `get_components` gives "object" type HOT 1
- Relationships HOT 8
- `World().create_entity()` does not create entity if no components are given HOT 1
- `remove_component()` method removes entity if no more components left HOT 3
- Add mypy to unit tests HOT 2
- Querying entities with denylist of components HOT 5
- API Design : Why so much OOP ? HOT 20
- "Quick start" in README is targeting old version HOT 3
- Seeking Guidance on Persisting and Loading Esper from a Database HOT 2
- Is esper Thread-Safe for Multi-threaded Environments? HOT 5
- Why roll up world into esper module? HOT 4
- Event handlers set within a function don't remain once the block scope exits. Why use weak references here? HOT 4
- Event System does not preserve event handlers upon switching context HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from esper.