SFML community forums

General => SFML projects => Topic started by: therocode on January 21, 2014, 04:36:01 pm

Title: Feather Kit - A C++ Game Framework
Post by: therocode on January 21, 2014, 04:36:01 pm
Hello!

For the last year or so, I have been spending time developing a modular lightweight game framework for C++. I am posting this thread here as a first peek out into the public to hopefully get some user feedback and opinions on the library. :) It is a quite lengthy post, including a description of features. If you're uninterested in reading the features, skip to the "Live demos" part.

featherkit.therocode.net (http://featherkit.therocode.net)

I have developed this framework for my own use and for educational purposes, and my aspiration is that this library would turn into something useful for other people as well. :) During the past year I have added various components to the library at the same time as using it. It was even used by a few people in a private game jam LAN. So I feel that the library has reached a point where it would be beneficial to get more users into it, to let it mature more.

So, what is Feather Kit really?

As stated, it is a framework. It is not an engine. What I mean by that, is that it is not a tied-together system, a ready application to just stuff content into to make a game. Rather, it is a toolbox with various independent components that you can pick and select from to help you build your game. It contains no gluing code and it is up to every user to use the tools in the way he/she finds best. Following this philosophy, the amount of dependencies are kept to a bare minimum, to make as few assumptions about the user's system/platform as possible.

The general idea of these components is that they should deal with problems often encountered in game development and provide solutions for these in a clean, lightweight and object oriented way.

It is divided into independent modules. Here is a list of the current modules and some of their features.

Entity system
The entity system right now consists of a way to create and store entities along with an arbitrary number of attributes. Right now it only deals with entity data, not entity logic but some kind of component based logic system is planned. Entity templates can be created and loaded from JSON files.
Example on how to set and get attributes on an entity:
entity->setAttribute<glm::vec2>("velocity", glm::vec2(1.0f, 4.0f));
bool isScared = entity->getAttribute<bool>("isScared");
entity->addToAttribute<uint32_t>("health", 20);
 

Messaging
The messaging module contains a message bus, and a general message class. This lets various parts of your game communicate with each other without explicit dependencies. Built heavily on C++11 features such as variadic templates to provide a really clean messaging interface with almost no boilerplate code. Most dispatching logic is also handled compile time which makes for a really low runtime overhead. Read more here: http://blog.therocode.net/2013/09/messaging-using-variadic-templates/ (http://blog.therocode.net/2013/09/messaging-using-variadic-templates/)

Example on how to define a message:
struct EntityMoved_tag{};//                              id      position
using EntityMovedMessage = fea::Message<EntityMoved_tag, size_t, glm::vec2>;
 

Example on how to send a message:
messageBus.sendMessage(EntityMovedMessage(1337, glm::vec2(5.0f, 2.0f)));
 

Render2D
This module aims to be a complete tool to render 2D graphics for a game. It is build on raw OpenGL and in a sense it reinvents a lot of what SFML can do. I chose to write this part from scratch to be able to more easily take Feather Kit to more exotic platforms. Right now it contains sprite rendering with animated sprites, tile maps, text rendering, with an inheriting interface to add new drawables. It supports a camera and a viewport, blend modes and shaders. More features and some cleanup are planned.

Structure
A module dedicated to structuring the code base of your game. Contains a general application class which helps you take command line arguments and create a main loop. It also lets you compile to emscripten to run your game in the browser without having to tailor your code to work with the asynchronity of the web. There is also a game statemachine and a general tree class which can be used as a quadtree, octree or NTree.

User Interface
I wanted Feather Kit to not be strictly dependent on any sub-system. So this module is mostly about reinventing a window class and an input handler. It does not however implement it from the bottom up. Instead it uses a backend approach where it translates the window/input things from the underlying backend to a more general Feather Kit format. That way you can by changing about 4 lines of code make your game run on SFML instead of SDL or any other platform which has a backend implemented for it. Furthermore it also implements an action handler where you can bind raw input to actions, and store that configuration to file.

So that's all modules there are for now, but planned modules (that will be added Some Day™) include a resource manager, audio, 3D rendering and networking.

I have also made the effort to make Feather Kit work out of the box with Emscripten. Emscripten lets you compile C++ code into javascript for direct deployment on the web.

Live demos

Alright, congratulations if you read this far, haha. Here are a few examples of what you can create without that much effort with the help of Feather Kit. They are all built for the web using Emscripten and if you have a reasonably new browser they should work.

Interactive textures: http://featherkit.therocode.net/wip/ (http://featherkit.therocode.net/wip/) (steer with WSAD)
Tilemap, actions, animations and lights: http://pallkars.net/~zagabar/bladepit/ (http://pallkars.net/~zagabar/bladepit/) (steer with WSAD and click the mouse to fire)
Tilemap and animations: http://featherkit.therocode.net/tutorials/tilesanimationexample.html (http://featherkit.therocode.net/tutorials/tilesanimationexample.html) (press space to get past the first screen)

End section

That is pretty much it. I would be very happy to get some feedback so you are very welcome to test it out if you have time. There is documentation and tutorials (more will be written) on the website. If you need help getting started or have general feedback or feature requests, there is an official forum and an IRC channel. Everything can be found on the website.

Keep in mind that the library is still very new, and has not received user feedback or haven't been used that much so a few quirks and bugs could exists, but I'll do my best to fix them as soon as possible. I also aim to be open for criticism and take all suggestions open mindedly to make this library as good as possible.

Thanks for reading! :)
Title: Re: Feather Kit - A C++ Game Framework
Post by: Nexus on January 21, 2014, 05:10:48 pm
Your framework looks really interesting, and it's one of the few ones that actually uses modern C++ :)

With its entity, message and state systems, it also looks like a nice addition to my own library Thor (which has a similar philosophy, but is tailored more towards SFML extensions than general game programming). As far as I see it, SFML is only one of multiple rendering/windowing backends, right? Do you plan to provide an abstraction layer so that one can easily switch between SFML and SDL, for example?
Title: Re: Feather Kit - A C++ Game Framework
Post by: select_this on January 21, 2014, 05:33:45 pm
I really like what I've seen of the messaging system; I must admit I'm not a huge fan of the syntax of variadic templates (and templates in general, to be honest - I cringe every time I have to dive into Boost's source) but I like the syntactic sugar of the end result.
Title: Re: Feather Kit - A C++ Game Framework
Post by: therocode on January 21, 2014, 05:35:53 pm
Your framework looks really interesting, and it's one of the few ones that actually uses modern C++ :)

With its entity, message and state systems, it also looks like a nice addition to my own library Thor (which has a similar philosophy, but is tailored more towards SFML extensions than general game programming). As far as I see it, SFML is only one of multiple rendering/windowing backends, right? Do you plan to provide an abstraction layer so that one can easily switch between SFML and SDL, for example?

Thanks for your kind words! :)

I have checked out Thor and it indeed seems nice! I have been keeping my eyes open for opportunities to try it out but these days I have had my time dedicated elsewhere than making SFML based games hehe.

There are no rendering backends, rendering is pure OpenGL. But indeed SFML is only one of multiple window/input backends. Right now there are backends for SFML, SDL2 and SDL, and such an abstract layer is provided. You use fea::Event for instance which the input backend is responsible of generating.
Title: Re: Feather Kit - A C++ Game Framework
Post by: MorleyDev on January 21, 2014, 06:03:56 pm
Interesting, I was working with similar ideas awhile ago. It was workable but I was never happy enough with my solution to release it though. Will have to dig into your code more to see how you approached some parts.

For events most my woes came from how I used std::function instead of inheritance for the message receivers. My main issue was with handling removal of a receiver (since you can't compare), and in the end I settled on adding a receiver returned a movable RAII object that on final deconstruction would remove the handler from the dispatcher. A solution with problems, but workable.

I guess the main difference looking is the higher level stuff.

My entity-component system didn't have entities directly knowing their components, instead they only existed as a UUID EntityId stored in a centralised datastore that mapped that id to components. Then the interface was based around getting all entities with a specific subset of components and doing operations on the datastore to CRUD those entities.

I also opted not to use a stack or FSM system for game state, instead there were a set of discrete Controllers that responded to events and enable/disable themselves as needed.

But yeah, looking at this I like the basic design of it. The emscripten support is awesome, and I can appreciate the headaches that must of caused to get working.
Title: Re: Feather Kit - A C++ Game Framework
Post by: Lo-X on January 21, 2014, 06:11:57 pm
Woaw... This sounds amazing :o

Your framework is there just in time, I was about to implement the messaging system in a game but now that I've seen it, I'll wait a bit.

I'm a begginer with variadic templates and not sure what Nexus mean by modern C++, but I'm not an idiot and I understand how to use it. But... I'm not sure I understood well how your messaging system works.

What I think I understood is :


1) The programmer needs to define message-type-structures and give it with message "parameters" to the fea::Message class. The tag is needed to differenciate several messages that could have the same "parameter(s)". Some using (as typedef) are used to make the naming easier.

2) The programmer has to create a MessageReciever class that is templated to get a message of that template type/class. So if I have a
using EntityMovedMessage = fea::Message<EntityMoved_tag, unsigned int, sf::Vector2f>;
I can handle that kind of messages like
class TargetComponent : public MessageReceiver<EntityMovedMessage>
{
public:
     virtual void handleMessage(const EntityMovedMessage& mess) { ... }
};

But my question is : why MessageReceiver do need to inherit from a MessageReceiverBase in your example ?

3) [that's the part I'm not confident with] The lib code is able, at compile time, to "link" messages senders or messages to their recievers ? How is it done, I don't get it.

4) The programmer just has to send messages through the message bus and it delivered to interested reciever(s)
bus.sendMessage<EntityMovedMessage>(EntityMovedMessage(42, sf::Vector2f(32.5f, 12.f));
// My TargetComponent will recieve a message (handleMessage)

What's wrong/right/am I a complete noob ?
Title: Re: Feather Kit - A C++ Game Framework
Post by: therocode on January 21, 2014, 07:04:00 pm
I really like what I've seen of the messaging system; I must admit I'm not a huge fan of the syntax of variadic templates (and templates in general, to be honest - I cringe every time I have to dive into Boost's source) but I like the syntactic sugar of the end result.

Thanks!

I think template programming is fun and I often try to find solutions for things with them. But they can indeed turn messy but i try to make the result have a clean API.

Interesting, I was working with similar ideas awhile ago. It was workable but I was never happy enough with my solution to release it though. Will have to dig into your code more to see how you approached some parts.

...

Feel free to do so! :)

I guess my entity system works similarly to yours. The entities themselves are just an ID. The entity manager is what holds the data. However, for convenience, I added getter and setter functions to the entities themselves which actually peeks into the entity manager.

And sure, Emscripten took a bit of a headache to get working, but actually not too much. It is a really cool piece of technology and I really like it.

Woaw... This sounds amazing :o

...

What's wrong/right/am I a complete noob ?

Thank you! :)

And you understood it fine, that is indeed how it works/how you use it. Except you forgot a detail. When the target component inherits from MessageReceiver<EntityMovedMessage>, it is just capable of receiving messages. It also needs to subscribe to them, to actually get them:
bus.addSubscriber<EntityMovedMessage>(targetComponent); //let target component subscribe
 

Optionally, what I usually do is putting it in the constructor of targetComponent:

TargetComponent::TargetComponent(fea::MessageBus& bus) : mBus(bus)
{
      bus.addSubscriber<EntityMovedMessage>(*this);
}
 

And remember to use the removeSubscriber whenever the object is being destroyed, or the application will crash when the message bus tries to send it a message!

How this works behind the scene is that it uses type_info to resolve the message types into a numerical index during compile time. The subscribers are then stored in a multimap with such type id being the key and all subscribers being the value. Whenever a message is sent, the type is resolved, then the subscribers are extracted from the multimap and the message is sent to the virtual handleMessage function, which will be sent to the right overload using polymorphism. I hope that makes sense.
Title: Re: Feather Kit - A C++ Game Framework
Post by: Grimshaw on January 21, 2014, 07:32:38 pm
Hey zagabar! Awesome work, your library is looking really neat!

I was mesmerized to see it running on emscripten! So much I really want to do the same myself! Would you be able to elaborate a little more on what it took to make it happen?

Thanks :)
Title: Re: Feather Kit - A C++ Game Framework
Post by: Lo-X on January 21, 2014, 07:36:02 pm
That's all clear, I indeed missed a part !

Thanks a lot =)
Title: Re: Feather Kit - A C++ Game Framework
Post by: Lo-X on January 21, 2014, 09:13:41 pm
I double post to notify you of an error I got while compiling the lib with CMake :

include/featherkit/rendering/textsurface.h:5:39: fatal error: featherkit/rendering/text.h: No such file or directory
#include <featherkit/rendering/text.h>

And indeed there is no file with such a name in the rendering folder. I managed to compile the lib by commenting this line. Was just to warn you.
Title: Re: Feather Kit - A C++ Game Framework
Post by: eigenbom on January 22, 2014, 04:27:42 am
Great stuff! :)
Title: Re: Feather Kit - A C++ Game Framework
Post by: therocode on January 22, 2014, 06:53:33 am
Great stuff! :)

Thank you. :)

I double post to notify you of an error I got while compiling the lib with CMake :

include/featherkit/rendering/textsurface.h:5:39: fatal error: featherkit/rendering/text.h: No such file or directory
#include <featherkit/rendering/text.h>

And indeed there is no file with such a name in the rendering folder. I managed to compile the lib by commenting this line. Was just to warn you.


Ah, dang there is always something you miss no matter how much you try haha. Thanks for pointing it out! I have fixed it now. It was a leftover from before and that file is indeed removed.

Hey zagabar! Awesome work, your library is looking really neat!

I was mesmerized to see it running on emscripten! So much I really want to do the same myself! Would you be able to elaborate a little more on what it took to make it happen?

Thanks :)

Thanks! Cool that you liked it running on emscripten. I was actually unsure on if people would care about that feature or not haha.

Well, some of the work with emscripten was to learn how to build things with it, especially with external dependencies. Which I think is easier these days because they seem to have updated their wiki to be easier to understand. Then I had to rewrite my rendering engine a bit to make it OpenGL ES2 compliant since that's what is supported by emscripten, and that took quite a lot of time, since I had to test a lot and work out the error messages in the browser etc. And finally, since the web is asynchronous designed, you can't have a blocking main loop since that would freeze the browser. So I added some emscripten specific code in the Application class to make it emulate a main loop using a timed approach. It isn't that complicated since emscripten has functions for it.

That is pretty much what I had to do. Not _too_ much, but it is nice to have it done hehe. :)
Title: Re: Feather Kit - A C++ Game Framework
Post by: Grimshaw on January 22, 2014, 04:37:47 pm
Cool! Since my code already supports all those requirements it shouldn't be too hard I believe!

I will try and achieve the same! Did SFML's windowing system work out of the box? I heard only SDL was working with emscripten..
Title: Re: Feather Kit - A C++ Game Framework
Post by: Lee R on January 22, 2014, 06:31:38 pm
I'm not sure if you realise it, but, there are serious constraints placed on the set of types which can be used as attributes. This is due to the use of memcpy in both of the 'EntityBackend' implementations. In short, any attribute type must be trivially copyable. I strongly suggest that you either rewrite the code to avoid memcpy, or at the very least statically assert that the attribute type being registered/queried is in fact trivially copyable. It isn't difficult to come up with worst case scenarios here (i.e. this is a real and serious issue).

The implementation of 'AlignedEntityBackend' imposes the further constraint that attribute objects cannot contain pointers to other attribute objects because the pointer value will become invalid if the array containing the pointee is resized.

It should also be documented that conversions are unsafe. That is, the type of the object being retrieved/set must *exactly* match the registered type to avoid undefined behaviour. About the best you could do here is a runtime type check (because of the use of strings to identify attributes).

I have some idea to avoid/mitigate the above situations if you get stumped.
Title: Re: Feather Kit - A C++ Game Framework
Post by: therocode on January 23, 2014, 04:00:00 am
Cool! Since my code already supports all those requirements it shouldn't be too hard I believe!

I will try and achieve the same! Did SFML's windowing system work out of the box? I heard only SDL was working with emscripten..

Nice!

Yeah, I don't think SFML works out of the box. But I think it could be easier now when SFML has Android/IOS stuff going on because I think that means that SFML would support open GL ES2. But I am not exactly sure. And you would still have to make a bridge from the browser events to the SFML events I think (but don't take my word for it). SDL is indeed supported out of the box by emscripten so that is the easiest way to go.

I'm not sure if you realise it, but, there are serious constraints placed on the set of types which can be used as attributes. This is due to the use of memcpy in both of the 'EntityBackend' implementations. In short, any attribute type must be trivially copyable. I strongly suggest that you either rewrite the code to avoid memcpy, or at the very least statically assert that the attribute type being registered/queried is in fact trivially copyable. It isn't difficult to come up with worst case scenarios here (i.e. this is a real and serious issue).

The implementation of 'AlignedEntityBackend' imposes the further constraint that attribute objects cannot contain pointers to other attribute objects because the pointer value will become invalid if the array containing the pointee is resized.

It should also be documented that conversions are unsafe. That is, the type of the object being retrieved/set must *exactly* match the registered type to avoid undefined behaviour. About the best you could do here is a runtime type check (because of the use of strings to identify attributes).

I have some idea to avoid/mitigate the above situations if you get stumped.

Ah, thanks for the feedback. :)

I am aware of those constraints although I had kind of forgot about them, so it is a good reminder. The entity system (and actually the whole AlignedEntityBackend class) is the first thing of the framework that I started to write and I have levelled up a lot as a programmer since then so the ugliest code in the framework will doubtlessly be there. I have even been wanting to rewrite big parts of the entity system but haven't gotten around to it yet.

But yes, that is an issue that should be addressed indeed. The reason why I used byte-pet-byte copying is due to the AlignedEntityBackend which stores all entity attributes in the end as char arrays, and I did that to achieve general storage of any data type. But of course this is limiting as you say. There is even the fact that if you try to store an object which has a non-default destructor, the stored object will be destructed whenever the copied instance goes out of scope.

I look over the old code and see if I can come up with a nice way to fix it. Feel free to post your ideas on how to do this the best way possible. :) Depending on things I actually might remove the aligned entity backend if I can't figure out a way to do what I wanted to do with it in a good way. Is is quite a special case component. Although the idea is nice.
Title: Re: Feather Kit - A C++ Game Framework
Post by: Tank on January 23, 2014, 09:20:20 am
Nice to see some public stuff about FeatherKit. Keep it going. :)
Title: Re: Feather Kit - A C++ Game Framework
Post by: Lee R on January 28, 2014, 12:18:46 am
Quote from: therocode
I look over the old code and see if I can come up with a nice way to fix it. Feel free to post your ideas on how to do this the best way possible. :) Depending on things I actually might remove the aligned entity backend if I can't figure out a way to do what I wanted to do with it in a good way. Is is quite a special case component. Although the idea is nice.

I personally think that it would be a good idea for you to go learn about type erasure, then redesign the whole system.

Also, it would make things a lot simpler if the "EntityBackend" type wasn't runtime configurable. That way, the full static type of both the attributes and their respective containers could be known, potentially allowing the registration/query code to be as straight forward as:

std::map<..., std::shared_ptr<void>> m_attributeArrays;
// ...
template<typename T>
void EntityManager::registerAttribute(const std::string& name)
{
    // 'attributeArrays' is a map containing type erased AttributeArray objects.
    m_attributeArrays[name] = std::make_shared<AttributeArray<T>>(name, this);
}

template<typename T>
T& EntityManager::getAttribute(const std::string& name, const EntityId id)
{
    // cast back to known static type.
    void* vp = m_attributeArrays[[name].get();
    return static_cast<AttributeArray<T>*>(vp)->get(id);
}
 

If you do go for a full redesign, you could consider looking up attributes by type rather than strings. That would allow the attribute arrays to be accessed by an integer index into a vector (which is hella faster than string keys into a map). Like so:

inline unsigned nextTypeID()
{
    static unsigned id = 0;
    return id++;
}

template<typename T>
unsigned TypeID()
{
    static const unsigned id = nextID();
    return id;
}

// ...
std::vector<std::shared_ptr<void>> m_attributeArrays;
// ...

template<typename T>
void EntityManager::registerAttribute(const std::string& name)
{
    // 'attributeArrays' is a vector containing type erased AttributeArray objects.
    const auto index = TypeID<T>();
    if (index >= m_attributeArrays.size()) {
        auto ptr = std::make_shared<AttributeArray<T>>(name, this);
        m_attributeArrays.resize(1 + index);
        m_attributeArrays[index] = ptr;
    }
}

template<typename T>
T& EntityManager::getAttribute(const EntityId id)
{
    // cast back to known static type.
    void* vp = m_attributeArrays[TypeID<T>()].get();
    return static_cast<AttributeArray<T>*>(vp)->get(id);
}
 

You could also keep the old string mapping around as a 'slow path' to ease serialization and such.

Because types will be registered at the granularity of attributes (versus, say, components), there would have to be some mechanism in place to allow multiple attributes of the same type to be registered independently. It could be as simple as matching the actual attribute type with a tag type:

template<typename T, typename Tag>
struct Attribute
{
    using value_type = T;
    using tag_type = Tag;
};

template<typename T>
typename T::value_type EntityManager::getAttribute(const EntityId id);

struct HealthTag {};
using Health = Attribute<int, HealthTag>;

//...

int health = entManager.getAttribute<Health>(id);
 

Hopefully, all that was more helpful than it was confusing.  ;)
Title: Re: Feather Kit - A C++ Game Framework
Post by: therocode on January 28, 2014, 11:17:49 am
Nice to see some public stuff about FeatherKit. Keep it going. :)

Thanks, mate! :)

I personally think that it would be a good idea for you to go learn about type erasure, then redesign the whole system.

...

Hopefully, all that was more helpful than it was confusing.  ;)

Nope, not confusing at all, but quite inspirational!

I read about type erasure and learnt a few new things about it which is nice, thanks. I've never known the term although I am familliar with many of the practices it leads to, but reading about it as a concept is nice. :)

Having a type based system instead of string based system indeed has its benefits with the compile time processing and type safety, but on the other hand it has its own drawbacks. For once, now when the system uses strings, it is trivial to read entity templates from JSON files where the strings are directly corresponding to an actual attribute. That is useful since content designers can define things purely in data files without fiddling with, and recompiling the code. This can of course be achieved with programmers creating a predefined lookup-table where strings correspond to a type, but it is less neat so it is a trade-off.

Another approach I am investigating to solve the current issue of not bieng able to store types that has custom value semantics is to store the attributes in std::shared_ptr<void> which will be able to delete them properly. Then a simple cast with a template getter function can retrieve the original value. This would get rid of the current issues.

I am not sure yet which approach I'll use, but feel free to come with more suggestions/ideas about it. :) And thanks for taking your time.

Oh btw, there is a built in way of getting an index representing a unique type instead of using a static incrementing counter:
std::type_index index = std::type_index(typeid(AttributeType));
 

Cheers!
Title: Re: Feather Kit - A C++ Game Framework
Post by: Lee R on January 28, 2014, 07:47:20 pm
Quote from: therocode
Having a type based system instead of string based system indeed has its benefits with the compile time processing and type safety, but on the other hand it has its own drawbacks. For once, now when the system uses strings, it is trivial to read entity templates from JSON files where the strings are directly corresponding to an actual attribute. That is useful since content designers can define things purely in data files without fiddling with, and recompiling the code. This can of course be achieved with programmers creating a predefined lookup-table where strings correspond to a type, but it is less neat so it is a trade-off. [...]

I'm not sure I see the problem. In my last post, I did say that the string mapping could be kept around to ease serialization and such. I mean, the string data must be mapped to real C++ types at some point, else it's nothing but meaningless junk taking up space.

Does this address the use case you have in mind (the concept, rather than exact implementation)?
using LoadFunc = std::function<
    void(EntityID, std::string)
>;
std::map<std::string, LoadFunc> m_loaders;

// ...

template<typename T>
void EntityManager::registerAttribute(const std::string& name)
{
    // ...same as before...

    m_loaders[name] = [this](EntityID id, std::string data) {
        std::stringstream ss(std::move(data));
        ss >> getAttribute<T>(id);
    };
}

void EntityManager::loadAttribute(EntityID id, std::string name, std::string data)
{
    m_loaders[name](id, std::move(data));
}
 

EDIT: Okay, I think I understand your use case better now. You actively want the ability to load meaningless junk. That is, user defined attributes for which the compiled executable has no specialized code. Then, while waiting for a programmer to implement their logic, a level designer could get on with placing objects containing said attributes. If that's the case, then a fully typed entity system could still work. You'd simply define a 'EditorAttribute' which would suck up all unknown attributes. The editor system would look for object with said EditorAttribute and display it's contents as if they were first class attributes. If, on the other hand, the idea is to have the logic be implemented in script files, while the above idea would still work (e.g. through a ScriptVars arrtibute), you would probably be better off back with the old string based system (depending on the amount of data that gets stuffed into the ScriptVars attributes).

Quote
Another approach I am investigating to solve the current issue of not bieng able to store types that has custom value semantics is to store the attributes in std::shared_ptr<void> which will be able to delete them properly. Then a simple cast with a template getter function can retrieve the original value. This would get rid of the current issues.

This is essentially what I suggested in my last post. It's pretty much the same idea, whether it's individual attribute objects that are type erased or entire arrays of them.

Quote
Oh btw, there is a built in way of getting an index representing a unique type instead of using a static incrementing counter:
std::type_index index = std::type_index(typeid(AttributeType));
 

The code I presented for mapping a type to an integer has the additional property that for the first type queried, the returned value will be 0; for the second type queried it will be 1, and so on. This makes it suitable for use in as the index into a vector. Resizing a vector to accommodate the returned value of the code you presented could (and likely would) result in gobs of memory being wasted. This besides the fact that I don't think the std::type_index class defines a conversion to integer.
Title: Re: Feather Kit - A C++ Game Framework
Post by: therocode on January 29, 2014, 09:36:04 am
Okay, I think I understand your use case better now. You actively want the ability to load meaningless junk. That is, user defined attributes for which the compiled executable has no specialized code. Then, while waiting for a programmer to implement their logic, a level designer could get on with placing objects containing said attributes. If that's the case, then a fully typed entity system could still work. You'd simply define a 'EditorAttribute' which would suck up all unknown attributes. The editor system would look for object with said EditorAttribute and display it's contents as if they were first class attributes. If, on the other hand, the idea is to have the logic be implemented in script files, while the above idea would still work (e.g. through a ScriptVars arrtibute), you would probably be better off back with the old string based system (depending on the amount of data that gets stuffed into the ScriptVars attributes).

[...]

