Skip to content
This repository has been archived by the owner on Feb 11, 2021. It is now read-only.

What about supporting singleton components #9

Closed
hongjiang-ye opened this issue May 16, 2018 · 10 comments
Closed

What about supporting singleton components #9

hongjiang-ye opened this issue May 16, 2018 · 10 comments

Comments

@hongjiang-ye
Copy link

I'm using your library to write a simple game. Your library is wonderful and it helps me a lot. But I hope that you could add APIs to support to create singleton components (came from GDC2017 'Overwatch Gameplay Architecture and Netcode', I'm sorry that I didn't find the video), which is like global variables that directly belong to the world instead of entities. I think they are helpful when you need components with camera position, window width and height, time, etc, that need to share between systems but does not logically belong to any entity.

I add some codes to complement a simple version, using a singleton entity to store the singleton components, but it's not gentle at all:

class World
{
public:
	Entity* singletons;

	template<typename T, typename... Args>
	void createSingletonComponent(Args&&... args) {
		this->singletons->assign<T>(args...);
	}

	template<typename T>
	ComponentHandle<T> getSingletonComponent() {
		return this->singletons->get<T>();
	}
};

I hope you could write these APIs in your way.

@redxdev
Copy link
Owner

redxdev commented May 16, 2018

I'm not sure I like the idea of having a singleton entity as part of this library. You can easily implement that without touching the library code by creating an entity and storing it wherever you store the World object.

@hongjiang-ye
Copy link
Author

I did that before and definitely it worked, but I had to access them as the other non-singleton components by methods like world->each<T>, which made the code untidy. If your library could provide the simple 'get' and 'create' APIs, I need not to implement it in by creating an entity only for singletons.

I'm only a student, and I'm not dare to change your codes at low level. I just told you what I need to see whether you would like to implement it.

@redxdev
Copy link
Owner

redxdev commented May 17, 2018

If you do it the way I suggested:

// These should be stored somewhere accessible
World* myWorld = World::createWorld();
Entity* mySingletonEntity = myWorld->create();
mySingletonEntity->assign<SomeComponent>();

You can access components on mySingletonEntity freely via Entity::get<T>():

ComponentHandle<SomeComponent> someComponent = mySingletonEntity->get<SomeComponent>();

// alternatively, use auto:
auto someComponent = mySingletonEntity->get<SomeComponent>();

Assuming you store mySingletonEntity in a place that's globally accessible (or at least accessible to anything that would otherwise be able to access the world), then you effectively have what you are asking for already.

@hongjiang-ye
Copy link
Author

Yeah I did that like:

Entity* singletons = world->create();
singletons->assign<CameraInfoSingletonComponent>();

In systems' tick:

virtual void tick(class World* world, float deltaTime) override {
    world->each<CameraInfoSingletonComponent>([&](Entity* ent, ComponentHandle<CameraInfoSingletonComponent> cameraCHandle) -> void {
        // do something with cameraCHandle...
    });
}

It works, just not neat. Actually there's only one CameraInfoSingletonComponent but it seems like there are many and I do something with all of them by world->each.

If I could do that like this, my team members could easily know that there's only one CameraInfoSingletonComponent.

virtual void tick(class World* world, float deltaTime) override {
    auto cameraCHandle = world->getSingletonComponent<CameraInfoSingletonComponent>();
    // do something with cameraCHandle...
}

@hongjiang-ye
Copy link
Author

You are right, it's not necessary, just few more lines. Feel free to close this issue.

@redxdev
Copy link
Owner

redxdev commented May 17, 2018

I do suggest considering other options. world->each is not fast for trying to look up a single object. I highly recommend storing your singleton entity somewhere (maybe pass it into the system's constructor and have a field on the system to store it?) and then avoiding world->each altogether.

Closed.

@redxdev redxdev closed this as completed May 17, 2018
@zmj1316
Copy link

zmj1316 commented Oct 3, 2018

What about a signature matching system? When a component is added or removed, use a container to trance the component, so the system can loop over the container instead of all the entities on each tick.
Should this be implemented by the framework or my own system?

@redxdev
Copy link
Owner

redxdev commented Oct 3, 2018

I'm not quite sure what you mean, can you give an example?

@zmj1316
Copy link

zmj1316 commented Oct 3, 2018

For example, when I try to loop over entities with SomeComponent1 and SomeComponent2 using this:

    world->each<SomeComponent1,SomeComponent2>(...)

and there are very few entities having these components, so I don't want to loop over all the entities to get the result due to low performance.
Instead I want to maintain a container to record the entities that matching the rules by listening on the component add/remove events. And use this

    for(auto pair : world->component_recorder_SomeComponent1_SomeComponent2)
        do some thing with pair ........

The question is, should this done by the framework itself or an extra system based on the framework?

@redxdev
Copy link
Owner

redxdev commented Oct 3, 2018

I suggest creating a new issue, what you are asking for doesn't have anything to do with singleton components. I'm going to lock this issue but feel free to open a new one with your idea.

As for the idea itself, yes world::each<> could be optimized to do a lookup on something like multimap<TypeIndex, Entity*> rather than iterating every single entity. There'd have to be some work done to notify the world whenever a component is created or destroyed, and there'd be an additional memory cost to the map.

Additionally, if you request multiple components then you'd still pay the cost of iterating entities (albeit a smaller set than the entire world) or you'd have to do a union of each set of entities with one of the requested components. I'm not convinced that in general this operation would be fast.

The last option would be to have some sort of structure you can register with the world that always contains a list of all entities with specified components - something like EntityContainer<MyComponent1, MyComponent2> could have an internal store that keeps an up-to-date list of all entities with MyComponent1 and MyComponent2. The upside is that it'd be fast for iteration and you'd only pay the costs of having such a system if you actually needed it. You could create containers for any common groups of components. The downside is that the world would now have to track a list of containers and there will be some overhead involved with creating and deleting components since each container would have to update its own internal list.

I think out of the options, I prefer the last one but I don't know if I'll get around to implementing it or not. Anyway, create a new issue if you're interested and hopefully I'll get to it or someone else will.

Repository owner locked as off-topic and limited conversation to collaborators Oct 3, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants