It depends how you want to structure your components. Like you said its best to keep them as flexible, reusable and independent of each other as much as possible.
So I would just create a simple render component like you want to. This is what I use in my games.
import SpriteKit
import GameplayKit
/// GK sprite component
class SpriteComponent: GKComponent {
// MARK: - Properties
/// The rendered node
let node: SKSpriteNode
// MARK: GKComponent Life Cycle
/// Init with image
init(imageNamed: String) {
node = SKSpriteNode(imageNamed: imageNamed)
}
/// Init with texture
init(texture: SKTexture) {
node = SKSpriteNode(texture: texture)
}
}
In your entity classes you add the component as usual
class Player: GKEntity {
override init() { // pass in an image name if you need to
super.init()
let spriteComponent = SpriteComponent(imageNamed: "Player")
addComponent(spriteComponent)
}
}
Than you add the entity to the scene and position it.
Once a component is added to an entity you can use the component(ofType: ...) method to access its properties, in this case the node property, and do something with them.
class GameScene: SKScene {
// code to add entity to scene
...
// position entity
if let playerNode = player.component(ofType: SpriteComponent.self)?.node {
playerNode.position = CGPoint(...)
}
Go back to your entity class and add the physics body after you added the sprite component.
...
addComponent(spriteComponent)
// Set physics body
if let sprite = component(ofType: SpriteComponent.self)?.node { // component for class is an optional and nil until component is added to entity.
sprite.physicsBody = SKPhysicsBody(...
sprite.physicsBody?.categoryBitMask = ...
...
}
This way all your entities can use 1 render component but have different physics bodies on them and use different positions.
You could create a physics body component and pass into the init method the bit masks etc and the node you want it to be added to. However I think thats makes it quite messy so I prefer this way.
If you do need to make components dependent of each other remember that each GKComponent has an entity property you can use. I would try to avoid this as much as possible to keep your components more flexible.
class SomeComponent: GKComponent {
func test() {
entity?.component(ofType: SomeOtherComponent.self)?.someMethod() // only works if this component is added to entity (entity?) and the other component is also added to entity (...self)?.
}
class SomeOtherComponent: GKComponent {
func someMethod() {
}
}
If you need more info you should read these articles, they are very good.
https://www.raywenderlich.com/119959/gameplaykit-tutorial-entity-component-system-agents-goals-behaviors
http://code.tutsplus.com/tutorials/an-introduction-to-gameplaykit-part-1--cms-24483
Hope this helps