6 ms·
EnTT: Gaming meets Modern C++
- mottosso 6y agoI've been using EnTT for the past 6 months or so for real-time content-creation development, coupled with a graphics framework called Magnum, and am really enjoying it. It's very intuitive and the author is very friendly and responsive too which is a massive plus for to get going and bounce ideas around - https://gitter.im/skypjack/entt https://gitter.im/skypjack/entt
- narak 6y agoThis sounds interesting, could you share any more of your project? I want to get back into c/c++ dev, the modern libraries look great!
- nybblesio 6y agoI've used EnTT in both compiler and graphics projects over the past few years. Nice API, good documentation, and continuous updates from skypjack. If you're looking for a C++ ECS, give EnTT a try.
- dkersten 6y agoCompletely agree. I still follow its development even though I don’t currently use it (I plan to get back to my toy game eventually though), its a great library, well designed, excellent performance and skypjack is friendly, super responsive and helpful. Big fan of EnTT.
- mattgreenrocks 6y agoI’m curious how you use it for compiler projects. Can you expand on that? Normally I see the typical stage-based design employed there.
- lenkite 6y agoRead the post and realised it might be a great idea. Perhaps each node in the AST is an entity and you can add/remove components to a node during compilation ? Need to really try it out to be sure this works.
- nybblesio 6y agoYes, this is the basic idea. Tokens from the lexer, AST nodes, basic blocks, control and data-flow graph nodes + edges can all be entities and/or components of entities, depending on how you wish to structure your data. Since a 32-bit entity ID provides a sufficiently large "address space", you get the added benefit of only needing to store 4-byte handles instead of 8-byte pointers. EnTT has an eventing system as well. These can be triggered in various ways (entity created, entity deleted, component assigned/removed, etc). I've used eventing to control fine-grained compilation pipelines. For example a recent scheme compiler I wrote used events to simplify inlining (both define-macro/define-syntax and straight procedure inlining) and quote/quasi-quote/unquote/unquote-splicing translation. If you spend a lot of time writing compilers, I find an ECS like EnTT can give you extra flexibility during the design/prototype phase. Try it out on a simple prototype and see if you like it.
- skypjack 6y agoWow. Is this a public project or something you can mention? It sounds very interesting!
- nybblesio 6y agoMy recent work involving EnTT is still under NDA, though at least one of the projects should have a public announcement sometime next year. With that said, if there is interest, I'd enjoy building a clean room compiler for an existing language using EnTT and other techniques I've developed over the years. Thoughts? While I absolutely adore TinyCC, it might be worthwhile giving that space another go?
- skypjack 6y ago
- Lawrencemm 6y agoYou can achieve a lot of things with this library, a whole new world of architectural patterns opened up for me when I got into it.
- sali0 6y agoI am very unfamiliar with ECS but I am learning. Could you expand on what you're speaking of? Very interested.
- avolcano 6y agoI was looking at EnTT's API when building a little toy ECS of my own in JavaScript. Since I'm working in JS, I haven't really tried to copy its internal architecture since it doesn't quite make sense for a higher-level GC'd runtime, but I think the public API was a really handy reference for the kinds of things a practical ECS needs to have. It's a really impressive and robust project, and the documentation is super thorough and worth a peek if you have any interest in game architecture. (slightly off-topic, but I'm excited to have a venue to ramble a bit about this:) ECS is really cool, and I'm excited about using it more for my games. The "cheap" (de)serialization by moving all state into pure, data-only components is really fascinating - I've been playing around with building networked multiplayer games for a while now, and I'm currently experimenting with rollback netcode. A key part of rollback is saving your state every frame so you can load it if you need to roll back, and ECS makes saving/loading easier to reason about, since you can "just" grab the components and their associated entity IDs and load if needed (EnTT, for the record, has an API for this[1], though they leave the actual (de)serialization up to you). Of course, JS's lack of a memcpy equivalent makes this much harder than what you could do in C++, which has lead me to experiment with immer[2] in my ECS, which uses structural sharing to avoid mutation, so you can get a "copy" of your state by just keeping a reference to it, as future updates will make new objects. This, of course, theoretically could make a ton of garbage (e.g. updating your position every frame would create a new Position object every frame), which is not great for high performance games. I'm not sure how bad this will be in practice - JS GC is relatively smart and fast these days, but I haven't tried doing much beyond little pong or platformer demos yet. I'd also imagine that, like, doing a deep clone of my state tree every frame (or doing the whole JSON.stringify/parse dance if I stick to primitive values) probably generates just as much garbage. Maybe if I could integrate immer with some kind of object pool it'd avoid these issues, but I have no idea how useful object pooling is in practice in JS... [1] https://github.com/skypjack/entt/wiki/Crash-Course:-entity-component-system#snapshot-complete-vs-continuous https://github.com/skypjack/entt/wiki/Crash-Course:-entity-c... [2] https://github.com/immerjs/immer https://github.com/immerjs/immer
- nicoburns 6y ago> but I have no idea how useful object pooling is in practice in JS... I'm pretty sure most JavaScript games use object pooling extensively. GC is definitely an issue if you want to hit 60fps. Even for non-games actually.
- danbolt 6y agoI really enjoy the storage strategy for EnTT. Other ECS games I had known the architecture for were a lot more rigid in terms of space, and it's nice to see more flexibility in that aspect.
- s9w 6y agoIt's a fantastic piece of c++. I've been using it for a year or so and it's still impressive and an immense time saver. The only thing I could think of as an improvement is the documentation. There is a lot of it but it's in many different places and not easy to find. There's an article series on his blog, there is some in the readme but most is in different pages on the GitHub wiki.
- mtsr 6y agoSkypjacks blog posts about all the design choices in making an ECS is great for understanding why EnTT works the way it does: https://skypjack.github.io/2019-02-14-ecs-baf-part-1/ https://skypjack.github.io/2019-02-14-ecs-baf-part-1/
- ur-whale 6y agoIt's header only, good start and makes it worth a second look.
- macgyverismo 6y agoHaving read through the README, I'm not quite sure what makes this perform better than other systems. I can see that it will perform excellent when iterating over a single type as all entries for this type are next to each other. However, for each meaningfull operation you are likely to combine at least two different types, which means data will have to be read from different locations, defeating the purpose. You could put more data in a single type (for the example from README, you would put velocity and position in a single type) but than you are back to hand-tuning your data types as you would in any other system. It still looks like an interesting library, but if there are any inherent performance benefits I am failing to see, I would love to hear about them.
- skypjack 6y agoThe design is such that you pay for what you need. To do what you're looking for, that is, a linear access on multiple components without jumps nor anything else, there exist groups. They are the fastest thing you can imagine because you iterate literally N arrays for N components in order with no jumps nor branches. They affect performance on creation/destruction though, in order to speed up quite a lot linear accesses. Also, views are such that it doesn't worth it creating a group when one of the components involved in a query is assigned to few entities, since the view internally uses the shortest pool. And so on, there are tons of details and use cases. The documentation (the wiki, not the README) contains all the details but it's pretty big and takes a while to go through all them. The fact is that a real world software isn't made only of linear accesses, so the whole library is meant to allow optimizing the given access pattern when needed. Feel free to ask if I triggered you and you want more details. ;) Reach me out here, on gitter, discord, by mail, whatever...
- xashor 6y agoSide note: The vel+pos example is a common one in ECS. It also often follow that you should put them in one type in the real world. However, nowadays thanks to SIMD instructions, it is probably faster to have them separate, as you don't have to unpack/align the various fields: // p={(x0,y0),(x1,y1),...} and v={(vx0,vy0),(vx1,vy1),...} for(int j=0;j<2*SIZE;j++)p[j]+=v[j]; vs. // pv={(x0,y0,vx0,vy0),(x1,y1,vx1,vy1),...} for(int j=0;j<4*SIZE;j+=4) pv[i+0]+=pv[i+2],pv[i+1]+=pv[i+3];