Giter Club home page Giter Club logo

Comments (12)

benmoran56 avatar benmoran56 commented on September 15, 2024

@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.

baudren avatar baudren commented on September 15, 2024

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.

benmoran56 avatar benmoran56 commented on September 15, 2024

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.

baudren avatar baudren commented on September 15, 2024

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.

benmoran56 avatar benmoran56 commented on September 15, 2024

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.

baudren avatar baudren commented on September 15, 2024

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.

benmoran56 avatar benmoran56 commented on September 15, 2024

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.

benmoran56 avatar benmoran56 commented on September 15, 2024

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.

benmoran56 avatar benmoran56 commented on September 15, 2024

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.

baudren avatar baudren commented on September 15, 2024

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.

benmoran56 avatar benmoran56 commented on September 15, 2024

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.

baudren avatar baudren commented on September 15, 2024

Thanks!

from esper.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.