08/04/2019 Note: this article is quite old (pre SECS 2.5) but since I ported the example to Svelto 2.8 (beta version at the time of this note), I updated this article as well, although it is still missing some important details related to the new features that ship with the newer SECS versions.

Introduction

Lately I have been discussing Svelto.ECS extensively with several, more or less experienced, programmers. I gathered a lot of feedback and took a lot of notes that I will be using as starting point for my next articles where I will talk more about the theory and good practices. Just to give a little spoiler, I realized that the biggest obstacle that new coders face when starting using Svelto.ECS is the shift of programming paradigm. It’s astonishing how much I have to write to explain the novel concepts introduced by Svelto.ECS compared to the small amount of code written to develop the framework. In fact, while the framework itself is very simple (and lightweight), learning how to move from the class inheritance heavy object oriented design or even the naive Unity components based design, to the “new” modular and decoupled design that Svelto.ECS forces to use, is what usually discourages people from adopting the framework.

Being the framework extensively used at Freejam, I also noticed that it’s thanks to my continuous availability to explain the fundamental concepts that my colleagues have less of a hard time to get in to the flow. Although Svelto.ECS tries to be as rigid as possible, bad habits are hard to die, so users tend to abuse the little flexibility left to adapt the framework to the “old” paradigms they are comfortable with. This can result in a catastrophe due to misunderstandings or reinterpretation of the concepts that are behind the logic of the framework. That’s why I am committed to write as many articles as possible, especially because I know that the ECS paradigm is the best solution I found so far to write efficient and maintainable code for large projects that are refactored and reshaped multiple times over the span of years and Robocraft as well as Cardlife are the existing proof of what I try to demonstrate.

I am not going to talk much about the theories behind the framework in this article, but I want to remind what took me to the path of ditching the use of an IoC Container and starting using exclusively the ECS framework: an IoC container is a very dangerous tool if used without Inversion of Control in mind. As you should have read from my previous articles, I differentiate between Inversion of Creation Control and Inversion of Flow Control. Inversion of Flow Control is basically the Hollywood principle “Don’t call us, we will call you”. This means that dependencies injected should never been used directly through public methods, in doing so you would just use an IoC container as a substitute of any other form of global injection like singletons. However, once an IoC container is used following the IoC principle, it mainly ends up in using repeatedly the Strategy Pattern to inject managers used only to register the entities to manage. In a real Inversion of Flow Control context, managers are always in charge of handle entities. Does it sounds like what the ECS pattern is about? It indeed does. From this reasoning I took the ECS pattern and evolved it into a rigid framework to the point it can be considered using it like adopting a new coding paradigm.

The Survival Example

let’s start downloading the project from https://github.com/sebas77/Svelto.MiniExamples/tree/master/Example2-Survival

open the scene Level01 and open the project in your IDE. Everything starts from maincontext.cs file. 

The Composition Root and the EnginesRoot

The class Main is the Application Composition Root. A Composition Root is where dependencies are created and injected (I talk a lot about this in my articles). A composition root belongs to the context, but a context can have more than one composition root. For example a factory is a composition root. Furthermore an application can have more than one context but this is an advanced scenario and not part of this example.

Before to start digging in the code, let’s introduce the first terms of the Svelto.ECS domain language. ECS is an acronym for Entity Component System. The ECS infrastructure has been analyzed abundantly with several articles written by many authors, but while the basic concepts are in common, the implementations differ a lot. Above all, there isn’t a standard way to solve the few problems rising from using ECS oriented code. That’s where I put most of my effort on, but this is something I will talk about later or in the next articles. At the heart of the theory there are the concepts of Entity, Components (of the entities) and Systems. While I understand why the word System has been used historically, I initially found it not intuitive for the purpose, so Engine is synonym of System and you may use it interchangeably according your preferences.

The EnginesRoot class is the core of Svelto.ECS. With it is possible to register the engines and build all the entities of the game. It doesn’t make much sense to create engines dynamically, so all the engines should be added in the EnginesRoot instance from the same composition root where it has been created. For similar reasons, an EnginesRoot instance must never been injected and engines can’t be removed once added.