Yes, that is right. Such use cases is what I have in mind. I am not entiry sure what you mean with a 'EditorAttribute' which would suck up all unknown attributes, but I have an idea on an implementation that I kind of like. It would work like this:

The entity manager has such a function:
eManager.registerAttribute<int>("Health");

After this line, "Health" is a valid attribute and the manager remembers the type of it.

You then create entities like so:
eManager.registerAttribute<int>("Health");
eManager.registerAttribute<float>("Weight");

WeakEntityPtr entity1 = eManager.createEntity({"Health", "Weight"});
WeakEntityPtr entity2 = eManager.createEntity({"Health"});
WeakEntityPtr entity3 = eManager.createEntity({"Weight"});

The parameter is an std::vector<std::string>. Exceptions are thrown if the attributes are not valid. WeakentityPtr is a typedef for std::weak_ptr<Entity>

Entity attributes are then accessed like so:
eManager.setAttribute<int>(entityId, "Health", 45);
int health = eManager.getAttribute<int>(entityId, "Health");

And in a similar sense to what you described before, the manager remembers what type the attributes where registered with, which makes it easy to add type safety. Behind the scenes, it stores the attributes in a copy-safe type erased way such as std::shared_ptr<void> or whatever is suitable. That way it can handle any type and it also has type safety. As a shorthand you can also call .setAttribute<int>("Health", 45) directry on an entity.


However, this is quite tedious to use since you have to provide an std::vector of std::string every time you create an entity. So there will be a utility class (which was previously functionality in the EntityManager, causing messiness) called EntityFactory or something along those lines. The entity factory takes the entity manager as a reference upon creation and provides an API to register entity templates with default value setters. These templates can be loaded from JSON files. So you can have this JSON file:
{
    "player":
    {
        "position":"900.0f,100.0f", "velocity":"", "acceleration":"", "maxvelocity":"5.5f", "maxacceleration":"1.0f", "hitbox":"24.0f,24.0f", "collisiontype":"solid", "collisiongroup":"player"
    }
}

This file defines one entity template but can define more as well. Every template has a name ("player") and a bunch of associated attributes. The attributes are pairs of their name and default value when the template is instantiated.

To use the attributes, they have to be registered in the entity manager using the registerAttribute<>() function, and to put a default value, a default-setting function must be registered using entityFactory.registerDefaultSetter(). If a default setter is not needed, the default value can be left empty in the file. Example on how to register a default-setter for a glm::vec2 for position:

entityFactory.registerDefaultSetter("position",
[] (const std::string attribute&, const std::vector<std::string>& arguments, fea::WeakEntityPtr entity) {
entity.lock()->setAttribute<glm::vec2>(attribute, glm::vec2(std::stof(arguments[0]), std::stof(arguments[1])));
});

Sorry for the messy lambda code but I wanted to keep it short in the forum post. :D

Then to finally instantiate an entity template, you would do something like:
WeakEntityPtr entity = entityFactory.instantiate("player");

I might also look into making the system template based so that it is optional if you want strings as identifiers for the attributes or if you'd prefer a numerical type or anything else. That way you could use enums if you care about strings being low performance to compare.

That's it.

To me this API seems quite straight-forward and it seems reasonably type-safe and exception safe. But that's easy to say without another persons perspective haha. So are there in your opinion any serious drawbacks or limitations with a system like that? Thanks again for your feedback and ideas. :)

edit: Forgot to reply to this bit:

The code I presented for mapping a type to an integer has the additional property that for the first type queried, the returned value will be 0; for the second type queried it will be 1, and so on. This makes it suitable for use in as the index into a vector. Resizing a vector to accommodate the returned value of the code you presented could (and likely would) result in gobs of memory being wasted. This besides the fact that I don't think the std::type_index class defines a conversion to integer.

True, useful if it should be stored indexed in a vector. I guess I just personally prefer to use an unordered_map for such storage so that I don't need to worry about managing indices.
Title: Re: Feather Kit - A C++ Game Framework
Post by: Rexou on January 29, 2014, 01:15:49 pm
Hi there, i've been reading this topic since its creation but haven't been able to give your framework a real try like i wished i could but i wanted to say that what i saw in the sources seems to be very useful, well organized and cool. Well done !

I've already tried the messaging part and looked at the examples for the basics but I can't wait to see tutorials on your entity system / Emscripten / other advanced parts.

I wanted to ask how would you do a class listening to several events/messages using your API ? I have created a working example but it's obviously not fun to maintain if we're listening for more than a dozen of messages.

Here's the code of my sample http://codepad.org/anuJSWAQ (http://codepad.org/anuJSWAQ)
Basically just a macro helping me to create the different structures & typedefs for the Message tag/data in Event.hpp and a HeroPet class containing 2 vectors<std::function>> filled in the ctor (one for each Message type). In the handleMessages functions i iterate over the two callback_vectors to call the associated functions and that's pretty much it.

I am not in a hurry so take your time it's ok if i have to wait for the documentation to be completed hehe.

Keep it up  ;) !
Title: Re: Feather Kit - A C++ Game Framework
Post by: therocode on January 29, 2014, 02:28:46 pm
Hi there, i've been reading this topic since its creation but haven't been able to give your framework a real try like i wished i could but i wanted to say that what i saw in the sources seems to be very useful, well organized and cool. Well done !

...

Ah, thanks a lot. :)

Interesting to see a macro to define message types, that is clever. Maybe I could incorporate such a message creation macro in the actual framework haha.

Regarding your sample, if it is done like that it would be not fun to maintain indeed. But it seems to me like you are mixing two techniques. Messaging and callbacks. Whenever I have used the messaging system, I don't use it to call callbacks, but I let the final object that is meant to react to the message actually receive the message. So in your example, I would skip the callbacks alltogether and just have the prints in the handleMessage functions.

Here is an example on how I have used the messagebus to subscribe to many messages (sorry if the code is messy, it was written during a game jam haha):
Header file: http://pallkars.net/gitweb/?p=tobbegame.git;a=blob;f=src/playerhandler.h;h=53f5ca63889daaee2f5bd5065e4de2c7a2085dd6;hb=HEAD (http://pallkars.net/gitweb/?p=tobbegame.git;a=blob;f=src/playerhandler.h;h=53f5ca63889daaee2f5bd5065e4de2c7a2085dd6;hb=HEAD)
Source file: http://pallkars.net/gitweb/?p=tobbegame.git;a=blob;f=src/playerhandler.cpp;h=ae91e9abbf660911442a4a939488855d8c79d12b;hb=HEAD (http://pallkars.net/gitweb/?p=tobbegame.git;a=blob;f=src/playerhandler.cpp;h=ae91e9abbf660911442a4a939488855d8c79d12b;hb=HEAD)

But yeah, I'll definitely consider providing some macros for the message typing you have to do. It seems really potentially handy!

Not sure if that answers your question, feel free to ask more if you need more clarifications. :)
Title: Re: Feather Kit - A C++ Game Framework
Post by: Rexou on January 29, 2014, 03:48:24 pm
Interesting to see a macro to define message types, that is clever. Maybe I could incorporate such a message creation macro in the actual framework haha.

Actually I didn't even know we could create empty std::tuples before that macro (it would be impossible to use this macro for messages without parameters) I just wanted to test my memory about preprocessor tricks
but im glad if i can contribute !

Regarding your sample, if it is done like that it would be not fun to maintain indeed. But it seems to me like you are mixing two techniques. Messaging and callbacks. Whenever I have used the messaging system, I don't use it to call callbacks, but I let the final object that is meant to react to the message actually receive the message. So in your example, I would skip the callbacks all together and just have the prints in the handleMessage functions.

Yep, it seems to be the legit way to handle messages and after reflexion about this, it could probably be done by splitting these handleMessages functions into subfunctions, you're right there is no need for callbacks there !

Here is an example on how I have used the messagebus to subscribe to many messages (sorry if the code is messy, it was written during a game jam haha):

Ok so it's also registration through inheritance and one function per message type, I don't think we can do better if we want to keep compile-time dispatching.

But yeah, I'll definitely consider providing some macros for the message typing you have to do. It seems really potentially handy!

Not sure if that answers your question, feel free to ask more if you need more clarifications. :)

No more questions for now, I'll keep reading the sources during my free time, thanks for the answers !
Title: Re: Feather Kit - A C++ Game Framework
Post by: therocode on February 03, 2014, 11:16:46 am

Actually I didn't even know we could create empty std::tuples before that macro (it would be impossible to use this macro for messages without parameters) I just wanted to test my memory about preprocessor tricks
but im glad if i can contribute !

Ah, the macro worked fine for me without parameters. I have added such a macro to the Message class now. Thanks for the tip. :)

Ok so it's also registration through inheritance and one function per message type, I don't think we can do better if we want to keep compile-time dispatching.

No more questions for now, I'll keep reading the sources during my free time, thanks for the answers !

Yep that is true.

Alright, no problems!
Title: Re: Feather Kit - A C++ Game Framework
Post by: Lee R on February 10, 2014, 04:26:55 am
Okay so this is a bit of a late reply, but hey :P

Quote from: therocode
Quote from: Lee R
Okay, I think I understand your use case better now. You actively want the ability to load meaningless junk. That is, user defined attributes for which the compiled executable has no specialized code. Then, while waiting for a programmer to implement their logic, a level designer could get on with placing objects containing said attributes. If that's the case, then a fully typed entity system could still work. You'd simply define a 'EditorAttribute' which would suck up all unknown attributes. The editor system would look for object with said EditorAttribute and display it's contents as if they were first class attributes. If, on the other hand, the idea is to have the logic be implemented in script files, while the above idea would still work (e.g. through a ScriptVars arrtibute), you would probably be better off back with the old string based system (depending on the amount of data that gets stuffed into the ScriptVars attributes).

[...]

Yes, that is right. Such use cases is what I have in mind. I am not entiry sure what you mean with a 'EditorAttribute' which would suck up all unknown attributes [...]

It's seems like the use case you have in mind is actually quite a bit simpler than that. You just want the ability to load values for known attributes from a JSON file. That's trivial to achieve even with a fully type based system and it takes no more effort than for the new system you've described (i.e. no need for an 'EditorAttribute' or the like). Because this:

Quote from: therocode
The entity manager has such a function:
eManager.registerAttribute<int>("Health");

Provides the entity manager with both the static type of the attribute, and its string identifier. This is exactly the same information that a type based system would need in order for it to satisfy the use case. The code in my earlier post shows what that could look like:
http://en.sfml-dev.org/forums/index.php?topic=14193.msg100008#msg100008

Quote from: therocode
You then create entities like so:
eManager.registerAttribute<int>("Health");
eManager.registerAttribute<float>("Weight");

WeakEntityPtr entity1 = eManager.createEntity({"Health", "Weight"});
WeakEntityPtr entity2 = eManager.createEntity({"Health"});
WeakEntityPtr entity3 = eManager.createEntity({"Weight"});

The parameter is an std::vector<std::string>. [...]

Perhaps std::set<std::string> would makes more sense here?

Quote from: therocode
Example on how to register a default-setter for a glm::vec2 for position:

entityFactory.registerDefaultSetter("position",
[] (const std::string attribute&, const std::vector<std::string>& arguments, fea::WeakEntityPtr entity) {
entity.lock()->setAttribute<glm::vec2>(attribute, glm::vec2(std::stof(arguments[0]), std::stof(arguments[1])));
});

This could just be a matter of taste, but I feel like it would become quite tedious having to provide the 'default-setter' function for the same type, whenever that type is registered in the entity factory as an attribute (e.g. both position and velocity being vec2, and having to provide same setter function for both, individually). That being in addition to having to register both with the entity manager. It would be nice if, for example, the 'glm::vec2' type is registered along with its 'default-setter', not as an attribute, but as a primitive which can then be mapped to a name to form a new attribute.

I realise that it's probably not entirely obvious what I mean, so I went ahead and wrote a reference implementation to demonstrate the idea (which you're free to ignore ;)):

http://codepad.org/kBtU0puv

As an example of usage:

int main()
{
    fea::EntityManager manager;
    fea::EntityFactory producer(manager);

    producer.addPrimitive("vec2", [](const fea::Params& params) {
        return glm::vec2{ std::stof(params[0]), std::stof(params[1]) };
    });

    producer.map("position", "vec2");
    producer.map("velocity", "vec2");

    fea::Template moveable = {
        { "position", { "0.0, 0.0" } },
        { "velocity", { "0.0, 0.0" } }
    };

    producer.addTemplate("moveable", moveable);
    auto entity = producer.instantiate("moveable").lock();

    glm::vec2 position = entity.getAttribute<glm::vec2>("position");
    glm::vec2 velocity = entity.getAttribute<glm::vec2>("velocity");

    return 0;
}
 

There's a few things you might find interesting about this:

- Note that the user no longer explicitly registers anything with the entity manager itself. The entity factory handles all that under the covers (i.e. there is no registration code missing here, this is a complete example).

- The 'default-setter' function has been reduced to a simple parser; it doesn't concern itself with entities or managers or even attributes. It simply parses the arguments and returns an object of the appropriate type (which the entity factory will automatically deduce).

- Entity templates are parsed as soon as they're added to the system and stored as what I call 'proto entities'. This saves the system from having to re-parse (as in your current system) the strings of a template every time one is instantiated. The point here is that one could add sophisticated error handling to the parser function (previously 'default-setter') and not have to worry about any performance overhead since it will only ever been invoked once per template, rather than once per instantiation.

- This system satisfies the use case quoted at the top of this post; One could create entirely new attributes inside JSON files (in addition to simply being able to provide the values of known attributes).
- The code requires no modification to your existing EntityManager, except that it assumes the 'createEntity' function accepts an std::set<std::string>.
Title: Re: Feather Kit - A C++ Game Framework
Post by: Lolilolight on February 10, 2014, 07:46:59 pm
O_O

I was just wondering about how could I store entities with any kind of attributes. (because it's often game specific)

This sounds like to be interesting!

I'll probably use that in the next version of my framework.

But I've already implemented this system for my state system.
Title: Re: Feather Kit - A C++ Game Framework
Post by: therocode on February 11, 2014, 08:00:33 am
Long post

Hello again!

Thanks a lot for your post! It makes very much sense and I agree that this is a good approach to the EntityFactory class. :)

I like the idea of registering primitives and their setters rather than types. I guess I hadn't really thought about doing that but it makes more sense and removes quite a bit of overhead from the usage which is good.

Also, deducting primitive type from the return type of the lambda is very elegant hehe.

Another hilight I like is reducing the default setter to purely a parser. That makes it easier to understand and follows the principle of single responsibility better and overall seems like a more clean design!

Am I allowed to assimilate your example code with minor changes? In that case, do you wish to be credited in comments at the top of the file?

If not, then I'll code something similar up myself probably.

Thanks a lot for your suggestions, it is appreciated!

O_O

