Giter VIP home page Giter VIP logo

entityplus's People

Contributors

rainerdeyke avatar yelnats321 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

entityplus's Issues

No exception support

Although the library was designed with a no exception mode in mind, all the exceptions are non recoverable for the most part. Have to figure out how to support a no exception environment and also write tests for such an environment (as currently all the tests are based on an exception environment).

Deletion in for_each

Currently for_each is much faster than get_entities for traversing some set of components because it uses iterators under the hood. However, this means that removing components or creating or deleting entities will break it. It may be possible to modify the control_block_t to pass this information to the manager.

Destroying an entity or deleting its components make the most sense to add support for. Additionally, adding components to the current entity should already be supported, because it won't invalidate any iterators being used.

Adding support for creating entities withing for_each in my opinion has little usage and adding support for it would be hard and possibly limiting (how many entities should be created?)

Cmake

Remove visual studio specific files and add cmake support instead.

Transitioning to 2.0

I am currently in the process of rewriting EntityPlus! One of the issues is how to transition this repository to the new version. As this is a ground-up rewrite, I am not sure what the correct approach is. I also want to push to the repo when I have a working, mostly stable interface, and it will probably be a single commit that entirely changes the code. It may not be as fast as intended, but featureful enough to use and additional optimization will be added without altering the interface (ideally).

I am not sure if this is the best way to do this. If you have any suggestions on how to transition to this new rewritten version, please let me know!

If you have any features you are interested in, check out the other issues, especially #22 and see if they are covered there. If not, please let me know.

Const correctness

Currently entities employ reference semantics rather than value semantics, which is the less intuitive of the two. This means that passing in a const entity to a function does not guarantee that the entity won't be modified (since you can just copy it into a non const entity and modify it there).

There are other problems like sync() not being able to be called from a const entity and other little things that just feel off.

The options going forward are either to keep things as is or to split entity into two classes, a const entity and a non-const one, where the manager will return one or the other based on context. Probably the best approach to this but might feel unintuitive and hard to follow.

Storeable entities

Currently you are prohibited from storing entities. Rather, altering an entity will invalidate any previous reference to it. This restriction is made so that you can have caching on the entity side for has_(tag/component). Although the case can be made that the restriction is not worth it for anO(1) has_component, the main feature of tags is their low overhead and so removing O(1) has_tag is detrimental to that, making them obsolete in terms of performance.

It seems useful for some applications to be able to store entities rather than having to query them each time. Without event integration this is not very useful, but with it the want for storeable entities is increased.

There are two options that I see for this feature. Either modify entity so that it has an sync() function, which will sync it up to its actual values inside entity_manager. The issue here is that I am not sure how to deal with the case where a sync reveals that the entity has been deleted. I can add a bool indicating this state but it just adds more complications for state checking and the like. However this can be alleviated by sync() returning an indication of if the entity is valid post sync.

The other option is to have another type that we would call an entity_handle. This would be a barebones storeable type that underneath only holds a pointer to its manager and an ID. You can get an entity_handle from an entity via get_handle() and also convert an entity_handle to an entity via get_entity(). The same problem exists as with the syncing if the entity was deleted in the meantime. This would probably mean that get_entity() will have to return a pointer or an optional, but without library support I am very hesitant with the latter option.

On the one hand the second option conveys more information because we know that entity is temporary, entity_handle is not. On the other hand having additional types is annoying and complicates code needlessly. I am leaning more towards the first option, especially because the interface can be much nicer.

Customization point

Had an idea for a while to specify the underlying storage of a component (for example an unordered_map may be more performant for some data sets). This would be done by supplying a component_list with an unordered<T> as a template argument, which seems like a very clean way of doing it, but might be hard to implement.

On a similar vein, add a not option for get_entities and for_each, so one can ask for specific tags/components and also specify which tags/components not to have. So something like for_each<Position, Player, not<Inactive>> would fetch every player+position that does not have the Inactive tag. Not restricted to tags, could be components too.

Testing