We need at least one composition root to be able to create and inject dependencies wherever needed. Yes, it’s possible to have even more than one EnginesRoot per application, but this is too not part of this article, which I will try to keep as simple as possible. This is how a composition root with engines creation and dependencies injection looks like:

This code is part of the survival example which is now well commented and follows almost all the good practice rules that I suggest to use, including keeping the engines logic platform independent and testable. The comments will help you to understand most of it, but a project of this size may be already too much to swallow if you are new to Svelto. For this reason, let’s proceed as we would have done if started from scratch: 

Entities

the first step, after creating the empty Composition Root and an instance of the EnginesRoot class, would be to identify the entities you want to work with first. Let’s logically start from the Player Entity. The Svelto.ECS entity must not be confused with the Unity GameObject. If you had the chance to read other ECS related articles, you will see that in many of those, entities are often described as indices. This is probably the worst way possible to introduce the concept. While this is true for Svelto.ECS too, it’s well hidden. As matter of fact, I want the Svelto.ECS user to visualize, describe and identify every single entity in terms of Game Design Domain language. An entity in code must be an entity described in the game design document. Any other form of entity definition will result in a contrived way to adapt your old paradigms to the Svelto.ECS needs. Follow this fundamental rule and you won’t be wrong in most of the cases. An entity class doesn’t exist per se in code, but you still must define it in a not abstract way. 

Engines

Next step is to think about what behaviours to give to this Entity. Every behaviour is always modeled inside an Engine, there is no way to add logic in any other classes inside a Svelto.ECS application. For this purpose we can start from the player character movement and define the PlayerMovementEngine class. The name of the engine must be very specific, as the more specific it is, the higher is the chance the Engine will follow the Single Responsibility Rule. Naming classes properly in Svelto.ECS is of fundamental importance. It’s not just to comunicate clearly your intentions, but it’s actually more about letting you think about your intentions.

For the same reason I would suggest (as good practice) to put your engine inside a specialised namespace. Using specialized namespaces helps a lot to identify code design errors when entities are used inside not compatible namespaces. For example, you wouldn’t expect any enemy entity to be used inside a player namespace, unless you want to break the good rules related to modularity and decoupling of objects. The idea is that entities of a specific namespace can be used only inside that namespace or a less abstracted namespace. While with Svelto.ECS is much harder to turn your code in to a fully fledged spaghetti bowl, where dependencies are injected everywhere and randomly, this rule will help you to take your code to an even better level where dependencies are correctly abstracted between classes.

08/04/19 Note: this good practice has been taken now to another level, encapsulating the layers of abstraction inside separate composition roots belonging in different assemblies. I never discussed this approach formally, so another article or wiki paragraph will come later on.

In Svelto.ECS abstraction is pushed on several fronts, but ECS intrinsically promote separation of the data from the logic that must handle it. Entities are defined by their data, not their behaviours. Engines instead are the place where to put the shared behaviours of entities, so that engines can always operate on a set of entities.

Svelto.ECS, and the ECS paradigm in general, allows the coders to achieve one of the holy grails of clean programming, that is the perfect encapsulation of logic. Engines must not have public functions, consequentially Engines are never injected in any other engine. If you think to pass an engine as parameter, you are probably doing something wrong already.

Compared to Unity monobehaviours, engines already show the first great benefit, which is the possibility to access to all the entity states of a given type from the same code scope. This means that the code can easily use the state of all the entities directly from the same place where the shared entity logic is going to run. Furthermore separate engines can handle the same entities so that an engine can change an entity state while another engine can read it, effectively putting the two engines in communication through the same entity data. An example of this can be seen with the engines PlayerGunShootingEngine and PlayerGunShootingFxsEngine. In this case the two engines are in the same namespace, so they can share the same entity data. PlayerGunShootingEngine determines if a player target (an enemy) has been damaged and writes the lastTargetPosition of the IGunAttributesComponent (which is a component of the PlayerGunEntity). the PlayerGunShootFxsEngine handles the graphic effects of the gun and reads the position of the currently targeted player target. This is an example of communication between engines through data polling. It’s quite logical that engines should (and must) never hold states.

