Search code examples
sprite-kitgameplay-kit

Should a GKEntity have properties or methods to access a component's features?


I'm trying wrap my head around game entity systems and using GamePlayKit. I'm struggling with the following scenario:

  • RenderComponent is a GKComponent that references an SKSpriteNode to show my entity.
  • MetaDataComponent is another component that holds various bits of information about an entity (like in my case, this would contain properties like MapX, MapY, ...)

I have a CharacterEntity that derives from GKEntity.

To initialise my entity, I pass the name of the texture to use for the sprite. This allows me to create the RenderComponent.

To initialise the MetaDataComponent I have three options and I wonder if one of them is considered best practice (and also, which one is worst practice)?

  • For every property in my component, add a parameter to the init()
  • Expose properties in the Character class which will update the properties of the component.
  • Pass a model object to my entity and initialise the component from that.

My thoughts:

  • Number 1: the more components my entity has, the more params I get...this is not really my preference.
  • Number 2: an entity should be "stupid" and not carry any data. In it's purest form, an entity is just a number. Adding props in there "feels" wrong.
  • Number 3: having a model object like MetaData to me feels best but also redundant because data is then in the component and in the model object. Maybe have the component store the model object instead of its properties?

To give another example: if I expect an entity to have a RenderComponent, I can query for that component and use it. Or I could add a method to the entity itself, like setRenderPosition which checks for existence of the required component and updates it. Again the question is, whether there's a right or wrong here in doing this?


Solution

  • If you're looking for pure Entity Component System then the design consists of three parts:

    Entity: Which is as you say, just a number. Nothing else.

    Component: Which is just data. Nothing else.

    System: The forgotten part. This is where the logic sits. You can inherit from GKComponentSystem<GKComponent> to create your own systems in SpriteKit.

    This article and it's supporting code helped me a lot in understanding ECS. The DemoBots example is another one to look at for a spriteKit oriented implementation.

    Since SpriteKit has it's own implementation of ECS and other quirks, some compromise is necessary I believe e.g. you need to render a node, so if you want a SpriteComponent, then you'll need to embed the node into the SpriteComponet or do something else - I preferred not to have a SpriteComponent, I created a VisualEntity that inherits from GKEntity, but that's my preference to focus on components that have behaviour that depends on the update run loop.

    To answer your question about properties on entities, it doesn't seem necessary, since you can query the entity for any component you need access to.

    guard let spriteComponent = entity?.component(ofType: SpriteComponent.self) else {
       return
    }
    

    The important thing is to be flexible, fit in with SpriteKit and be aware of the compromises you are making.