LastOliveGames / becsy

A multithreaded Entity Component System (ECS) for TypeScript and JavaScript, inspired by ECSY and bitecs.
MIT License
202 stars 17 forks source link

Ability to run a `dispose` method on systems in a system group #16

Closed kishek closed 2 years ago

kishek commented 2 years ago

Hey there!

Firstly: Thank you so much for becsy! It's been awesome getting to work with it. I had a bit of an... interesting need which I wanted to ask about 😄

In my application, I've setup some system groups to correspond to different concepts:

...etc

Since I'm in a context where people can navigate away and back to the application, I need a way to dispose of all the event handlers which have been declared in the input system group, so they don't double up / we restart in a clean state.

From an API perspective, I believe this could look something like:

const group = System.group(MouseInputSystem, KeyboardInputSystem);

// Before the world is terminated, clear out all event handlers:
group.dispose();

The assumption here would be that all of the systems have an optional dispose() method attached to them which allows them to handle cleaning up any state / listeners they have attached. Not strongly attached to the idea of course - just how I'd see it fitting into my application neatly!

I'm currently reaching into group.__systems a bit naughtily to achieve this... 🙈

Keen for any solution which you believe would align best with becsy's vision. Also more than happy to contribute it back if you think the above approach makes sense!

Cheers!

pkaminski commented 2 years ago

Hey, thanks for the kind words -- I'd love to see what you're building if/when it's public!

IIUC you only need to remove all the handlers once, when you're cleaning up after your app. If that's so, how about adding a new finalize hook method to System that would be triggered when world.terminate is called, just like initialize is triggered on World.create? Lacking imagination, I originally thought that once created a world would exist for the lifetime of the page, but it turns out that people need to destroy and recreate the world somewhat regularly for various reasons so I think it makes sense to flesh out that side of the API.

On the other hand, if I'm wrong and you actually want to keep the world alive then perhaps the problem is better solved within the existing framework. I could imagine a singleton holding the current app state with systems reacting to it via change-queries, or perhaps making use of the system start/stop feature and building a new facility to let systems react to the state changes there.

What do you think?

kishek commented 2 years ago

Hey - no problems! Absolutely, would love to share a link with you once it's out in the wild!

The former is actually a perfect description. Our use case is that we want to clean up after our app and then come back to fresh / clean version of it 👍 A finalize hook would be fantastic!

If this hook is triggered on world.terminate() then that's perfect too, otherwise we'd need a way to call .finalize() on all the systems part of a group. But, based on what you've mentioned, I don't think we'd need that if it's all handled by becsy 😄

pkaminski commented 2 years ago

Implemented as discussed in 0.12.0 -- let me know if anything's broken!