Search Unity

  1. Unity Asset Manager is now available in public beta. Try it out now and join the conversation here in the forums.
    Dismiss Notice
  2. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  3. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

a question about best practice for using components data

Discussion in 'Project Tiny' started by gamayun, May 13, 2019.

  1. gamayun

    gamayun

    Joined:
    Nov 20, 2012
    Posts:
    34
    Hi all,

    I was wondering which way is most optimzed when I have the choice to use:

    1) usingComponentData like in:

    this.world.usingComponentData(myEntity, [myComponent], (e) => {
    // blabla
    });


    or 2) get/setComponentData like in:

    let someComponent = this.world.getComponentData(myEntity, myComponent);
    // blabla
    this.world.setComponentData(myEntity, someComponent);


    Cheers,

    Thierry
     
  2. Ferran_SP

    Ferran_SP

    Joined:
    Jul 9, 2018
    Posts:
    27
    I can't speak about optimization and details, but in the Project Tiny Workshop videos it's said that "we can do world.getComponentData and then world.setComponentData, but it's much easier to just wrap that together in world.usingComponentData".
    So, at least you know that in that Unity video a) they seem to not care about using one over the other for performance, and b) recommend using world.usingComponentData for simplicity.

     
    gamayun likes this.
  3. Rupture13

    Rupture13

    Joined:
    Apr 12, 2016
    Posts:
    129
    usingComponentData uses the other two statements internally, so the performance there would be the same. Simplicity is then a reason to use it.

    The only reason you wouldn't want to use it (that I can think of) is that usingComponentData uses an anonymous inner function, which you might want to avoid at times.

    For example:
    Code (CSharp):
    1. OnUpdate(): void {
    2.     this.world.usingComponentData(myEntity, [myComponent], (e) => {
    3.         //Example return 1
    4.         return;
    5.     });
    6.  
    7.     let someComponent = this.world.getComponentData(myEntity, myComponent);
    8.     //Example return 2
    9.     return;
    10.     this.world.setComponentData(myEntity, someComponent);
    11. }
    The return in the first block ("Example return 1") will not return out of the OnUpdate() method, only out of the inner function from usingComponentData.
    The return in the second block ("Example return 2") will return out of the OnUpdate() method.

    So all in all, usingComponentData is usually simpler to use, but if you use that you should know what the inner function means and what it does.
     
    Last edited: May 13, 2019
    gamayun, Ferran_SP and Zionisias like this.
  4. reallyhexln

    reallyhexln

    Joined:
    Jun 18, 2018
    Posts:
    69
    This is my IMHO for this question:

    1) usingComponentData
    + auto-save all changes in specified components - less mistakes when you missing setComponentData after making changes;
    + less code: there is no sense, how many components you will update - there is one call of usingComponentData to update all of them + there is no needing to check if some component exists - usingComponentData creates it automatically with default values:
    Code (JavaScript):
    1. world.usingComponentData(entity, [A, B, C], (a, b, c) => {
    2.     ...
    3. });
    vs
    Code (JavaScript):
    1. let a = world.hasComponentData(entity, A) ? world.getComponentData(entity, A) : new A();
    2. let b = world.hasComponentData(entity, B) ? world.getComponentData(entity, B) : new B();
    3. let c = world.hasComponentData(entity, C) ? world.getComponentData(entity, C) : new C();
    4. ...
    5. world.setComponentData(entity, a);
    6. world.setComponentData(entity, b);
    7. world.setComponentData(entity, c);
    - it has potentially worse performance - it calls setComponentData for all specified components even if you don't make changes in their data
    - it can't be used in code where you explicitly removes component on the entity - it can lead to runtime errors:
    Code (JavaScript):
    1. world.usingComponentData(entity, [A], (a) => {
    2.     // do something useful
    3.     ...
    4.     world.removeComponent(entity, A); // ooops
    5. });
    in such code you have remove component A in usingComponentData callback, when this callback has been finished, usingComponentData will try to call setComponentData() for component A which is not existing that will lead to runtime error.

    At the same time you can easily avoid such error with the following code:
    Code (JavaScript):
    1. let a = world.getComponentData(entity, A);
    2. // do something useful
    3. ...
    4. world.removeComponent(entity, A); // ok
    5. if (world.hasComponent(entity, A)) {
    6.     world.setComponentData(entity, a);
    7. }
    Such example seems artifical but I encounter such issue very often in the real code.

    2) getComponentData + setComponentData:
    + code is more understandable comparing with usingComponentData
    + better control - you can decide when setComponentData must be called (and whether at all)
    - too many boilerplate code - checking for component presence / explicitly calling of getComponentData and setComponentData for each component.
     
  5. gamayun

    gamayun

    Joined:
    Nov 20, 2012
    Posts:
    34
    Thank you very much guys for your answers

    reallyhexln... really excellent as usual :)
     
  6. reallyhexln

    reallyhexln

    Joined:
    Jun 18, 2018
    Posts:
    69
    Guys, I made a mistake, and Pakor has corrected me.
    Instead of:
    Code (JavaScript):
    1. let a = world.hasComponentData(entity, A) ? world.getComponentData(entity, A) : new A();
    you of course can use:
    Code (JavaScript):
    1. let a = world.getOrAddComponentData(entity, A);
     
    gamayun likes this.
  7. Zionisias

    Zionisias

    Joined:
    Apr 23, 2019
    Posts:
    40
    Hey reallyhexln,

    You can edit your posts, so you can include this change within your anwser. This might be usefull for people who don't scroll completely down ;).