Skip to content

Feature Request: abstract WrapperComponent class #88

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed

Feature Request: abstract WrapperComponent class #88

wants to merge 1 commit into from

Conversation

LinusVanElswijk
Copy link

In many cases, all a component has to do is hold just a single value.
Components of this type can feel a bit clunky, because you end up writing things like:

string name = entity.Name.value;
GameObject object = entity.GameObject.value;
int score += entity.PointValue.value;

The code becomes more concise when an implicit conversion operator is added to these Components:

string name = entity.Name; //implicitly converted to string
GameObject object = entity.GameObject; //implicitly converted to GameObject
int score += entity.PointValue;  //implicitly converted to int

I added the abstract WrapperComponent class to allow users to create these single value Components including the implicit conversion operator in a single line of code:

public class NameComponent: WrapperComponent<string> { }

This line of code is equivalent to the following:

public class NameComponent: IComponent
{
  public T value;

  public static implicit operator string(NameComponent component) 
  {
    return component.value;
  }
}

@sschmid
Copy link
Owner

sschmid commented Mar 25, 2016

Hey, nice :) You can definitely do that. I merged the part where the abstract classes are ignored to support the WrapperComponent. While the WrapperComponent might be nice I don't think it should be part of Entitas but rather part of your Entitas tool belt ;) Thanks, and I hope it's ok for you.
Changes will be in the next release.

@sschmid sschmid closed this Mar 25, 2016
@SvDvorak
Copy link

I've felt the same way, very nice solution and I'm definitely going to use it myself. Thanks @LinusVanElswijk

@sschmid
Copy link
Owner

sschmid commented Mar 30, 2016

@LinusVanElswijk I updated the wiki with your WrapperComponent
https://github.com/sschmid/Entitas-CSharp/wiki/Tools-and-Extensions

@JamesMcMahon
Copy link
Contributor

JamesMcMahon commented Apr 24, 2016

@sschmid I wonder if this would fit better into the Entitas project is it was a modification to the code generator. IE, for single field components, generate a convenience accessor that you can call off of an entity. Thoughts?

If you think it would fit in the project It's something I can look into once I get some spare time.

@JamesMcMahon
Copy link
Contributor

Though instead of another accessor it would probably be better to just add an extension to the component class located in the generated component code.

@sschmid
Copy link
Owner

sschmid commented Apr 25, 2016

I was thinking about modifying the code generator to achieve this, but my main argument why I didn't do it was: If you add another field to the component, lot's of places in your code won't compile anymore.

@JamesMcMahon
Copy link
Contributor

JamesMcMahon commented Apr 25, 2016

Hmm, yeah I understand your concern.

Maybe if it was an field attribute:

XComponent : IComponent
{
    [Entitas.CodeGeneration.ImplicitField]
    public int foo;

    public string otherNonImplicitField;
}

Or maybe if it was a Ruby on Rails style convention over configuration approach:

XComponent : IComponent
{
    // value is a magicial field name that gets turn into an implicit field
    public int value;

    public string otherNonImplicitField;
}

That way you could keep your code working when you added a second field.

Thoughts?

@sschmid
Copy link
Owner

sschmid commented Apr 25, 2016

It's maybe the very first time I wouldn't actually mind some magic :)
I can give it a try with value being a magic field name :)

I only see 1 problem:

public class ScoreComponent : IComponent {
    public int value;
}
var score = e.score;

How would you actually get the ScoreComponent from an entity now?

@JamesMcMahon
Copy link
Contributor

I would use the implicit operator method that Linus created. So

ScoreComponent score = e.score;
int scoreValue = e.score;
var scoreDefault = e.score; // this is a ScoreComponent

@sschmid
Copy link
Owner

sschmid commented Apr 27, 2016

I think it won't make it into Entitas by default for the following reasons:
Implicit casting is (you guessed it) implicit. I think in this case explicit > implicit.

int score = e.score; // returns score.value
var score = e.score; // returns ScoreComponent

(Almost) same code, different results, not a big fan of that.

Adding new fields in the future will also break this unless I add magic by reserving the field name "value" and treat it differently or I add a new Attribute for the code generator.
Again, I think explicit > implicit > magic.

But of course you can still use the WrapperComponent or easily add a custom code generator to get the result you suggested. But I'll push this responsibility to the application layer and away from Entitas ;)

@JamesMcMahon
Copy link
Contributor

JamesMcMahon commented Apr 27, 2016

I understand your concerns @sschmid. I think the convenience would be nice, but it could lead to weird errors / bugs if the users weren't wary of it.

Thanks @LinusVanElswijk for the WrapperComponent. I will use that in future projects.

@jwvanderbeck
Copy link

Thanks @LinusVanElswijk this is very nice!

@sschmid In regards to your concerns, I would argue this is an example of why using var is a bad habit. I never use it personally unless I absolutely have to.

@zehreken
Copy link

zehreken commented Feb 5, 2018

I liked this idea for simple components, like Name, Info or Score etc. But when I create the NameComponent like this;
public class NameComponent: WrapperComponent<string> { }
it is now generated as a boolean component since the body of the class is empty. Is there another attribute to force it to be generated as a 'normal' component?

@jwvanderbeck
Copy link

jwvanderbeck commented Feb 5, 2018

Are you using the Rosyln generator? It was broken in there at one point, though should be fixed now if the asset store has updated.

#532

@zehreken
Copy link

zehreken commented Feb 6, 2018

Yes, you're right I'm using the external generator. Unfortunately your answer showed me that I got bigger problems, if I auto-import inside Unity, I can generate with Unity but not with Roslyn. If I auto-import in Terminal, I can generate with Roslyn but not with Unity. :( Is that normal?

@jwvanderbeck
Copy link

Yes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

6 participants