Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We are updating our Terms of Service for all Unity subscription plans, effective October 13, 2022, to create a more streamlined, user-friendly set of terms. Please review them here: unity.com/legal/terms-of-service.
    Dismiss Notice
  3. Have a look at our Games Focus blog post series which will show what Unity is doing for all game developers – now, next year, and in the future.
    Dismiss Notice

EgoCS - A Full Entity Component System framework

Discussion in 'Assets and Asset Store' started by andoowhy, Dec 26, 2015.

  1. andoowhy

    andoowhy

    Joined:
    Dec 26, 2015
    Posts:
    24
    EgoCS on GitHub

    An Entity (GameObject) Component System framework for Unity3D, in C#.

    EgoCS aims to improve upon Unity3D's GameObject / Component relationship by completely decoupling Data and Behaviour, typical in Unity3D Components.


    Hey all,

    I'm using EgoCS in personal super-secret side-project, but I thought it would cool to open source it. So, after getting the all-clear from my employer, and bashing my head in writing the wiki, here it is! (I actually uploaded it about a month ago, but I'm only promoting it now ._. )

    You can check the project's GitHub wiki for more info.

    If you have any questions, let me know.

    If you find any bugs or want to contribute, I might owe you a drink.
     
    rosdi, hammertime2014 and lazygunn like this.
  2. moure

    moure

    Joined:
    Aug 18, 2013
    Posts:
    184
    Hi,
    Its always nice to play around with new opensource projects and try new things, so thanks for opensourcing your code :)
    As someone who is more a "scripter" than a programmer i find these type of projects extremely interesting. If i understand this correctly your project has a similar aproach to Entitas?
    I recently stumbled upon a "similar" issue like the one you described in your wiki page. I wanted to create something like a procedural spell/ability system where the effects and functionality of the spell could change on they fly (e.g. you level up and now your spell also casts a fireball and also heals everyone for 100 health) and i couldnt quite wrap my head around how to do it (iirc i tried to use delegates for multicasting).
    I think in situations like this your framework could shine. Though since its a completely different aproach to handling things, a bit better wiki/tutorial section and some sample scenes would be great for people like me. Cheers!
     
  3. prakash.jadhavjp

    prakash.jadhavjp

    Joined:
    Mar 27, 2015
    Posts:
    3
    Hi moure totally agree with you on making the code open source !
    Thank you @andoowhy for such product.
    I just started working on unity and I read your approach of coding its very nice !
    I use actions and delegates so you don't have to tell the components or entities to do something its program to do stuff on actions . Is its right way to do it? and if yes then can we implement in your code to combine it .
     
  4. andoowhy

    andoowhy

    Joined:
    Dec 26, 2015
    Posts:
    24
    Thank you! Since you're new to Unity, I would actually suggest not using EgoCS. First, I suggest you get more familiar with Unity, and complete a small game clone, like Pong, Breakout or Space Invaders with the built-in Unity workflow (GameObjects and Components, no Systems). EgoCS is designed to work on top of the traditional Unity workflow, so you should already be familiar and comfortable with it to use EgoCS.

    Since I can't see your project, I can't say if you are doing it the "right way" for your current needs.

    However, if you want to use EgoCS in your project, I can definitely say that no, using delegates and actions is incorrect and unnecessary. EgoCS provides that event-driven functionality with Events and the Event Queue.

    EgoCS assumes that your entire project will follow its rules and conventions, as most frameworks do. You probably won't be able to just combine EgoCS with your current work without changing it significantly, based on how you described it.
     
  5. prakash.jadhavjp

    prakash.jadhavjp

    Joined:
    Mar 27, 2015
    Posts:
    3
    Thank you andoowhy for the suggestion . I will try to use EgoCS it in my next project .
     
  6. Visartech

    Visartech

    Joined:
    Aug 10, 2012
    Posts:
    29
    Hi andoowhy.

    I'm looking for a Unity ECS framework for my project now. My goals are a clean architecture with uncoupled code, and the most convenient workflow. I want it to be integrated with Unity as much as possible.
    I've already looked through a number of ECS frameworks and found drawbacks in all of them:
    - Entitas - too complicated for my case. I'd use it in case I needed to do code sharing or unit testing. But for my project it's an overingeneering.
    - uFrame ECS - its core is not bad and it integrates with Unity nicely. It's built on UniRx which allows to observe changes in componens easily. But the problem is that it's built on graphs which have a lot of bugs and which I don't need since I prefer coding.

    Now I'm looking through your framework. I like the API. Using generics in Systems for querying looks very clean and minimalistic. Also it's great that Unity components can be queried as well.

    However examples are lacking. I wanted to start implementing my game using EgoCS and got stuck on Login screen.

    The question I have are the following:
    1. How would you architect components and system or systems for Login screen with the following hierarchy:
    - LoginScreen
    -- UsernameInput
    -- PasswordInput
    -- LoginButton
    I have several ideas:
    - make single LoginScreen component and put both input fields and button there. In this case LoginSystem would subscribe to Button.onClick in order to listen for onClick events. Is it fine to subscribe to Button.onClick in LoginSystem?
    - make OnButtonClickComponent which publishes the OnButtonClick event. In this case in order to be bound to right entity the component should be added to LoginScreen, not to LoginButton. And in case if there are 2 buttons will I be able to place 2 similar components but with reference to different buttons to same entity?
    2. Are the components immutable here? Is it handled somehow when value inside the component is changed? Or only when new component is added?

    Thanks
     
  7. Visartech

    Visartech

    Joined:
    Aug 10, 2012
    Posts:
    29
    Regarding generics in System declaration, it's convenient for the first glance, but then I found that it's limiting.
    That way you limit system to work only with entities having ALL of those components. I'd prefer to have ability to react to changes in one group of components and update data in another one inside same system. I think that's better than firing a global event and handling it in another system, in order to update data there. I'd like to avoid having too many global events.
     
  8. Sam-K

    Sam-K

    Joined:
    Mar 23, 2013
    Posts:
    27
    Hi All,
    The core reasons for using this framework is decoupled code hence clean code/architecture and tests. But what I would like to ask is, especially, from @andoowhy since he's the creator of an ECS system and @alandyshev as he has tested many such frameworks,
    • Why not use an IOC/DI framework like StangeIOC, Zinject, RobotLegs Sharp? I mean what's the difference not it terms what DI and ECS is because in the end they both tend to provide decoupled code clean architecture, tests?
    • What are specific use cases when to use one over another?
     
    S_Darkwell likes this.
  9. andoowhy

    andoowhy

    Joined:
    Dec 26, 2015
    Posts:
    24
    I accidentally had email notifications turned off for this thread. Sorry about the super-delayed response.

    @alandyshev:

    I don't think ECSs work well for GUIs. ECSs work well with a flat list of independent GameObjects & Components, while GUIs are very nested and hierarchical. I am working on an example project that does have a simple GUI, but I wouldn't use it as the cannon implementation for the reasons I've mentioned and in-general-UGUI-weirdness.

    BTW, Components are very mutable. If a System works with a particular Component, expect it to change.

    Instead of firing events, you could attach a Component, and use a second System. For example, SystemOne updates Components A & B, and SystemTwo updates Components A, B & C. SystemOne can then attach Component C under the right conditions, and the GameObject will now also be updated by SystemTwo. While it might seem tempting to make one System do many things, I've had the best experience making my Systems as single-purpose and granular as possible. I've broken up my PlayerSystem into a PlayerMovementSystem, PlayerCameraSystem, and PlayerAttackSystem.

    @Sam K:
    I think it comes down to personal preference. Personally, I think IoC/DI is an over-engineered solution to make up for the shortcomings of purely Object-Oriented Programming. I love ECSs because of their simplicity, flexibility and rejection of OO dogma.


    BTW, v0.3.0 is out. You should update if you haven't already.
     
  10. andoowhy

    andoowhy

    Joined:
    Dec 26, 2015
    Posts:
    24
    v0.4.0 is out! It has some API changes to reduce the "foreach( var bundle in bundle )" boilerplate. See the Wiki for details.

    However, while v0.4.0 removes the boilerplate in Start(), Update() and FixedUpdate(), it's still there in Event Handler methods. I will be changing the API again in v0.5.0 (out very, very soon) to make it as painless as possible to iterate over each System's GameObjects wherever you'd want.
     
    zyzyx likes this.
  11. Sam-K

    Sam-K

    Joined:
    Mar 23, 2013
    Posts:
    27
    hi Andoowhy I decided using ECS and I'm loving it.. finding it a bit hard in the start to convert from OOP to DOD specially for things not related to core game. but i think with time it will get easier..
    I would like to ask a few noob questions..
    1. How to do things like Download and Read Economy. Analytics IAP etc with ECS? Just let them be monobehaviors or mix of MBs and Systems?
    2. Previously i stored economy in datastructure of custom objects and its always there to read from. how to translate this into ECS. Create entities for each and add components to them ? It doesnt sounds right
     
  12. andoowhy

    andoowhy

    Joined:
    Dec 26, 2015
    Posts:
    24
    ECSs aren't a silver bullet: they're great for gameplay code and AI, but maybe not so much for UI, databases, or working with external SDKs (for ads, analytics , etc).
     
  13. Sam-K

    Sam-K

    Joined:
    Mar 23, 2013
    Posts:
    27
    yeah thought so on the 3rd party side .. but the config file has the values that are integral to the gameplay.. how to tackle that ..
     
  14. andoowhy

    andoowhy

    Joined:
    Dec 26, 2015
    Posts:
    24
    You can write a "Config" EgoSystem with a Start() method that loads the config file, creates one or more EgoEvents with relevant values from the config, and handle those events in other EgoSystems to set up GameObjects & Components.
     
  15. Babar

    Babar

    Joined:
    Mar 5, 2013
    Posts:
    1
    How do we make Components out of object arrays. E.g.a model Upgrade had (three objects/Array) of the same model Prize. How to translate this into components which belong to the same entity.
    If I make a component prize same as prize model or even if I divide it into smaller components prizeid, prizecount.
    How multiple components, that are same, would be attached to an Entity.
    One way I think of is to put number when making components PrizeId1 etc but this seems bad.

    Prize has primitive types e.g. char, int, int.
     
  16. andoowhy

    andoowhy

    Joined:
    Dec 26, 2015
    Posts:
    24
    @Babar, I'm not sure if I understood you're question, but I'll try answering it:

    Let's work from the bottom up. A "Prize" GameObject / Prefab would have a Transform Component, a Mesh Filter Component (which has the 3D model), Mesh Renderer Component (to render the model), and a "Prize" Component (which has relevant data about the prize: score, value, etc.)

    I'm assuming that an "Upgrade" presents one or more "Prizes". On the "Upgrade" GameObject, you can attach one or more "Prize" child GameObjects. From this, an "Upgrade" GameObject would have a Transform Component, an "Upgrade" Component (to store whatever data an Upgrade needs), and a "PrizesReference" Component.

    The PrizesReference Component would contain an array of Prize Components. Rather than use the parent / child relationship to get PrizeComponent references, (which would be a form of tight coupling), you should store them explicitly in a specialized Component. These references would need to be filled in by hand in the Editor, or by an "UpgradeSystem" that generates Prizes for each Upgrade.
     
  17. tgaldi

    tgaldi

    Joined:
    Oct 28, 2015
    Posts:
    90
    @andoowhy

    Hey Andy, I'm playing with ego and I had a question about interacting with a single entity's component.

    I made a character game object and some ability components, such as strength, dex, etc.

    I have an ability system that handle's AddComponent events for the abilities, which goes through and computes a modifier value based on the ability score.

    How would I go about having the ability system fire off when I update the ability score? I tried to remove the ability component then add a new one, but because the events don't fire off until the systems finish, the addcomponent event doesn't fire since the component isn't destroyed yet.

    I also tried to create an event that takes a game object and component type, but couldn't get it to work.

    Thanks.
     
  18. andoowhy

    andoowhy

    Joined:
    Dec 26, 2015
    Posts:
    24
    @tgalditw

    Check out this example GitHub gist.

    There's a DexStat Component (which represents the actual combined dexterity), a DexStatModifyer Component (which modifies the dexterity in some way), and the DexStatSystem EgoSystem.

    The DexStatSystem has Event Handlers for when a DexStatModifyer Component is attached / destroyed on any GameObject with a DexStat Component.

    Other Systems that work with DexStat Components will now have the proper modified value on the next frame. Note that EgoCS will not let you attach multiple DexStatModifyer Components. But, you can still attach other Component types to the GameObject that could affect the DexStat if you have the corresponding logic in the DexStatSystem.

     
  19. tgaldi

    tgaldi

    Joined:
    Oct 28, 2015
    Posts:
    90
    @andoowhy

    Thanks for the gist andy. The problem is that every game object that has a DexStat will be updated when a modifier is added to an entity. What if I have a character that acquires an item and I only want him to have his dex modified?

    Is there a way to create an event that passes in an entity and a component type<>, so that when the event fires off you can find the component on the passed in entity and do some logic?
     
    Last edited: Jun 12, 2016
  20. andoowhy

    andoowhy

    Joined:
    Dec 26, 2015
    Posts:
    24
    @tgaldi

    You could make an event like this:

    Code (csharp):
    1. //ModifyDexEvent.cs
    2. using UnityEngine;
    3.  
    4. public class ModifyDexEvent : EgoEvent
    5. {
    6.     public readonly Dex dex;
    7.     public readonly float amount;
    8.  
    9.     public ModifyDexEvent( float amount, Dex dex )
    10.     {
    11.         this.amount = amount;
    12.         this.dex = dex;
    13.     }
    14. }
    Then, your DexSystem would could look like this:

    Code (csharp):
    1. //DexSystem.cs
    2. using UnityEngine;
    3.  
    4. public class DexSystem : EgoSystem
    5. {
    6.     public override void Start()
    7.     {
    8.         EgoEvents<ModifyDexEvent>.AddHandler( (e) =>
    9.         {
    10.             e.dex.dex += e.amount;
    11.         });
    12.     }
    13. }
    When you "use" the item, you'd create a ModifyDexEvent object. Getting the Dex reference is going to be trickiest bit.
     
  21. tgaldi

    tgaldi

    Joined:
    Oct 28, 2015
    Posts:
    90
  22. MaDDoX

    MaDDoX

    Joined:
    Nov 10, 2009
    Posts:
    764
    This looks great, and your Wiki is clear and to-the-point, differently from other ECS frameworks for Unity.

    So, your global/persistent event system with "component pattern matching" is easy to grasp and use, but left me wondering. How do you deal with dynamic events messaging? For instance, if instead of destroying a brick in your Breakout example you want to send it a WasHit(20) message, to communicate the brick just got 20 hit points of damage. That's usually the most common scenario of course. What's your recommended approach for that, using SendMessage (not type safe) or calling a method in the component directly (which sounds like hard coupling and defeating the point)? Or am I missing something?

    PS.: I currently favorite ExecuteEvents in my Unity projects, for being native, decoupled and type-safe, but I'm not sure it'd work with Ego.
     
  23. hammertime2014

    hammertime2014

    Joined:
    Jan 16, 2014
    Posts:
    6
    Hey MaDDoX. Are you not using the AddEvent to fire events?

    For example, we do lots of this kinda thing in the game, then subscribe to these events in the EgoSystems.

    EgoEvents<PlayerFiredWeaponEvent>.AddEvent(new PlayerFiredWeaponEvent());
     
  24. MaDDoX

    MaDDoX

    Joined:
    Nov 10, 2009
    Posts:
    764
    But the Player is a static entity (ie. created in edit time), thus you may easily apply a static event. What I asked was how to send a message from a dynamic (instantiated in runtime) object, like a missile, to another dynamic object, like an alien ship.
     
  25. hammertime2014

    hammertime2014

    Joined:
    Jan 16, 2014
    Posts:
    6
    If your player is static, it could be passed inside the event.

    EgoEvents<PlayerFiredWeaponEvent>.AddEvent(new PlayerFiredWeaponEvent(thePlayer, theMissile, otherData));

    A system would then have a handler for that event - which would look something like:

    void Handle(PlayerFiredWeaponEvent e) {}

    (or, the handler could reference the global static player if you so wished)
     
  26. andoowhy

    andoowhy

    Joined:
    Dec 26, 2015
    Posts:
    24
    Hi everyone,

    EgoCS v1.0.0 has been released! You can download it here.

    The biggest changes can be seen on this Wiki page. Mainly, I introduced EgoConstraints and EgoParentConstraints to define and retrieve desired Components on a GameObject, as well as it's parent GameObject (and grandparent, etc).
     
    hammertime2014 likes this.
  27. bayganik

    bayganik

    Joined:
    Jan 30, 2017
    Posts:
    12
    I've retrofit my systems to match the new constraint. The wiki is not "exactly" clear.
    old:
    publicclassInitializePlayerSystem : EgoSystem<MoveAbleComponent, PlayerComponent ,AcceleratableComponent, Transform>
    new:
    publicclassInitializePlayerSystem : EgoSystem<EgoConstraint<MoveAbleComponent, PlayerComponent ,AcceleratableComponent, Transform>>

    publicoverridevoid Start()

    {

    constraint.ForEachGameObject(

    ( ego, moveAble, player, acceleratAble, transform) =>

    {

    player.transform.position = transform.position;

    moveAble.speed = .025f;

    moveAble.maxSpeed = .075f;



    }

    );

    }

    Am I on a right track? The ForEachGameObject loop does not require the types to be mentioned anymore. How did I get the small "constraint" variable in front of ForEachGameObject?

    Thank you for improving this package. Just need to keep up with you :)
     
  28. andoowhy

    andoowhy

    Joined:
    Dec 26, 2015
    Posts:
    24
    Yep, your changes seem to be correct. However, I suggest you should put the EgoConstraint definition on it's own line like so:
    Code (CSharp):
    1. publicclassInitializePlayerSystem : EgoSystem<
    2.     EgoConstraint<MoveAbleComponent, PlayerComponent ,AcceleratableComponent, Transform>
    3. >{
    4.     //...
    5. }
    That's correct. You can include the types in the lambda callback if you want, but the compiler is smart enough to figure them out. I omit them since it's less visual noise (and less to type).

    Every System you make inherits it from EgoSystem<...>
     
  29. bayganik

    bayganik

    Joined:
    Jan 30, 2017
    Posts:
    12
    Thank you for your prompt reply.

    I have attached a component to the Parent GameObject (that has at least one child). When I try to get this object using that component, the system will not work. Is it because the game object is a parent of many other?

    Example game object:
    >FinishLine (sqr box)
    >>FinishFlag (an image)

    Component attached : FinishLineComponent
    System call:
    publicclassPlayerCarSystem : EgoSystem<EgoConstraint<MoveAbleComponent, PlayerComponent, FinishLineComponent>>

    This will not work. No compile errors but system acts as if there are no objects that meet the criteria. If I remove the FinishLineComponent, then it works.

    Help me Obi-One !!
     
  30. andoowhy

    andoowhy

    Joined:
    Dec 26, 2015
    Posts:
    24
  31. bayganik

    bayganik

    Joined:
    Jan 30, 2017
    Posts:
    12
    Andrew,

    Let me apologize ahead of time for asking stupid question.

    I've tried a lot of combination and I can't seem to make a particular issue to go away. I am making a simple system with 2 components
    [DisallowMultipleComponent]
    publicclassPlayerComponent : MonoBehaviour

    [DisallowMultipleComponent]
    publicclassEndOfLineComponent : MonoBehaviour

    The system has the following definition
    publicclassEndOfLineSystem : EgoSystem<EgoConstraint<EndOfLineComponent, PlayerComponent>>
    publicoverridevoid Start()
    {
    constraint.ForEachGameObject(

    (ego, endofline, player) =>
    {
    Debug.Log(endofline.transform.position.y);
    }
    ) ;
    }

    They are both attached to simple GameObjects. A system with just one of them works. Not both of them.
    When I use both of them, and I step thru the code I see your code below executing, in EgoConstraint2.cs module, I see a variable "rootBundles" which is empty. Under what condition is the rootBundles empty? I am doing something wrong to cause that. I really want to make this work. What am I doing wrong?

    publicvoid ForEachGameObject( ForEachGameObjectDelegate callback )
    {
    var lookup = GetLookup( rootBundles );
    foreach( var kvp in lookup )
    {
    currentEgoComponent = kvp.Key;
    var bundle = kvp.Value asEgoBundle<C1, C2>;
    callback(
    currentEgoComponent,
    bundle.component1,
    bundle.component2
    );
    }
    }
     
    Last edited: Jan 31, 2017
  32. andoowhy

    andoowhy

    Joined:
    Dec 26, 2015
    Posts:
    24
    I can see a few issues. First, when you're copy/pasting code into a forum post, please embed it in a code block like so:



    It makes code a lot easier to read.

    Second, when you want to work with a GameObject's Transform Component, please include it in the EgoConstraint Parameters:

    Code (CSharp):
    1. EgoConstraint<Transform, EndOfLineComponent, PlayerComponent>
    2.  
    3. //...
    4.  
    5. constraint.ForEachGameObject( ( ego, transform, endOfLine, player) =>
    6. {
    7.     //...
    8. }) ;
    "rootBundles" should be empty when EgoCS cannot find any GameObjects that meet the Constraints. I'll double check that code later this evening.
     
  33. andoowhy

    andoowhy

    Joined:
    Dec 26, 2015
    Posts:
    24
    Hi everyone, v1.0.1 is out.

    Please update ASAP as it includes a critical bug fix. Sorry about that.
     
  34. bayganik

    bayganik

    Joined:
    Jan 30, 2017
    Posts:
    12
    Thank you for the quick fix.

    How can I tell which Entity's transform I am working with? Every Entity (GameObject) has this component. I am passing a Car and a Finish Line Entity to the system and need to check their positions against each other.

    My impression was by using the components (in below example), I am passing both objects to the system (with all of their components).
    Code (CSharp):
    1. EgoConstraint<Transform, EndOfLineComponent, PlayerComponent>
     
    Last edited: Feb 1, 2017
  35. bayganik

    bayganik

    Joined:
    Jan 30, 2017
    Posts:
    12
    The system works properly on one entity with all of its components.

    if you have ONE entity called Player with following components, then all is well,

    Code (CSharp):
    1. public class PlayerCarSystem : EgoSystem<EgoConstraint< Transform, PlayerComponent, MoveAbleComponent>>
    If you have TWO entities called Car & FinishLine with following components then it won't work.

    Code (CSharp):
    1. public class EndOfLineSystem : EgoSystem<EgoConstraint<Transform, CarObjectComponent, EndOfLineComponent>>
    If you attach AllObjectComponent to every entity in the game, it works and I can go thru all of them.

    Code (CSharp):
    1. public class EndOfLineSystem : EgoSystem<EgoConstraint<Transform, AllObjectComponent>>
     
    Last edited: Feb 1, 2017
  36. andoowhy

    andoowhy

    Joined:
    Dec 26, 2015
    Posts:
    24
    What the... wow. I have no words, other than DO NOT DO THIS, HOLY--

    I appreciate your enthusiasm, but you have a fundamental misunderstanding of what an Entity-Component-System is, and what it can do. For now, stop. Stop working on your project and read this article explaining ECSs, then read the EgoCS wiki. Twice through. All of it. After you're done that, you can read through the rest of this post:

    When you need to look at two GameObjects (like whether your Player/Car has crossed the Finish Line), you need to use Events:

    Every time the Player/Car/Whatever moves, you create a PlayerMoveEvent (or equivalent). Then a FinishSystem, that's Constrained to FinishLine Components, receives PlayerMoveEvents. You can then iterate over all FinishLine GameObjects in the MoveEvent handler and check if the Player/Car has crossed the finish line.
     
    Last edited: Feb 2, 2017
  37. bayganik

    bayganik

    Joined:
    Jan 30, 2017
    Posts:
    12
    LOL . I was trying to take short cuts, but apparently I have to give this more thought !!

    I come from MonoGame development and big classes for every thing. I rolled my own very simple ECS. I am new to Unity and trying to put things in perspective. Thanks for the kick in the pants.
     
  38. andoowhy

    andoowhy

    Joined:
    Dec 26, 2015
    Posts:
    24
    Hi everyone, please update to v1.0.2 ASAP.

    It includes a critical bug fix for adding GameObjects / Instantiating prefabs with Children.
     
  39. bayganik

    bayganik

    Joined:
    Jan 30, 2017
    Posts:
    12
    I've finally figured the system, events connections and uploaded a sample car racing game to github.

    https://github.com/bayganik/EgoCS_RaceCar_Example

    Again, thank you for providing this framework for everyone to use. I tried to use Entitas but got tired of it being "decoupled" from Unity. For someone like me that makes games for personal use and for the fun of programming, EgoCS does a much better job.
     
  40. andoowhy

    andoowhy

    Joined:
    Dec 26, 2015
    Posts:
    24
    Any variables declared in a System are verboten, and a severe anti-pattern. In your project specifically: "carComp" and "gameIsOver" in PlayerCarSystem.cs, along with playerComp" and "gameIsOver" in OpponentCarSystem.cs. To represent a valid "game over" state while keeping your Systems pure, have a look at my example project.

    Also, this is more of a general Unity-thing, but don't use Constructors for Components & Monobehaviours. Unity will call them multiple times during when serialising / deserialising, and thing'll get weird. In your case, for your SpeedComponent, you can simply make a SpeedComponentInitialisationSystem.cs, and setup your Components in SpeedComponentInitialisationSystem.Start()
     
    laurentlavigne likes this.
  41. bayganik

    bayganik

    Joined:
    Jan 30, 2017
    Posts:
    12
    Thank you for looking at the example and the sound advise. I am new to Unity and your framework is the only reason I am giving it a try.

    I will play around with the your recommendations.

    EDIT: Fix the variables in system scripts. Looking at speed component initial setting .. It is being done in the "Start()" function. I would think, that it is called only once. Am I wrong?
     
    Last edited: Feb 15, 2017
  42. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    5,636
    I've struggled in the past to keep an actor->action->subject pipeline and came to the conclusion that data transformation is just easier than trying to map the real world to a computer (there is something philosophical lurking here somewhere).
    After doing some rather simple event driven everything, I'm tempted to make the jump to ECS, I have a few questions:
    1. why is there so much scaffolding code? in what way is it better than tons of monos sending tons of events that other tons of monos listen to?
    2. I see you have constraints. Do you have more general ways to make queries such as "Enemies within 5 meters that have less armor than 1/10th of my dps"?
    3. did you benchmark performance? I see that you use unity's component system ( Ego.AddComponent) in some cases and binary masks of your own brew in others.
    4. Behaviour Trees with ECS, ever tried to integrate?
    5. bonus question: egoComponent.HasComponents<Pause>() I see you have quite a few overloads handling up to 5 filters. Why do you check for component in such way? instead of HasComponents(params T p) ... if it's even valid c# ;)
     
  43. andoowhy

    andoowhy

    Joined:
    Dec 26, 2015
    Posts:
    24
    Mike Acton's Data Oriented Design talk was very enlightening for me, and I highly suggest it. The big eureka moment for me was that we don't have to try to model the entire world, nor do we need to follow *cough*objectoriented*cough* dogma.

    Your game's execution order is a lot more explicit and user defined. A lot of bugs I run into at my AAA day job somehow involve key sequences running out of order, or Null Reference Exceptions from variables that haven't been initialised yet.

    With "tons of monos sending tons of events" your call stack and / or execution order becomes a mess, especially if you throw in coroutines in too.

    No, the Constraints in EgoCS are just for Components on individual GameObjects. I've often thought about how SQL / LINQ style, general game state queries could be done while staying performant, but I've got nothing so far.

    I haven't done any extensive tests; I started writing EgoCS to stay busy right after I graduated and was on the job hunt. The most expensive operations are performed immediately on startup, and there shouldn't be too much overhead on any given operation at runtime. But, like with anything worth doing, it should be in moderation.

    Half the reason for rolling my own bitmask implementation was for slight performance gains, but the other half was to make sure only one Component of any given type was attached to a GameObject.

    Nope. I've used Behaviour Trees extensively at my day job and I'm not a fan. Even after I finally understood them, I found them hard to debug. I think I'd have a better and easier time with an ECS and straight-up if / else statements.

    Well, the "T" in HasComponents(params T p) would be System.Type, so if I wanted to make sure you only passed in Component Types, I'd have to assert at runtime if you did something silly like pass in "typeof(GameObject)" or "typeof(float)". By (ab)using generic type parameters, I can make sure you only specify Component Types at compile time.

    Plus this is less to type:

    egoComponent.HasComponents<Transform, Rigidbody, Pause>()

    than this:

    egoComponent.HasComponents(typeof(Transform), typeof(Rigidbody), typeof(Pause));
     
    laurentlavigne likes this.
  44. bayganik

    bayganik

    Joined:
    Jan 30, 2017
    Posts:
    12
    Hey Andoowhy,

    I am trying to create another example game using playing cards. How can I detect OnMouseDrag() or any other events that detect drag and drop operations?

    I wrote a system to detect which card the mouse clicked on and that was an Input. But having a hard time with a drag/drop system. Any ideas?

    I want to drag a card to a discard stack (as an example).

    Do I handle drag with one system and drop with another?
     
  45. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    5,636
    if/else?! I'm lost after 3 levels of nesting, I turn everything into a state machine these days. GOAP had my heart until I saw how hard the GC chokes, influence maps seem well suited to ECS, max decoupling, arrays, threadable, it's just a non object way of thinking that takes getting used to.

    Yes, I had to create a data bus to get around this, which looks very similar to ECS, just not as flexible.

    That would be so powerful!
    I just ran some tests on the typical case of n objects distance check. Linq was fast enough, well, until I started calling .OrderBy, but I think it's like SQL: requests can be split in ways where you turn an O(n log(n)) op into multiple o(n).
     
  46. andoowhy

    andoowhy

    Joined:
    Dec 26, 2015
    Posts:
    24
    At the moment, OnMouse* MonoBehaviour events aren't translated into EgoCS events (yet). I'll add support for those soon™.
     
  47. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    5,636
    Better add support for EventSystems as they get masked by UI
     
  48. andoowhy

    andoowhy

    Joined:
    Dec 26, 2015
    Posts:
    24
    v1.2.0 is out, and it includes OnMouse* support @bayganik

    v1.1.0 added the Reorderable Event Queue. You can now reorder your Event Handlers, making them more deterministic.
     
  49. bayganik

    bayganik

    Joined:
    Jan 30, 2017
    Posts:
    12
    Hey Andrew,

    Thank you for the mouse events. There is a slight issue:

    A file called EgoInterface.cs in your top directory has the Brick example interface instead of a generic interface. This causes compiler issues.
     
  50. andoowhy

    andoowhy

    Joined:
    Dec 26, 2015
    Posts:
    24
    Fixed in v1.2.1. Sorry about that ._.
     
unityunity