I was just wondering about how could I store entities with any kind of attributes. (because it's often game specific)

In my system I use std::shared_ptr<void>.
Title: Re: Feather Kit - A C++ Game Framework
Post by: Lolilolight on February 11, 2014, 11:51:57 am
I like the idea by using a template to store one of more attributes for the entities. (It avoid to have a to use too much inheritance, in the case of the game have a lot of different entities. (weapons, caracters rôles, skills objects, etc...)

But I don't see where is the utility to use a template to move the entities. (for exemple)

Combinate the inheritance (to store the common entities attributes) and the templates (to store specific attributes)  shouldn't it better ?

I really like combinates many techniques in a framework and taking advantages of each techniques. (And I think the most sotisticated frameworks should work like that)

If someone see an utility to use a template to do transformations on entities can he explain me because I don't very understand.
Title: Re: Feather Kit - A C++ Game Framework
Post by: Lee R on February 11, 2014, 05:03:38 pm
Quote from: therocode
Am I allowed to assimilate your example code with minor changes? In that case, do you wish to be credited in comments at the top of the file?

Sure. You may do whatever you like with it. I don't require any credit.

Quote from: Lolilolight
But I don't see where is the utility to use a template to move the entities. (for exemple)

It was just an example to show the process. Perhaps I should have used names like 'foo' and 'bar'. Although having said that, you have picked up on something:

Quote from: Lolilolight
Combinate the inheritance (to store the common entities attributes) and the templates (to store specific attributes)  shouldn't it better ?

I did originally implement a mechanism for the templates to be combined (i.e. inherit from one another), hence the name 'moveable' in the example. I removed that mechanism for a number of reasons, but left the example as-is. However, combining language level inheritance with an entity system is a big mistake. That is exactly what they're designed to avoid.
Title: Re: Feather Kit - A C++ Game Framework
Post by: therocode on February 13, 2014, 06:12:40 am
Sure. You may do whatever you like with it. I don't require any credit.

Thanks!

I have now assimilated the code and it works fine. I also added an overload of the addPrimitive function which lets you add data types without providing a parser function like so:

factory.addDataType<float>("float");

In such a case, the type is provided using the template argument.

Thanks again! :) It will be interesting to use this in production code.
Title: Re: Feather Kit - A C++ Game Framework
Post by: select_this on February 24, 2014, 01:35:31 pm
May I ask what your intention was with the following snippet?:

Message(typename std::enable_if<sizeof...(DataTypes) >= 1>) {}

My understanding of template metaprogramming is a little sketchy, so I might be barking up the wrong tree here, but to me it seems like it's a constructor with an argument of type std::enable_if<cond> (struct), which would be pretty much impossible to call and wouldn't do anything even if it was called.
Title: Re: Feather Kit - A C++ Game Framework
Post by: therocode on February 24, 2014, 02:47:10 pm
May I ask what your intention was with the following snippet?:

Message(typename std::enable_if<sizeof...(DataTypes) >= 1>) {}

My understanding of template metaprogramming is a little sketchy, so I might be barking up the wrong tree here, but to me it seems like it's a constructor with an argument of type std::enable_if<cond> (struct), which would be pretty much impossible to call and wouldn't do anything even if it was called.

Yeah, the enable_if function can be quite confusing. I don't have the best understanding of it myself since I haven't done super much meta programming but I'll explain the best I can and I'll start with the purpose.

Okay, if we start with this:
template<class tag, typename... DataTypes>
    struct Message
    {
        Message() {}
        Message(DataTypes... data) : mData(data...) { }
        Message(const std::tuple<DataTypes...>& data) : mData(data) { }
        std::tuple<DataTypes...> mData;
    };
 

Then we have 3 ways of constructing a message. For example, with the instantiation Message<int, int> we can do:

1. Construct without parameters, making a default message: Message<tag_type, int, int>()
2. Construct with parameters that get directly packed in the tuple:   Message<tag_type, int, int>(34, 45)
3. Construct with another tuple: Message<tag_type, int, int>(otherMessage.mData)

This is good, but it has an unexpected flaw. If you want a message carrying no data, say you would have a ShutDownMessage = Message<tag_type>, then since the variadic parameter DataTypes would not contain anything, both the first and second constructor would resolve to Message<tag_type>() and compilation would fail with a redefinition error.

In other words, it is impossible to have a zero-parameter message. So to solve this problem, we want to have constructor number 1 if and only if DataTypes contain one or more types. That is what the enable_if function lets us do.

How this works is actually by kind of exploiting the behaviour of the compiler using a principle called SFINAE (substitution failure is not an error) which works on the principle that if the compiler cannot find a fitting template instantiation, then it silently ignore that or something along those lines. And that behaviour is wrapped in the enable_if template so that you can enable/disable overloads depending on compile time conditions.

If that sounded messy it is probably because I don't fully understand it myself. I read about it for real just the other day and I still haven't grasped it fully, haha. :D But hopefully it gave some insight anyway.
Title: Re: Feather Kit - A C++ Game Framework
Post by: select_this on February 24, 2014, 03:01:38 pm
Ah okay, that makes sense, thanks. I must admit I've never seen enable_if used in that way before, only when used in conjunction with a template function:

template <typename T = std::tuple<DATATYPES...>>
Message(typename std::enable_if<std::tuple_size<T>() >= 1, dummy>::type = dummy{}) {
}

Your version seems considerably more concise than the syntax I'm familiar with.
Title: Re: Feather Kit - A C++ Game Framework
Post by: Nexus on February 24, 2014, 08:50:41 pm
May I ask what your intention was with the following snippet?:
Message(typename std::enable_if<sizeof...(DataTypes) >= 1>) {}
My understanding of template metaprogramming is a little sketchy, so I might be barking up the wrong tree here, but to me it seems like it's a constructor with an argument of type std::enable_if<cond> (struct), which would be pretty much impossible to call and wouldn't do anything even if it was called.
The objection is justified; SFINAE won't work like this. There are several problems with that declaration:
Usually, enable_if is employed in one of the following ways:
// Parameter: Use default parameter of type void*
template <typename T>
R function(typename std::enable_if<cond>::type* = nullptr);

// Return value: Use 2nd template paramater of enable_if
template <typename T>
typename std::enable_if<cond, R>::type function();

// Template default parameter
template <typename T, typename Unused = typename std::enable_if<cond>::type>
R function();

Title: Re: Feather Kit - A C++ Game Framework
Post by: therocode on February 25, 2014, 06:21:25 am
Ah, yeah you're actually right, it doesn't work! :D

I assumed that it worked since the compiler didn't complain, but now when I tried using the empty constructor, it doesn't work indeed. That's what you get when you lack proper understanding I suppose.

\
Usually, enable_if is employed in one of the following ways:
// Parameter: Use default parameter of type void*
template <typename T>
R function(typename std::enable_if<cond>::type* = nullptr);

// Return value: Use 2nd template paramater of enable_if
template <typename T>
typename std::enable_if<cond, R>::type function();

// Template default parameter
template <typename T, typename Unused = typename std::enable_if<cond>::type>
R function();

I tried working out how to apply one of those ways of using it into my case but I can't figure out how to do it with the variadic parameters. If you know how to do it in this case, care to give me some directions?

Also, thanks to you for finding this issue.
Title: Re: Feather Kit - A C++ Game Framework
Post by: Nexus on February 25, 2014, 09:26:42 am
std::tuple already has a default constructor, so one constructor with a variadic argument list is enough. And I would not copy the arguments, but rather use perfect forwarding and move semantics.
#include <tuple>
#include <utility>

template <typename Tag, typename... DataTypes>
struct Message
{
    // Perfect forwarding
    // This is also the default constructor!
    template <typename... Args>
    Message(Args&&... args)
    : mData(std::forward<Args>(args)...)
    {
    }

    // Pass-by-value and move
    Message(std::tuple<DataTypes...> data)
    : mData(std::move(data))
    {
    }

    std::tuple<DataTypes...> mData;
};
Title: Re: Feather Kit - A C++ Game Framework
Post by: select_this on February 25, 2014, 10:21:00 am
This would appear to invalidate the following syntax though:

typedef Message<struct MessageTag, double, double, double> TMessage;

TMessage message1(double(1), double(40), double(42));

TMessage message2(message1);  // Compilation error
TMessage message3 = message2; // Compilation error

I guess it's not a big issue if you never wanted to copy messages around by themselves.
Title: Re: Feather Kit - A C++ Game Framework
Post by: Nexus on February 25, 2014, 12:04:04 pm
Strange, I'd expect the Big Five to have priority in overload resolution. You can try to declare them with = default, but I don't think it makes a difference.

Otherwise, I would create a class template specialization for the case with zero variadic arguments. That would not only simplify code, but also save memory, since you wouldn't have the tuple member.

By the way: You can use double literals such as 1. or 1.0 instead of double(1). And it's not necessary to write struct MessageTag, MessageTag is enough.
Title: Re: Feather Kit - A C++ Game Framework
Post by: therocode on February 25, 2014, 12:22:33 pm
Ah yeah, a specialisation would be a better solution indeed.

Thanks again, both of you!
Title: Re: Feather Kit - A C++ Game Framework
Post by: select_this on February 25, 2014, 12:55:01 pm
By the way: You can use double literals such as 1. or 1.0 instead of double(1). And it's not necessary to write struct MessageTag, MessageTag is enough.

I'm not normally so verbose, I'll admit this is test code adapted from something else that I just tweaked.  :)

However, removing the struct bit gives a not declared in this scope error (as I hadn't defined or declared the type prior to this snippet).

Edit: Turns out the copying issue was simply solved with user defined copy constructors:

template <typename TAG, typename... DATATYPES>
class Message {

    public:

        typedef std::tuple<DATATYPES...> TDataTypes;

        Message (Message& message) : m_data(message.m_data) {
        }

        Message (const Message& message) : m_data(message.m_data) {
        }

        template <typename... ARGS>
        Message (ARGS&&... args) : m_data(std::forward<ARGS>(args)...) {
        }

        Message (TDataTypes data) : m_data(std::move(data)) {
        }

        TDataTypes m_data;
};
Title: Re: Feather Kit - A C++ Game Framework
Post by: therocode on February 26, 2014, 04:59:32 pm
Alright, time for a little update post!

Since the initial post, I have rewritten large parts of the entity system which was needed since it was the oldest part of the framework and I have learnt a lot since then, and as kind people in this thread pointed out, the system had serious flaws.

These flaws have now been fixed and the API is cleaner and much safer to use, and it has also gotten more features. The system has three main parts: The EntityManager, EntityFactory and the EntityComponent.
   The EntityManager stores all entities, and with it you can register attributes that the entities hold, and also create and delete entities.
   The EntityFactory is a convenience class where you can register entity templates. These are predefined sets of attributes. They can also have default values and inherit from each other. This is shown in the example code below.
   The final part consists of an abstract base class EntityComponent which is inherited to create entity logic. How this works is also shown in the example below.

With these parts working together, Feather Kit provides a full system for handling both entity data and logic.

Here follows a code snippet with a full example on how the entity system is used in practice. I hope it is not too long, and if anything is unclear and you want to know more, just ask here or over in the Feather Kit forums. :)

#include <featherkit/entitysystem.h>
#include <featherkit/util/entity/basictypeadder.h>
#include <featherkit/util/entity/glmtypeadder.h>
#include <featherkit/messaging.h>
#include <iostream>
#include <glm/glm.hpp>

FEA_DECLARE_MESSAGE(EntityDamagedMessage, fea::EntityId, int32_t);          //message to sent when an entity is damaged
FEA_DECLARE_MESSAGE(EntityDiedMessage, fea::EntityId);                      //message is sent when an entity has died
FEA_DECLARE_MESSAGE(EntityMovedMessage, fea::EntityId, const glm::vec2&);   //message is sent when an entity has moved
FEA_DECLARE_MESSAGE(FrameMessage);                                          //message is sent once every frame  

