Entitas icon indicating copy to clipboard operation
Entitas copied to clipboard

More flexible AddComponent/ReplaceComponent methods

Open ianeinman opened this issue 4 years ago • 4 comments

If you have a component with multiple member variables, the AddComponent and ReplaceComponent methods require specifying every single member.

[Game]
public struct ExampleComponent : IComponent {
   public Vector3 Position;
   public Quaternion Rotation;
   public int Layer;
   public bool Visible;
}

When I first started using Entitas I expected that I would need to create the component and add it. But instead you need to do this:

   entity.AddComponent(newPosition, newRotation, newLayer, isVisible);

The problem is this can be tedious if some of the values should default to false/null. If you supported the ability to take ExampleComponent as a parameter, I could do this:

   entity.AddComponent(new ExampleComponent() { Position = newPosition });

Or alternatively define my own constructors (if it is a class not a struct).

I like the existing syntax for some cases, but in other cases it is not a fit. So I'd actually like flexibility by having an attribute for the class that defines how the signature of AddComponent/ReplaceComponent work.

ianeinman avatar Nov 23 '19 10:11 ianeinman

You doing all wrong. If you need to change part of component, then you need new component, that will be part of previous component.

public class PositionComponent : IComponent {
   public Vector3 Value;
}
public class RotationComponent : IComponent {
   public Quaternion Value;
}

public class LayerComponent : IComponent {
   public int Layer;
}

public class VisibleComponent : IComponent {}

And use classes.

WeslomPo avatar Dec 26 '19 15:12 WeslomPo

Generally I agree with @WeslomPo , in this case it makes sense to split the components into smaller ones which will increase the reusability of those components.

There might be other components where you don't want to do that, in this case just extend the partial entity class with your custom addition of a Add and Replace method.

partial class GameEntity
{
    public void AddPosition(float x) {
        AddPosition(new Vector3(x, 0, 0));
    }

    public void ReplacePosition(float x) {
        ReplacePosition(new Vector3(x, 0, 0));
    }
} 


// somewhere else
e.ReplacePosition(2.5f);

sschmid avatar Apr 25 '20 17:04 sschmid

Sorry I didn't follow up on this earlier. I understand WeslomPo's point but the thing is, my example was just made up as an illustration, and I think it was a poor example, because it just led people to questioning why anyone would ever want to do such a silly thing.

Let me try again. This time, I will actually use the example of WeslomPo:

public class PositionComponent : IComponent {
   public Vector3 Value;
}

Now, when I add a PositionComponent, I need to add a Vector3. Because this is a position, maybe I actually want to supply the position by giving it a name or enumeration, like Cities.NewPhoenix, which it will then look up the position in some other place, and turn it to a Vector3.

However, in this example, Vector3 is not my class, I didn't make it. I cannot make a constructor for Vector3. I can create a constructor for PositionComponent, but this does no good because AddPosition() does not accept a PositionComponent, it accepts the members of PositionComponent which is a Vector3 in this case.

I know that there's other ways to do it, such as just making a static method to convert, but it just seemed like it should not be difficult to make versions of AddXXX and ReplaceXXX that took an actual PositionComponent instead of the members of position component. That's why I asked for an attribute to do this for convenience.

Being able to define this conversion right in PositionComponent is convenient as it keeps the code together with the single class where it is used.

Now, there may be implementation issues that make this not possible, for example maybe the underlying data structure never actually creates or uses a real PositionComponent. But if it is possible, my request stands, even though I do know there's workarounds. Thanks.

ianeinman avatar Jun 14 '20 08:06 ianeinman

Very hard to understand real application of your demand (maybe my translation skill not enough :) ). Can you provide a fake code example? By the way, may real components looks like this: image

If I understand right, you trying make something that not intended to be created like this.

For example, if you want to take position of something like city by some kind of id, you need to get that position somewhere first place. Where did entity can get that position, even if you pass id for that? Entity does not know about all cities, entity is just a ONE ROW of DATA. So, if you want to get data for particular ID and that data stored in entitas, it actually stored in CONTEXT. Context - are TABLE of ROWS (array of entities). You can't make components doing complex work, their responsibility are storing one row of data.

To make contexts made complex work for you you have two options:

  1. Make partial class for that context.
  2. Create extensions method for context - I think this is more convenient work to do that.

WeslomPo avatar Jun 15 '20 07:06 WeslomPo