I am currently building a game and I want to use Gameplaykit to organise the elements.
I discovered the concept of ECS (Entity Component System) that enables to put functionality in small blocks (called components) that can than be added to an entity to give it functionality.
I would like to use it combined with SpriteKit, my first idea was of course to create a SpriteComponent, but since I am also using the physics engine of SpriteKit, I am wondering how I should make the PhysicsBodyComponent, because for this component to work it would need direct access to the physics body of my SpriteKit node, so it would be dependent of the SpriteComponent, but isn't it wrong for components to be dependent on each other ?
How should I do that ?
Thank you.
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.
http://code.tutsplus.com/tutorials/an-introduction-to-gameplaykit-part-1--cms-24483
Hope this helps