Search Unity

ECS-Tween: A very simple tweening system using ECS that works with GameObjects

Discussion in 'Entity Component System' started by Xerioz, Jun 15, 2018.

  1. Xerioz

    Xerioz

    Joined:
    Aug 13, 2013
    Posts:
    104


    What would be the most useful thing to do in Unity that can benefit enormously from ECS? A tweening library!

    I dedicated some time trying to come up with a way of interpolating GameObjects through entities.
    This is a really simple setup, more of a proof of concept kind of thing.
    I'm still getting used to Unity's ECS architecture.

    Here's the github repo link: https://github.com/Xerios/ECS-Tween

    I'd love to hear you guys out how this could be further improved. Any ideas?
     
  2. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    I have a similar 2D tween library I would like to convert to ECS, if only they allowed me to change Sprite's color, change Sprite's image, set .enabled, and evaluate curve from thread... the 4 missing things I would like to use. Also currently TransformAccess has no effect on those with RectTransform.
     
  3. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Awesome! I've been thinking of making a jiggle bone thing and attachment system myself.
     
  4. dadude123

    dadude123

    Joined:
    Feb 26, 2014
    Posts:
    789
    Nice work, I can see ECS tweening libraries becoming a big thing in the future.
    Quick question, why are TweenTime and TweenLifetime split?
    I see you have TweenLifetime as readonly in the system, does that make any big difference? What is the reason for that? Not really sure about that and I feel like I'm missing something important here.

    Here's something you might find interesting:
    I made a custom tweening system in the past that does code-generation to support any basic property type (float, Vector3, ...). For example it simply generated C# source text to automatically create "Tweeners" for selected classes/properties. For example if you select "UnityEngine.Image + Color Color"; it would write out a .cs file containing all the code to tween the color of an UI image + some extension method to quickly schedule a tween.

    That's an easy way to avoid having to explicitly support every type + property combination there is.
    Maybe that could be interesting for you as well. Just have a simple EditorWindow dialog Unity where you can select the type + properties and it generates .cs files with the needed IComponentData's and Systems.
     
  5. Xerioz

    Xerioz

    Joined:
    Aug 13, 2013
    Posts:
    104
    The reason why I split TweenTime and TweenLifetime is because they're read/written differently.

    TweenLifetime: only read by TweenNormalizedTimeSystem and TweenRemoveSystem.
    TweenTime: written by TweenNormalizedTimeSystem, optionally read/written by TweenEasingExponentialSystem and eventually read by TweenPositionSystem.

    Obviously this may not be the best approach if there's no real gain by splitting them up, but I haven't tested that out yet.
    I wanted to keep things separate by the systems that use them.

    One of the things I was thinking of doing was to have another component type that was basically TweenTimeEvaluated, which was the result of whatever easing component you used. I just happened to settle on something that didn't use that, because I thought that having a TweenEasingLinearSystem would be pointless.

    Doubt that code generation would help. My idea was to create different types of systems that handle different tweens.
    For instance, if we wanted to use rotation as well, we would create a new TweenRotation type and use TweenRotationSystem which would handle the transforms. Same goes for any other tweens ( like UI and the rest ).

    ---

    I do have have some issues with order though, like for example :
    I can't seem to get CopyTransformToGameObjectSystem to execute as last, so I imagine that creating my own version based on their source would be the way to go.
     
  6. sathya

    sathya

    Joined:
    Jul 30, 2012
    Posts:
    297
    @Xerioz.
    Awesome work. This is something going to be huge and mainstream. Have you considered adding callback events Like OnStart, OnFinish, OnUpdate
     
  7. Necromantic

    Necromantic

    Joined:
    Feb 11, 2013
    Posts:
    116
    Do you need it to be UI based? Else you could check out my ECS SpriteRenderer Example that supports coloring.
    https://github.com/Necromantic/ECS-Sandbox mentioned in this thread: https://forum.unity.com/threads/instanced-sprite-renderer-example.525235/
     
  8. Xerioz

    Xerioz

    Joined:
    Aug 13, 2013
    Posts:
    104
    I've been at Unite these last few days, and only yesterday they announced their new Reactive Systems for ECS which would make OnStart/OnFinish easily integratable. OnUpdate is already possible, as long as you're doing it in ECS way.

    Unfortunately I haven't really looked into callbacks yet. At this moment, I'm not sure if it can be achieved while maintaining a proper linear memory layout.
     
    sathya likes this.
  9. sathya

    sathya

    Joined:
    Jul 30, 2012
    Posts:
    297
    @Xerioz Hope you are having a good time at Unite.
     
  10. Xerioz

    Xerioz

    Joined:
    Aug 13, 2013
    Posts:
    104
    It was a... messy experience, but good overall.

    upload_2018-6-24_16-2-49.png

    Anyhow, small update:
    - I've included Rotation tweening and it works nicely with position tweens,
    - Did a small refactor and no longer use parallelfor ( no big advantage of using that, plus it required a lot more boilerplate code which wasn't really nice to look at )

    At this moment, I create an entity for each tween and to my surprise, having two entities linked to a GameObject worked out of the box!
     
  11. Xerioz

    Xerioz

    Joined:
    Aug 13, 2013
    Posts:
    104
    I was thinking, perhaps there's a better way of doing this.

    Creating new entities per tween doesn't sound like a good approach, but maybe someone can shine some light on this.

    Also, I'm having issues with tweening where my tween gets removed too early. Any ideas how to ensure that I only delete my entities AFTER certain systems have ran ?
     
    Last edited: Jun 24, 2018
  12. dadude123

    dadude123

    Joined:
    Feb 26, 2014
    Posts:
    789
    Creating an entity per tween is optimal because entities themselves are only the sum of their components.

    So the only thing being created is the component(s) needed to save the information of the tween.

    Dont think of entities as normally allocated .Net objects! There is zero overhead for them.
     
  13. Xerioz

    Xerioz

    Joined:
    Aug 13, 2013
    Posts:
    104
    I understand that, but in cases of having multiple tweens. My issue is the fact that I have CopyTransformToGameObject executed twice, for the two tweens, since I have two entities. This could be avoided with only one entity approach.

    Say for instance, in a perfect example, I would do position and rotation tween, with same TweenTime, TweenLifetime and TweenEasingExpIn, CopyTransformToGameObject and the only thing being different is the two componentTypes PositionSystem and RotationSystem. So far, I'm still not sure how to achieve this.
     
  14. Xerioz

    Xerioz

    Joined:
    Aug 13, 2013
    Posts:
    104
    Sad to see some lack of professional input for ECS related stuff around here, but anyhow: I managed to make the system update order work properly.

    upload_2018-7-3_9-47-36.png

    Also added Exponent Out easing type
     
    Last edited: Jul 3, 2018
  15. Xerioz

    Xerioz

    Joined:
    Aug 13, 2013
    Posts:
    104
    Something strange that I noticed, the moment I start killing off my entities, my
    IJobParallelForTransform
    starts taking an abnormal high amount of performance on the main thread.

    You can clearly see the difference between before tweens are completed ( left ) and after ( right ).

    upload_2018-7-3_10-39-42.png

    My transform update code is pretty much a copy/paste of
    CopyTransformToGameObjectSystem
    from
    com.unity.entities@0.0.12-preview.8


    Any ideas why?
     
  16. dadude123

    dadude123

    Joined:
    Feb 26, 2014
    Posts:
    789
    I guess people like to use ECS for everything so they never even have to leave that framework, so there's no need to have any sort of data-management like this at all.

    Interacting with GameObjects and Transform components will already give you a performance hit, compared to converting your GameObjects into ECS entities+components.

    I mean, how many objects do there even need to before and ECS gives you better performance?
    We know it scales really well with lots of objects.
    But what about 1,2,3,4,5,10,20 objects? Is ECS still faster in total compared to MonoBehaviours? Has anyone tested that yet?
    In this particular use case that should be relatively easy to test.
     
  17. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Pretty sure ECS by default is more efficient. As to if it's more efficient right now in early stage of dev, I don't know.
     
  18. Xerioz

    Xerioz

    Joined:
    Aug 13, 2013
    Posts:
    104
    If you understood what makes ECS better than OOP, you would know that ECS is faster by default because it takes advantage of how memory is used on the hardware level. At worst ( lets say one entity ), the performance is the same, and at best, it's more performant. It's as simple as that.

    It kind of surprises me that people are still questioning the efficiency of an ECS structure. I agree that it's harder than OOP approach because wrapping your head around a different way of programming is not an easy task, but damn, people, please do your own research.

    Unfortunately, I'm not gonna be the one to do a comparison so feel free to fork it and test your theories out :)
     
    hippocoder likes this.
  19. dadude123

    dadude123

    Joined:
    Feb 26, 2014
    Posts:
    789
    As for research:
    I did, in fact, do my research and used it for a few things as well already. And I'm not even saying that ECS isn't more efficient for many things. I'm well aware of how ECS works, but memory layout alone doesn't mean anything at all when you only have a single object. Sure its an extreme example, but that doesn't make it invalid!

    With a single object you still have to add up all the "setup" costs associated with ECS. Scheduling a job, syncronizing back with the main thread. Yes, that won't take long, but neither will calling Update() on a MonoBehaviour.

    So no, it is actually not "as simple as that". (sorry for that last comment but to me your post sounded really condescending, I know what I'm talking about)
     
  20. Xerioz

    Xerioz

    Joined:
    Aug 13, 2013
    Posts:
    104
    This discussion shouldn't exactly take place in this thread because I was hoping for someone to help me out with some advanced topics, ...but I'm gonna answer anyway:

    You don't have to use Jobs if you want to write ECS code.
    Here's an example of such a system: SyncTransformSystem.cs

    Jobs with ECS is equivalent of a safe mutli-threaded monobehavior script, which is far more lines of code than just a class with an Update() function.

    Obviously some simple scripts are better off written in OOP way, but that doesn't make ECS any worse, just different.
    ECS solves different problems, and has its use, that's the way I see it. Maybe I'm not enlightened yet, and perhaps everything could and should be written in ECS, and that once it clicks it becomes so easy that you would start looking down on the poor OOP peasants while spewing out 100's of re-usable systems every day, I don't know.

    Reason why I posted here is to seek for help, because I'm interested in this radical new way of thinking. I want to learn and see where this could lead me to. True that it's kind of ugly and hard to grasp, but we're still in early preview version.

    I'm not the guru you're looking for to debate your uncertainties, I'm just a passenger :)
     
    hippocoder likes this.
  21. Xerioz

    Xerioz

    Joined:
    Aug 13, 2013
    Posts:
    104
    If I add a SharedComponentData for lets say, callbacks, will this mess up the memory layout for every system or only systems that use this?
     
  22. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    863
    If you have different values in SCD it will fragment the chunks for everyone, since there is just one copy of all the data laid out in chunks, and each combination of components and also unique SCD values is a separate chunk.

    I would love to know what impact on performance exactly the chunk fragmentation has though. If anyone would benchmark that would be awesome. Best way to benchmark would be to use SCD to control fragmentation.