//the physics component simulates physics on physics entities. if entities have fallen further than 300 units, they start taking 5 damage every frame
class PhysicsComponent : public fea::EntityComponent,
    public FrameMessageReceiver
{
    public:
        PhysicsComponent(fea::MessageBus& bus) : mBus(bus)
        {
            //subscribe to frame messages to be able to simulate one physics step every frame
            mBus.addSubscriber<FrameMessage>(*this);
        }
        ~PhysicsComponent()
        {
            mBus.removeSubscriber<FrameMessage>(*this);
        }
        bool keepEntity(fea::WeakEntityPtr e) const override
        {
            fea::EntityPtr entity = e.lock();

            //only simulate on physics entities
            return entity->hasAttribute("position") &&
                entity->hasAttribute("velocity") &&
                entity->hasAttribute("acceleration");
        }
        void handleMessage(const FrameMessage& message) override
        {
            (void)message; //supress warning

            for(auto entityIterator : mEntities)
            {
                fea::EntityPtr entity = entityIterator.second.lock();

                //dumb physics simulation
                entity->addToAttribute("velocity", entity->getAttribute<glm::vec2>("acceleration"));
                entity->addToAttribute("position", entity->getAttribute<glm::vec2>("velocity"));
                const glm::vec2& position = entity->getAttribute<glm::vec2>("position");

                //notify that an entity has moved
                mBus.send(EntityMovedMessage(entity->getId(), position));

                //apply damage if further down than 300
                if(position.y > 300.0f)
                {
                    mBus.send(EntityDamagedMessage(entity->getId(), 5));
                }
            }
        }
    private:
        fea::MessageBus& mBus;
};

//the health component lets entities with health be able to take damage and die
class HealthComponent : public fea::EntityComponent,
    public EntityDamagedMessageReceiver
{
    public:
        HealthComponent(fea::MessageBus& bus) : mBus(bus)
        {
            //subscribe to know when entities are damaged
            bus.addSubscriber<EntityDamagedMessage>(*this);
        }

        ~HealthComponent()
        {
            mBus.removeSubscriber<EntityDamagedMessage>(*this);
        }

        bool keepEntity(fea::WeakEntityPtr e) const override
        {
            fea::EntityPtr entity = e.lock();

            //only deal with entities that have health and can be dead/alive
            return entity->hasAttribute("health") &&
                   entity->hasAttribute("alive");
        }

        //subtract health according to damage, and kill entity if health goes to zero or below
        void handleMessage(const EntityDamagedMessage& message)
        {
            fea::EntityId id;
            int32_t damageAmount;
            std::tie(id, damageAmount) = message.mData;

            if(mEntities.find(id) != mEntities.end())
            {
                fea::EntityPtr entity = mEntities.at(id).lock();

                int32_t health = entity->getAttribute<int32_t>("health");
                health -= damageAmount;

                entity->setAttribute("health", health);

                //if dead, notify about the death of the entity
                if(health <= 0)
                {
                    entity->setAttribute("alive", false);            
                    mBus.send(EntityDiedMessage(entity->getId()));
                }
            }
        }
        private:
            fea::MessageBus& mBus;
};

//simple class to print what is happening in the world
class Logger
    : public EntityDiedMessageReceiver,
      public EntityMovedMessageReceiver
{
    public:
        Logger(fea::MessageBus& bus) : mBus(bus)
        {
            //subscribe to the messages we are interested to print information about
            bus.addSubscriber<EntityDiedMessage>(*this);
            bus.addSubscriber<EntityMovedMessage>(*this);
        }

        ~Logger()
        {
            mBus.removeSubscriber<EntityDiedMessage>(*this);
            mBus.removeSubscriber<EntityMovedMessage>(*this);
        }

        //print when an entity has died
        void handleMessage(const EntityDiedMessage& message) override
        {
            fea::EntityId id = std::get<0>(message.mData);
            std::cout << "Entity id " << id << " died!\n";
        };

        //print when an entity has moved
        void handleMessage(const EntityMovedMessage& message) override
        {
            fea::EntityId id = std::get<0>(message.mData);
            const glm::vec2& position = std::get<1>(message.mData);
            std::cout << "Entity id " << id << " moved to " << position.x << " " << position.y << "\n";
        };
    private:
        fea::MessageBus& mBus;
};

int main()
{
    fea::MessageBus bus;
    Logger logger(bus);
    fea::EntityManager manager;
    fea::EntityFactory factory(manager);

    //use utility functions to register common data types like bool, int32 and vec2
    fea::util::addBasicDataTypes(factory);
    fea::util::addGlmDataTypes(factory);

    //register all attributes that our entities will use
    factory.registerAttribute("position", "vec2");
    factory.registerAttribute("velocity", "vec2");
    factory.registerAttribute("acceleration", "vec2");
    factory.registerAttribute("health", "int32");
    factory.registerAttribute("alive", "bool");
    factory.registerAttribute("hardness", "int32");

    //setup the physics entity template. physics simulation will be done on these
    fea::EntityTemplate physicsEntityTemplate;
    physicsEntityTemplate.mAttributes = {{"position"     , "0.0f, 0.0f" },
                                         {"velocity"     , "0.0f, 0.0f" },
                                         {"acceleration" , "0.0f, 0.8f"}};  //default gravity

    factory.addTemplate("physics_entity", physicsEntityTemplate);

    //setup the living entity template. these entities will be able to take damage and die
    fea::EntityTemplate livingEntityTemplate;
    livingEntityTemplate.mAttributes = {{"health" , "20"},     //default to 20 HP
                                        {"alive"  , "true"}};  //default to be alive

    factory.addTemplate("living_entity", livingEntityTemplate);

    //the rock template will inherit the physics entity but will also have a hardness attribute
    fea::EntityTemplate rockTemplate;
    rockTemplate.mInherits = {"physics_entity"};
    rockTemplate.mAttributes = {{"hardness" , "5"}};

    factory.addTemplate("rock", rockTemplate);

    //the enemy template will inherit both the physics entity and the living entity. so it will both be physics simulated and able to take damage
    fea::EntityTemplate enemyTemplate;
    enemyTemplate.mInherits = {"living_entity", "physics_entity"};

    factory.addTemplate("enemy", enemyTemplate);

    //store our entity components in a list
    std::vector<std::unique_ptr<fea::EntityComponent>> components;
    components.push_back(std::unique_ptr<PhysicsComponent>(new PhysicsComponent(bus)));
    components.push_back(std::unique_ptr<HealthComponent>(new HealthComponent(bus)));

    //create our entity instances. 2 rocks and 2 enemies. we also change the default attributes for some of them for variation
    factory.instantiate("rock").lock()->setAttribute("position", glm::vec2(50.0f, 50.0f));
    factory.instantiate("rock").lock()->setAttribute("position", glm::vec2(20.0f, 500.0f));
    factory.instantiate("enemy");
    factory.instantiate("enemy").lock()->setAttribute("position", glm::vec2(100.0f, 100.0f));

    //get all our created entities and pass them to the components. if they have the right attributes, the components will store them
    for(auto entity : manager.getAll())
    {
        for(auto& component : components)
            component->entityCreated(entity);
    } //(this can be done in a better way but i wanted to keep it simple)

    int32_t counter = 0;

    //our main loop which will terminate after 30 frames
    while(counter < 30)
    {
        //notify that a frame has passed
        bus.send(FrameMessage());

        //go through all entities and look for dead ones. these will be removed
        for(auto e : manager.getAll())
        {
            fea::EntityPtr entity = e.lock();
            if(entity->hasAttribute("alive"))
            {
                //if an entity is dead, tell all components to remove it if they have it, and finally remove it from the entity manager
                if(!entity->getAttribute<bool>("alive"))
                {
                    for(auto& component : components)
                        component->entityRemoved(entity->getId());

                    manager.removeEntity(entity->getId());
                }
            }
        }
       
        counter++;
    }
}
Title: Re: Feather Kit - A C++ Game Framework
Post by: Rexou on March 05, 2014, 02:07:00 pm
Hi there,

Again, nice work on the entity system ! The API seems very intuitive to me now especially on the entities template.

I was wondering : Is there a specific reason not to have Systems in your framework ? I mean is that only a design choice to put the behavior in components or are there any constraint that forced you towards that architecture ?

Ty for the sample about entities and keep up the good work.
Rexou
Title: Re: Feather Kit - A C++ Game Framework
Post by: therocode on March 06, 2014, 04:56:13 am
Thanks a lot! :)

Hmm what do you actually mean with "Systems" VS "components"? It seems to me like poeple use a lot of different terminology for these things haha.

Cheers!
Title: Re: Feather Kit - A C++ Game Framework
Post by: Rexou on March 06, 2014, 10:09:11 am
Yeah there are a lot of ECS terminology/architecture/implementation hehe

What i mean is that you've put the behavior & data in the components and i wanted to know if that was originally intended and if something prevented you from decoupling data (into components) and behavior (in systems) and let the different Systems/Controllers iterate over the entities it's interested in (using bitmasks or keepEntity()-like fonctions to check if it has the right components like you did).

That's just a bit of curiosity on constraints encountered while implementing something like that, I have done a very simple one for learning purpose but never tried to layout the underlying type in order to avoid cache misses and optimize the performances. Your implementation seems to be very flexible and that's why I am very curious about the difficulties/choices happening during the development.

Maybe i am a little bit off-topic just let me know if that's the case,
Rexou.