Add unit testing (probably with catch since it's header only) as well as metaprogram testing (for all the metaprogramming stuff).

Grouping entities

As it stands for_each will iterate over the smallest component/tag provided, however this means that if the intersection of the provided components/tags is very small compared to the smallest component/tags, we are doing a lot of unnecessary work. It may be helpful for the user to provide groups of entities they plan on iterating over in the future to reduce the cost of this iteration.

As an example, say there are 50 entities, 20 of which have only tag A, 25 which have only tag B, and 5 which have both A and B. If we did for_each<A, B>() we would iterate over 20 entities (the ones with tag A) and then compare the bit signatures of the entities to match AB. Instead the user may tell us that they will use a grouping of AB regularly and so now we have a separate list of all entities with AB that we update with changes, and now we only have to iterate over the 5 AB entities.

The Future, C++17

This project is currently in a bit of a limbo state. The version for all intents and purposes should be at 2.0, however I am afraid there are certain features/changes that are not backwards compatible that I want to make before I release, but have not had the time to sit down and examine the code thoroughly to make the change. I am currently very busy with school work, and I don't see it slowing down for at least a month or two.

With all this being said, I want to wait until GCC/Clang/MSVC support C++17, or at least most of the nice features that are coming with that standard version. I think that when that happens, I will rewrite a lot of the code to use these features and support C++17 only. This would mean nicer error codes and a more simplifications in the code. However, this may reduce the userbase of the library.

To combat this standard version bump, I will rewrite the code alongside a 2.0 release. That way, any features (or breaking changes) that occur as a natural result of the rewrite can be also ported into the 2.0 release. The rewrite will force me into the state of mind that I need to be in to further extend and enhance the library, as I have not touched the code for some time now. In effect, there will be a 2.0 and 3.0 release simultaneously, with the only difference between the two being compiler/standard version.

I don't know if a standard version increase is a deal breaker for any users (or potential users), so I would like to hear your input too.

Error C2737: 'entityplus::meta::delay_v': 'constexpr' object must be initialized

Hello,

I'm trying to use your library:

cmake .
-- Building for: Visual Studio 14 2015
-- The C compiler identification is MSVC 19.0.23026.0
-- The CXX compiler identification is MSVC 19.0.23026.0
[...]

When building the solution from Visual Studio 2015, I get the following error message:

\entityplus\metafunctions.h(26): error C2737: 'entityplus::meta::delay_v': 'constexpr' object must be initialized

Thanks

Remove boost dependency

Remove or incorporate that part of boost with the library. Look for a different container library instead.

Exposing entity to the user

Currently there is no pretty way to take an entity as a parameter for the library user, since the fully qualified type is in detail. Either expose entity_t from entity_manager so the user can typedef it, or somehow inherit from a base class that the user can use it in parameters.

The issue with the first approach is that the user will need to expose typedef to any function that wants to take an entity, but this is no large burden as they can just write their own header #includeing the library and defining the typedef.

The second approach requires a whole new set (or an exposure) of the functions that operate on an entity inside entity_manager (the ones that take entity as a param) and will need to be kind of tricky about making sure the type information will match up. It will also introduce a new way to operate on entitys, which is something I'd like to avoid.

First approach easiest to implement for now, but may be changed later.

Licensing

Include licensing for the code (probably going to use boost).

Integrate events into entity_manager

Add events for adding/removing components/tags and creating/deleting an entity. This feature should be optional (by providing an event_manager to the entity_manager ctor or by specifying one via a function).

Lowercase file names

Can't change case of files without removing/readding them, will do that around v1.0

Examples

Add more examples! In the code so people can just expand on those and see what works and what doesn't, as well as lead by example with idiomatic code.

Will mesh well with cmake I think.

Future Plans

So I am currently in the process of a pretty large rewrite, meaning a lot of old code will be removed and replaced with (hopefully) better code.

The main key points I am trying to hit are:

  • const correctness
  • Customization
  • Efficiency
  • Faster speeds
  • C++17
  • Stronger versioning

I will also be maintaining the current feature set, just possibly in a slightly more cohesive way. Some functions may be renamed and the status quo may change a bit, but I aim to not reduce the feature set (and hopefully add to it in a meaningful way).

Fix non-dependent lambda triggering errors before eval_if

In add_component due to an MSVC bug the lambda is not generic and therefore all the types can be deduced when the function is called, before the lambda is invoked. This means that the pretty eval_if errors are swamped by other errors. One way to fix it is to change the entity manager's add_component to take a tuple of perfectly forwarded args instead, so that the generic lambda does not rely on the parameter pack and can once again be generic.

Versioning

Versioning has been a little lacking. There is only one release (v1.0) even though in reality there have been other releases (minor and patches, and also a couple breaking ones). Adding entity grouping will be technically a release of v.2.0.0 and then afterwards I will try to follow semantic versioning as best as I can. The git will still have commits that don't necessarily correlate to a version, but when I feel satisfied with a feature I will bump up the minor version, for bug fixes the patch version, and also for breaking changes the major. I don't foresee many breaking changes with the current feature set, but that may of course change.

Relationships between entities (inventory as an example)

Curious if you have any recommendations on a good way to handle references between entities, and how to store and access those relationships. In particular, we're looking at this in context of entity inventories.

Originally what we kind of hoped was going to work was a component along the lines of this:

struct Inventory {
    int capacity;
    std::vector<entity_t> items;
};

and then use a system and events to manage adding/removing items to a particular entity. This fell flat on its face because entity_t is defined after the components are.

One easy little change we found out we could make was to expose entityplus::detail::entity_id_t; and then using that in place of entity_t above in the vector. We kept going to see how it plays out, and what we ended up with was this helper function to convert the entityplus::detail::entity_id_t; into entity_t:

template <typename ...CompsAndTags>
inline std::unique_ptr<entity_t> find_entity_by_id(entity_manager_t* manager, entityplus::detail::entity_id_t id)
{
    for (entity_t entity : manager->get_entities<CompsAndTags...>())
    {
        if (entity.id == id)
        {
            return std::make_unique<entity_t>(entity);
        }
    }

    return NULL;
};

and it made for fairly enjoyable access anywhere you wanted to use the entities items

auto inventory = player.get_component<Components::Inventory>();
for (auto iter : inventory.items)
{
    auto item = find_entity_by_id(this->entity_manager, iter.second);

    // now we have a pointer to work with
    item->get_component<Components::Identity>();

    // off we go using the entity
}

We actually ran with that for a little bit and it's been alright, but it feels dirty given that we have to modify entityplus to expose that ID. We're lookin to switch this up, but the best next alternative we can think of is having the Inventory component know nothing about the items and go through our InventorySystem which could maintain a mapping of entities with inventories to the list of item entities, then have a function like std::vector<entity_t> InventorySystem::get_items_for_entity(entity_t) for accessing the items.

The reason we don't like that approach as much is because we lose the ability to fully describe our entity by simply looking at its components. With that approach our component tells us how many items might be in the inventory, but we need to communicate with a system to know what items those actually are.

So I guess what I'm asking is if you have any ideas that might allow for referencing entities from within a component. Or perhaps you know of an entirely different approach that maybe we didn't think of. I did notice you mentioned in #19 kind of this scenario we're talking about, but we're failing to understand how the tag approach would work when we have N entities that could have inventories (N tags?).

Appreciate any thoughts.

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.