Engines are not supposed to know how to interact with other engines. The best engines are the ones that do not even need to trigger any form of external communication. These engines reflect a well encapsulated behaviour and usually work through a loop. Loops can be modeled with a Svelto.Task task inside Svelto.ECS applications. Since the player movement must be updated every physic tick, it would be natural to create a task that is executed every physic update. Svelto.Tasks allows to run every kind of IEnumerator on several types of schedulers. In this case we decide to create a task on the PhysicScheduler that allows to update the player position:

Svelto.Tasks can run IEnumerator directly (using the extension methods Run and RunOnScheduler for Svelto Tasks 1.5 and RunOn for Svelto Tasks 2.0), but in this case I decided to use a TaskRoutine, as I want to stop it when the entity is removed.

Svelto.ECS exploit the Add and Remove callbacks to know when specific entities are added or removed. These callbacks are used also during a swap (note: these interfaces are currently undergoing some refactoring to make the difference between Add,Remove and Swap more obvious, so this paragraph may be obsolete soon).

Engines more commonly implement the IQueryingEntityViewEngine interface instead. This allows to access the entity database and retrieve data from it. Remember you can always query any entity from inside an engine, but in the moment you are querying an entity that is not compatible with the namespace where the engine lies, then you know you are already doing something wrong. Engines should never assume that the entities are available and they must work on a set of entities. Engines must always be functional, regardless the number of entities currently available (0, 1 or N). This rule can be broken if you know by design that specific entities will be unique (like the Player in this example). A very common approach to how to query entities is found in the EnemyMovementEngine:

In this case the engine main loop is running directly immediately on the predefined scheduler. Tick().Run() shows the shortest way to run an IEnumerator with Svelto.Tasks. The IEnumerator will keep on yielding to the next frame until at least one Enemy Target is found. Since we know that there will be always just one target (another not nice assumption), I pickup the first available. While the Enemy Target can be just one (although could have been more!), the enemies are many and the engine takes care of the movement logic for all of them.

Note that the component never exposes the Unity navmesh dependency directly. Entity Component, as I will say later, must always expose value types. In this case this rule also allows to keep the code testable, as the field value type navMeshDestination could be later implemented without using a Unity Nav Mesh stub.

To conclude the paragraph related to engines, note that there isn’t such a thing as a too small engine. Hence, don’t be afraid to write an engine even for just few lines of code, after all you can’t put logic anywhere else and you want your engines to follow the Single Responsibility Rule. 

EntityViews

So far we introduced the concept of Engine and an abstracted definition of Entity, let’s now define what an EntityView is. I have to admit, of the 5 concepts of which Svelto.ECS is built upon, the EntityViews is probably the most confusing. Previously called Node, name taken from the Ash ECS framework, I realized that node meant nothing. EntityView may be confusing as well, since programmers usually associate views with the concept coming from Model View Controller pattern, however in Svelto.ECS is called View because an EntityView is how the Engine views an Entity. This scheme of the Svelto.ECS concepts should help a bit:

I suggested to start working on the Engine first, thus we are on the right side of this scheme. Every Engine comes with its own set of EntityViews. An Engine can reuse namespace compatible EntityViews, but it’s more common for an Engine to define its entity views. The Engine doesn’t care if a Player Entity definition actually exists, it dictates the fact that it needs a PlayerEntityView to work. The writing of the code is driven by the Engine needs, you shouldn’t create the entity and its field before to know how to use those fields. In a more complex scenario, the name of the EntityView could have been even more specific.

(note: since the introduction of Svelto.ECS 2.5, EntityStructs are much more relevant then EntityViewStructs. I still call EntityStructs and EntityViewStructs entity views, because I still like the original definition. However EntityStructs are effectively entity components)

EntityViews are classes that hold only Entity Components. Entity Components in Svelto.ECS are always interfaces that must be implemented, but the Engine and EntityView doesn’t need to know the implementation. For this reason, without even implementing the component yet, I can just start to type the logic in the engine like if it was in place:

Even if PlayerEntityView is still an empty class, I start to use the fields I need. Since an EntityView can hold only components, the field must be a component interface.

Hoping you use an IDE that supports refactoring, the IDE will immediately warn you that the field you are trying to access actually doesn’t exist. This is where the refactoring tools can help you speeding up the writing of the code. For example, using Jetbrains rider (but it’s the same with Visual Studio) you can create the field automatically like this:

this would add the component field in the EntityView like:

since the IPlayerInputComponent interface doesn’t exist yet, I name it and use on the spot. Then I use again the refactoring tool:

this will create an empty interface, so that now the code would look like:

the inputComponent field now exists, but it’s empty so the input field is not defined yet, but I know I need it.

Yes that’s right, I would use again the refactoring tool:

so that the IPlayerInputComponent interface will be filled with the right properties. As long as I don’t run the code, I can build it without needing to implement the Entity Component IPlayerInputComponent interface yet. Honestly, once you get in this flow, you will notice how fast can be coding with Svelto.ECS using the IDE refactoring tools. 

Components

We understood that engines model behaviors for a set of entities and we understood that engines do not use entities directly, but use the entity components through entity views. We understood that an entity view can hold ONLY public entity components.

When EntityViewStructs are used to abstract objects coming from OOP platforms/libraries, an entity component is an interface. The Entity Component interface is then implemented with a so called Implementor. We are now starting to define the Entity itself and we are on the left side of the scheme above.

Components should always hold value types and the fields are always getter and setter properties. This allows to create testable code that is not dependent by the implementation of the Not ECS/OOP platforms or libraries used in the project. Moreover it prevents people from cheating and use public functions (which would include logic!) of random objects.  

EntityDescriptors

This is where the Entity Descriptors actually come to help to put everything together and hopefully let everything click in place. We know that Engines can access to Entity data through the Entity Components held by the Entity Views. We know that Engines model the behavior of the entities through their entity views, that entity views hold only Entity Components and that Entity Components are value types. While I have given an abstracted definition of entity, we haven’t seen any class that actually represent an entity. This is in line with the concept of entities being just IDs inside a modern ECS framework. However without a proper definition of Entity, this would lead coders to identify Entities with EntityViews, which would be catastrophically wrong. EntityViews is the way several Engines can view the same Entity but, conceptually, they are not the entities. The Entity itself should be always be seen as a set of data defined through the entity components, but even this representation is weak. An EntityDescriptor instance gives the chance to the coder to name properly their entities independently by the engines that are going to handle them. Therefore in the case of the Player Entity, we would need an PlayerEntityDescriptor. This class will then be using to build the entity, and while what it really does is something totally different, the fact that the user is able to write BuildEntity<PlayerEntityDescriptor>() helps immensely to visualize the entities to build and to communicate the intentions to other coders.

However what an EntityDescriptor really does is to build a list of Entity Views!!!

This is how the PlayerEntityDescriptor looks like:

the EntityDescriptors (and the Implementors) are the only classes that can use identifiers from multiple namespaces. In this case the PlayerEntityDescriptor defines the list of EntityViews to instantiate and inject in the engine when the PlayerEntity is built. 

EntityDescriptorHolder

The EntityDescriptorHolder is an extension for Unity and should be used only in specific cases. The most common one is to create a sort of polymorphism storing the information of the entity to build on the Unity GameObject. It can be useful when prefabs are seen exclusively as a way to serialise entities and currently they are commonly used to serialise entities for GUIs. However, building entities explicitly is always preferred, so use EntityDescriptorHolders only when you have understood Svelto.ECS properly otherwise there is the risk to abuse it. This function from the example shows how to use the class:

Note that with this example I am already using the less preferred, not generic, function BuildEntity. I will talk about it in a bit. The Implementors in this case are always monobehaviours in the gameobject. Also this is not a good practice. I actually should remove this code from the example, but left to show you this other case. Implementors, as we will see next, should be Monobehaviours only when strictly needed! 

Implementors