EDIT : Nevermind, just saw your post on your blog explaining this part !
Title: Re: Feather Kit - A C++ Game Framework
Post by: therocode on March 06, 2014, 04:53:47 pm
Ah, well there is decoupling. :)

In my system I call it attributes and components where attributes are data and components are logic.

So the attributes are completely detached from any logic and can be freely accessed with the .setAttribute and .getAttribute functions.

Then the logic is a system where you specialise behaviour by inheriting from one EntityComponent class which specifies which entities it should process.

There was before an AlignedEntityBackend which could be used by the entity system to get cache friendly iterable entity data, but that one was coded badly and has now been taken out. I plan however to in a future version rewrite it and incorporate it again. I made a blog post about how the inner workings worked here: http://blog.therocode.net/2013/04/insights-into-the-entity-manager-design-decisions/ (http://blog.therocode.net/2013/04/insights-into-the-entity-manager-design-decisions/)

Hope that answered your question! :) It is not on topic, discussion is always interesting!
Title: Re: Feather Kit - A C++ Game Framework
Post by: therocode on April 06, 2014, 02:06:03 pm
Greetings!

It has been a while since I posted here last time. I have some update news regarding the framework and since a few of you guys seemed interested I'll write them here. :)

General approach changes
Up until now, version management and such was a mess. But I have now decided to follow semantic versioning (http://semver.org). This in short terms mean that you can tell from the versioning number what an update does. 0.0.x is a bugfix/patch update, 0.x.0 is a feature addition update in a way that does not break compatibility and x.0.0 is a compatibility breaking update.

I will also no longer develop on the master branch (which is a very bad thing to do in the first place for a library) so the default cloning of the repo will always be the latest official release and will match the documentation.

From now on every new release will come with changes listed in the changelog.txt and information will be available on how to transition in case of API breaking changes.

New features/big changes
Woo, everyone loves new features!

The biggest addition is a whole new module. The Audio module. This module lets you play audio, music or custom streams in a way fairly similar to SFML. It also lets you apply effects and filters with which you can create realistic room acoustics, muffle the sounds under water or maybe add an echo to a canyon level.

Aside from that, a big part of the Entity System module is now also rewritten to be way more safe. It can also store any data type now, and the API is more convenient to use.

Other changes
However much I like the UK spelling myself, this is far from standard in the programming world. Feather Kit now uses US spelling.

All header files have been renamed to .hpp and the templated ones now hide the implementation in .inl files.

The CMakeLists now makes sure to use the -d prefix for debug builds and the FindFeatherKit.cmake is updated to reflect this as well.

The forum has been updated, but not many people registered there anyway so I am not sure who cares about this. :D

So what now?
Before the true 1.0.0 release, I will write more tutorials and update the website a bit more. There will also be a showcase application to show what Feather Kit can be used for. When that is done, I will see if I can post about Feather Kit in other places than just here to see if there is an interest.

Oh, the web build is also not working right now in the 1.0.0rc1 version and will be patched as soon as possible.

If you're interested, check the new version out at the website or go directly to the source code.

Feather Kit website (http://featherkit.therocode.net)
Source code (https://github.com/therocode/featherkit)

Thanks for reading! :)
Title: Re: Feather Kit - A C++ Game Framework
Post by: Nexus on April 06, 2014, 09:47:30 pm
I will also no longer develop on the master branch (which is a very bad thing to do in the first place for a library) so the default cloning of the repo will always be the latest official release and will match the documentation.
Why that? I would say users that clone the Git repository expect to have the latest changes.

You can use Git tags to refer to official releases.

Title: Re: Feather Kit - A C++ Game Framework
Post by: therocode on April 06, 2014, 10:21:14 pm
Why that? I would say users that clone the Git repository expect to have the latest changes.

You can use Git tags to refer to official releases.

Well, I guess it depends on the release cycle of the library. I aim to wrap up and release things rapidly, and fix bugs really quickly etc. Combined with semantic versioning that lets me push bugfixes and feature additions as releases to the master quickly enough to be equivalent to "latest changes". Then if you as user want the experimental non-released stuff you can check out the development branch.

But of course, if you have a way slower release cycle like SFML for example, then you might want to use the other approach. :)
Title: Re: Feather Kit - A C++ Game Framework
Post by: minirop on April 07, 2014, 11:02:43 pm
I will also no longer develop on the master branch (which is a very bad thing to do in the first place for a library) so the default cloning of the repo will always be the latest official release and will match the documentation.
Why that? I would say users that clone the Git repository expect to have the latest changes.

You can use Git tags to refer to official releases.
sometimes it can help (http://waterstreetgm.org/git-why-you-should-never-commit-directly-to-master/).
Title: Re: Feather Kit - A C++ Game Framework
Post by: therocode on June 30, 2014, 11:21:20 am
Alright, I felt it was time to update this thread again in case someone is interested in knowing the progress. :)

Since last time, I've seen some interest in the framework and I've got some users/contributors (for example this project (http://cyvasse-online.com))which really helps the maturing of the library. :)

I am still trying to get the library in a good shape for the 1.0.0 release (it is now at 1.0.0rc4) and some things might change until then, but as it hits 1.0.0, there will be no API breaking changes until 2.0.0.

Some notable changes since last time:


The pathfinder is completely general and can work on any data, so even if you are not interested in using featherkit in general for your project, you can still use only the pathfinder would you need to.

Example 1:
This shows how an infinite landscape can be created using the noise tools:
Link (http://pallkars.net/~zagabar/biomes/)
Controls:
- Cursor keys to steer the camera.
- Click to see what biome is at a certain point.

Example 2:
This shows among other things, text rendering, entity management and pathfinding.
Link (http://pallkars.net/~zagabar/pathfinding/)
Controls:
- Click "begin" to get past splash screen.
- WSAD to steer the camera.
- Click/drag left mouse button to place walls.
- Click/drag right mouse button to erase walls.
- Scroll to zoom.
- Press B to place a building. The workers will find a path to the building site if it exists, and build it.
Title: Re: Feather Kit - A C++ Game Framework
Post by: Temeez on June 30, 2014, 06:47:16 pm
I registered just to say this: Awesome job mate, I just found this today and its very awesome!

Those examples are intriguing and I hope their source code will be available later. :)
Title: Re: Feather Kit - A C++ Game Framework
Post by: Lo-X on June 30, 2014, 08:14:04 pm
Yes I would definitively would like some tutorials/examples about each modules, but the source code is amazing !
Title: Re: Feather Kit - A C++ Game Framework
Post by: therocode on July 01, 2014, 05:27:53 am
Thanks for the feedback! :)

The source of the landscape generator will be made available. I just need to refactor it becasue it is currently very (read extremely) ugly... When I've done that, I'll definitely make the source available.

Not sure about the other one though since it is a game project I am working on, and right now I haven't decided if I want it closed source or not. But it is on my todo-list to write example programs to showcase the things shown there anyway.

I will also definitely write more tutorials! The current 4 tutorials doesn't touch most of the modules hehe. Cheers.
Title: Re: Feather Kit - A C++ Game Framework
Post by: Xafi on July 04, 2014, 06:06:23 pm
I need watch this source so i can learn new way of programming
Title: Re: Feather Kit - A C++ Game Framework
Post by: Lo-X on October 08, 2014, 03:17:13 pm
I've got an error when I build the lib :

/featherkit/src/entity/glmtypeadder.cpp:40:20: error: ‘u64vec2’ is not a member of ‘glm’
return glm::u64vec2(static_cast<uint64_t>(std::stoul(params[0])), static_cast<uint64_t>(std::stoul(params[1])));
              ^

I've the last libglm version available in Ubuntu packages.


Edit: the same with all u64vecX and i64vecX, I replaced them by their rightfull name : uvecX and ivecX and it solved these errors.

But I've got another error :

/featherkit/src/rendering/quad.cpp:6:37: error: converting to ‘const vec2 {aka const glm::detail::tvec2<float>}’ from initializer list would use explicit constructor ‘glm::detail::tvec2<T>::tvec2(const value_type&, const value_type&) [with T = float; glm::detail::tvec2<T>::value_type = float]’
     Quad::Quad() : Quad({2.0f, 2.0f})

along with some other initializer errors that I corrected in the sources (switch from init. list to constructors) and it worked

Title: Re: Feather Kit - A C++ Game Framework
Post by: therocode on October 09, 2014, 02:17:43 pm
Ah, hmm, Interesting with the "not a member" error. I haven't gotten that myself and glm::u64vec2 does definitely exist. Maybe glm/gtc/type_precision.hpp needs to be included. Would you mind trying adding #include <glm/gtc/type_precision.hpp> under the glm include in that file to see if that fixes it? If it does, I'll add it.

As for the second errors, would you be able to show a diff of where you changed the { } to constructors? I'll add those as well in that case.

Thanks for the information. :)
Title: Re: Feather Kit - A C++ Game Framework
Post by: therocode on October 18, 2014, 04:24:25 pm
I myself got these errors now with an updated clang version, so I have fixed all of them and the changes are in the incoming branch. Thanks!