Before to build our entity, let’s define the last concept in Svelto.ECS that is the Implementor. As we know now, Entity Components are always interfaces and in c# interfaces must be implemented. The object that implements those interfaces are called Implementors. Implementors have several important characteristics:

  • Allow to uncouple the number of objects to build from the number of entity components needed to define the entity data.
  • Allow to share data between different components, as components expose data through properties, different component properties could return the same implementor field.
  • Allow to create stub of the entity component interface very easily. This is crucial for leaving the engine code testable.
  • Act as bridge between Svelto.ECS Engines and third party platforms. This characteristic is of fundamental importance. If you need unity to communicate with the engines you don’t need to use awkward workarounds, simply create an implementor as Monobehaviour. In this way you could use, inside the implementor, Unity callbacks, like OnTriggerEnter/OnTriggerExit and change data according the Unity callback. Logic should not be used inside these callback, except setting entity components data. Here an example:

Remember the granularity of your EntityViews, entity components and implementors is completely discretional and up to you. More granular they are, more the chance are to be reusable. 

Build Entities

Let’s say we have created our Engines, added them in the EnginesRoot, created its EntityViews that use Entity Components as interfaces to be implemented by one or more Implementors. It is now time to build our first entity. An Entity is always built through the Entity Factory instance generated by the EnginesRoot through the function GenerateEntityFactory. Differently than the EnginesRoot instance, an IEntityFactory instance can be injected and passed around. Entities can be built inside the Composition Root or dynamically inside game factories, so for the latter case passing the IEntityFactory by parameter is necessary.

so let’s see how the normal BuildEntity<T> is used inside the EnemySpawnerEngine code

Don’t forget to read all the comments in the example, they help to clarify even more the Svelto.ECS concepts. Due to the simplicity of the example, I am actually not using the BuildEntityInGroup<T> which is instead commonly used in more sophisticated products. In Robocraft every engine that handles the logic of the functional cubes handles the logic of ALL the functional cubes of that specific type in game. However often is needed to know to which vehicle the cubes belong to, so using a group per machine would help to split the cubes of the same type per machine, where the machine ID is the group ID. This allows us to implement fancy things like running one Svelto.Tasks task per machine inside the same engine, which could even run in parallel using multi-threading.

This piece of code highlight one crucial issue, which I may talk more about in the next articles…from the comment (in case you haven’t read it):

Never create implementors as Monobehaviour just to hold data. Data should always been retrieved through a service layer regardless the data source. The benefit are numerous, including the fact that changing data source would require only changing the service code. In this simple example I am not using a Service Layer but you can see the point. Also note that I am loading the data only once per application run, outside the main loop. You can always exploit this trick when you now that the data you need to use will never change.

Initially I was reading the data directly from the monobehaviour like a good lazy coder would have done. This forced me to create an implementor as monobehaviour just to read serialized data. It could be considered OK as long as we don’t want to abstract the data source, however serializing the information into a json file and reading it from a service request is much better than reading this kind of data from an entity component.

Every entity needs an unique ID. This unique ID must be unique regardless the descriptor type and the group it belongs to. I took this decision recently, so if I say otherwise in other articles, please let me know I will fix it. 

Communication in Svelto.ECS

One problem of which solution has never been standardized by any ECS implementation is the communication between systems. ECS communication must happen through entity data polling, but in SECS there are some exceptions:

Reactive Engines

These are reactive callback that are called when an entity is added, remove or swapped. The entity is passed by ref and the values can be modified. These interfaces may change with SECS 2.8.

DispatchOnSet/DispatchOnChange

The use of DispatchOnSet<T> and DispatchOnChange<T>  Radically changed over the time. Nowadays is used only to implement communication between implementors that abstract underlying platform events and the engine that has the responsibility to handle that specific event. In a pure ECS scenario, without OOP integration, these tools become useless.

The Sequencer

The Sequencer is exclusively used when is absolutely necessary there isn’t any other way to provide an execution order between engines.

Entity Streams

Svelto ECS 2.8 introduces the concept of Entity Stream, please read the related articles to know more about it.  

Svelto.ECS and Unity

Svelto.ECS (as well as Svelto.Tasks) is designed to be platform agnostic. However I mainly use it with unity, so Unity extensions are provided. The EntityDescriptorHolder is an example. Using implementors as Monobehaviour let to exploit most of the Unity callbacks, but on other platforms the reasoning could be very similar. All that said, Svelto.ECS gives you the chance to abstract from Unity and you should use Unity classes as less as possible, especially Monobehaviours. It’s also important to keep in mind that the creation of GameObject(s) is uncoupled from the creation of Entities, the only thing they have in common is the fact that gameobject monobehaviours can be implementors. You can see from the example that enemy gameobjects and their ECS entities are built independently. 

Logic inside utility classes

You can create static utility classes to share code, that is not a problem as long as the static classes do not hold any state (they must be just a set of static functions) 

if you are new to the ECS design and you wonder why it could be useful, you should read my previous articles:

That’s all folks! FEEDBACK ME!

25 Comments

  1. Avatar

    Ok Im still not convinced 100% that components Should not have references to other components.

    Take this example:
    https://github.com/Darelbi/svelto-ecs-sandbox/blob/master/SveltoSandbox/Assets/Scripts/ECS/Engines/Lifter/LitferCollectionEngine.cs

    This is a engine that keeps objects parented for the purpose of moving things
    Along with a carrier.

    I could code the hierarchy Just by querying entities and find entity views by querying IDs, but the code would be perfetcly (in this case) equivalent to the one present in the example. Am I missing some important point? Off course I would only maintain references from that engine only.

    1. Sebastiano Mandalà
      Author

      Put in this way how would have you written the code if the engine would handle a set of lifter entities and a set of liftable entities?

      1. Avatar

        Instead of a List inside the component I would have used a List then the movement engine access the int list, and for each int in it, TryQuery the Liftable so the engine cann add to it the delta movement of the lifter.

        1. Avatar

          I mean, I would have replacing the List of Liftable with a List of int

          1. Sebastiano Mandalà
            Author

            Yes that’s one way and I don’t see why not

  2. Avatar

    Hi, I have a question. how to do you communicate between multiple roots?

    1. Sebastiano Mandalà
      Author

      this is a super interesting question, but first I need to reply with another question, what are you trying to achieve?

      1. Avatar

        sorry I asked that from phone. Not sure, just curious on the topic :). Actually I started migrating a game to using Svelto ECS, and I’m surprised it is actually possible to have the game partially ECSized without much troubles. I tried to think to many usages but apart writing isolated Unit tests I can’t think to some serious use cases. In theory a sequencer can have engines from different roots. If a game part is isolated enough it may make sense using a different root for it (in example the trophy/profile part for a XBOX game may be a self-contained root that use sequencers to send events for very specific things related to player profiles on XBOX).

        Another use case could be handling for PVP games, 2 players have 2 machines so 2 different roots, but no one prevent using 2 roots in the same machine for a hotseat game. In this case there could be 2 symmetric sequencers that send/receive data packets.

        Also.. I noticed I tend to write engines that have a precise execution order. To keep the order correct I wrote many mini-managers that call the engines in a precise order (using a enum and the engines register themselves in the manager using the enum, making the ordering explicit). reading your posts in unity forums I suspect there is a better way to not rely on update order of engines (actually what I’ve done is a sort of simplified sequencer that do “steps” without events).. any clue? XD

        1. Sebastiano Mandalà
          Author

          Contexts are actually very useful to isolate the engines like you said by for the same reason communication should not be needed. At most you can exchange data through service requests.

        2. Sebastiano Mandalà
          Author

          Execution order must be driven only by sequencers, but if you need it a lot there is something wrong in your design.

          1. Avatar

            Well. In example the 2d hyperfast Shadow caster use a order dependent algorithm. Light mesh generation/ Clipping against static intersecting Shadow casters,/ Clipping against moving obstacles.

            Of course every moving thing Should move before the Shadow casting phase and many optimizations to remove invisibile stuff Should be performer After movement update phase and before Shadow casting.

            It seems everything is order dependent. Ho do i Should design that to not be’ order dependent?

          2. Sebastiano Mandalà
            Author

            This is very rendering specific. ECS is a general purpose design, but of course must be adapted for each single specific case. For example, it’s true that svelto has several solutions that are close to data binding and mvvm but it will never beat a proper GUI framework. All that said, it sounds to me that your problem could be easily solved with a serialtaskcollection. Create it in the context, pass it as parameter of the constructor of each engine, register a new enumerator in the right order. Let it start. Now actually it may not be so straightforward but I can create a special collection for this purpose so you can run engines tasks in sequence

        3. Sebastiano Mandalà
          Author

          Hey I read your original post somehow it seems I didn’t read it all the first time. The mini managers idea sounds terrible what you do with that ? Remember engines can never be injected anywhere

          1. Avatar

            Actually the managers are injected in engines and each engine implements a ITick interface. I have a mini manager for movement update, One for Shadows, One for culling, and the managers are runned in a determined order(move/ cull/ Shadows) and each manager update 3/4 engines.

            Since usually if you write something There is a reason for that I wanted to understand how to get rid of the order dependence… Well yes i can Just use svelto tasks and achieve the same execution order, but I feel There is a better way. Yes it is all’ rendering related stuff, but svelto helped a lot keeping it manageable. It is very Easy adding Shadows tricks without touching existing engines

          2. Sebastiano Mandalà
            Author

            Don’t use tick stuff either. We had something like that and ran away from it. Use tasks always. If you tell me what you need exactly I can write a new collection for you if the serialtaskcollection is not enough

  3. Avatar

    Hi, I do appreciate the ECS framework and all the examples. Great job,

    I have however a questions about Group Entities.

    Why there seem to be restriction of moving grouped entity out of group altogether or move un-grouped entity to a group?

    Best regards,
    Dawid

    1. Sebastiano Mandalà
      Author

      The swap group function is largely untested because I never needed to use it so far. All the other applications are therefore theoretical and may be avoided with different designs, so I need to be sure that there are practical applications before implementing them. What are your use cases?

      1. Avatar

        One of our Ideas was to use grouping for creating a pool of objects, instead of instantiating new just put them in to pool or out of it. This can be achieved with specific use cases, or with making all entities grouped. And have separate groups for active(in use entities) and free(objects in pool). I was just wandering if there is practical need for restricting move of entity out of a group (as opposed to just moving it to another group – making a grouped entity un-grouped and vice versa) – I understand that there may have been no need for that – Just wanted to make sure I didn’t missed any principle/rule that would restrict such actions 🙂

        1. Sebastiano Mandalà
          Author

          Pooling was one of the reason why I introduced group swapping. Tbh I could make by default entities being built in a group as there isn’t really a reason to not do so. You didn’t miss anything it’s just I don’t want over complicate the framework. Mind some things tho: I am working already on several new features. Some of them will make building entities require less allocations however if you want to go allocation free you should use entity structs although they come with several limitations

          1. Avatar

            Good stuff. Thanks again for sharing your awesome work.

            A little thing I noticed btw MoveEntityView method name seem to be a bit of a missnoma as it does copy/reference but does not remove from the source list – got me confused a little 🙂

            Best Regards,

          2. Sebastiano Mandalà
            Author

            Thanks there are some things to improve in the example.. I’ll try to fix most of the things this weekend!

  4. Avatar

    Not found EGID in example?

    1. Sebastiano Mandalà
      Author

      I will fix it today but the example currently points to the database refactoring branch of svelto ecs

  5. Avatar

    Hi, I’m trying to use Svelto.ECS in my turn based strategy project. The game has Routes (trade routes) consisting of Points. I’ve decided to group all Points belonging to the same Route as the idea of groups seems to suit the case. Nevertheless, I’ve discovered that group can’t be changed, so it is impossible to add or remove Points of the already created Routes. Is it intended behavior or I have missed any Svelto function? Perhaps, creating temporary group and further swapping between it and edited Route’s group can be a workaround?

    1. Sebastiano Mandalà
      Author

      Hello, I just noticed your comment. Yes swapping is the way to go in this case. A group of disabled point is OK if you don’t want to remove the entity.

Leave a Reply