Entity Component First Impressions

I have been looking at the new Entity / Component pattern this afternoon, although I like the concept it is proving to be difficult to work with. My first concern (and this particularly applies to spriteKit) is that the majority of the existing API is designed around the concept of working with SKNodes. The first issue that I hit was that when specifying an SKNode there is no way to find its associated entity, I appreciate that you can work round this (the DemoBots example shows how) but it just feels clunky. I am slightly concerned that after all the effort of designing the demo in a modular component fashion that decoupling is somewhat reversed by having to twist everything back into the SKNode way of working

Even though the projects I work on are small I can appreciate that entity/component could be a useful pattern to compartmentalize logic but I also worry that the pattern brings with it a fair bit of complexity (especially in terms of communication between components) that might not be justified for a small project / solo developer when compared to a simpler more monolithic design.


Gary.

For simple projects, it might not be worth it. The docs indicate that this is something to help with complex projects.


I agree that it is awkward that there isn't a connection between SKNode or SCNNode and entities. But since GKEntity is applicable to both, I can understand leaving that in the developer's hands. What I found interesting about that, though, was that the sample code has the GKEntity owning the node. One could go the other way, and have the SKNode or SCNNode own the GKEntity. I do not know if one direction is clearly better than the other or not.


I will also point out that, while SKNode is serializable, GKEntity, GKComponent, and GKAgent are not. That means it might be tricky to restore a saved game to exactly the state it was saved in. One can add serialization to custom GKEntity or GKComponent subclasses, but you can't usefully subclass or inspect GKAgent and friends.

What I started doing is, instead of building around SKNode, I build around GKEntity and GKComponent. I encapsulate an SKNode object in a VisualComponent class and add that component to the entity. This code is still a little rough, but it's a start:


class VisualComponent: GKComponent {
    var node: SKSpriteNode

    init(imageNamed image: String, scene: SKScene) {
        self.node = SKSpriteNode(imageNamed: image)
        self.node.anchorPoint = CGPointZero
        self.node.xScale = 0.35
        self.node.yScale = 0.35
        self.node.position = CGPoint(x: 0.5*scene.size.width, y: 20)
  
        scene.addChild(self.node)
    }
}


Then to create a node in the scene I do this:


var player = GKEntity()
self.player.addComponent(VisualComponent(imageNamed: "Player.png", scene: self))


If I need to, I can also customize the node from the scene:


self.player.componentForClass(VisualComponent)?.node.xScale = 0.35
self.player.componentForClass(VisualComponent)?.node.yScale = 0.35


Here's where I'm uncertain. I'm not sure if it's ok to try to access an entity's component from another component. For example:


class VerticalMovementComponent: GKComponent {
    init(scene: SKScene) {
        super.init()
       
        let node = self.entity?.componentForClass(VisualComponent)?.node
        node.position.x = CGFloat(0.5*scene.size.width)
        node.position.y = scene.size.height+20
        node.zRotation = CGFloat(M_PI)
      
        node.runAction(SKAction.moveToY(-10, duration: 5))
    }
  
    override func updateWithDeltaTime(seconds: NSTimeInterval) {
        let node = self.entity?.componentForClass(VisualComponent)?.node
      
        if node?.position.y < -5 {
            node?.removeFromParent()
        }
    }
}


While this code does do what I need it to, I'm not sure if it's really safe.

One quick issue I see with your code is that you are adding the sprite into your scene automatically. This makes it impossible to create hierarchical node structures, e.g., a ship with a base sprite for the body and child sprites for gun turrets that can rotate independently.


I have the same questions as you about components accessing and modifying the state of other components. I don't want to duplicate state (like position for the sprite and position for a path following component), but having one component access another's state seems like way too tight coupling. On top of that I see potential for circular references leading to memory leaks, etc.


One of my biggest issues is the one mentioned by FuzzyGoat: If an entity owns a sprite (which seems natural) then a lot of the SpriteKit way of doing things becomes difficult. For instance, how do we handle touch events on sprites if we can't easily propagate them to the owning entity? We can use the userData field of the sprite to store the parent entity, but that leads to potential memory leaks as well. Then there is the issue that physics can't be easily managed by a component since physicsbodies are so tightly coupled to SKSpriteNodes.


It seems like a lot of the convenience features of SpriteKit (attaching SKPhysicsBody to SKSpriteNode, SKSpriteNode receiving touch events, etc.) make it difficult to create a good component/entity framework.

As I mentioned, I've gone the other way: the sprite creates the components that it needs. This lets me do dependency injection into each component. Basically, everything outside of itself that a component uses—its dependencies—should be given to it in the constructor. I am using Swift, so I am giving each component unowned references to its dependences to prevent retain cycles. These dependencies include both inputs (e.g., a component depends on a state-holding component to make its decisions) and outputs (e.g., a component sets state of downstream components or uses a separate component to implement its results).


As part of the dependency injection, I sometimes initialize a component with a closure (or block) so that it can perform some job as a black box function call. The sprite supplies the closure, because the sprite actually knows how to do the thing, the component just calls the closure. I may also need to use other forms of dependency injection (provider objects or maybe delegates) later on in this game's development.


I find some inspiration in this diagram: https://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html. In general, the thing closest to the "outside world" (e.g. an input handler or sprite) calls on the "inner" thing (e.g. some sort of model object). But the order in which you create these things depends on whether you are doing dependency injection via constructor or via property-setting. If you do it via constructor, you have to create the "inner" things first. If you do it via property-setting (like adding components to a sprite's entity), you have to create the "outer" things first.

@_Agent (others)


Thanks for the write up. I'm beginning learning programming in SpriteKit (as seasoned ux developer on big brand/high end projects/featured apps). Before I roll my sleeves up in writing too much tangled up code/schoolboy code - I've been reading allot about clean architecture from Uncle Bob to various topics spanning across; single point of responsibility, seperations of concerns (mvvm/binding/router style), DI frameworks in SWIFT, 130 line class rules, testing, protocol/value orientated programming, flow controllers/co-ordinators, composition patterns, Redux/flux style architecture for iOS, avoiding massive view controllers (general paradigm approach) for background reading/learnings (Which is enough of a challenge in its own right for a kinda newbie!)


Hence to summarise; your post, was refreshing to read as I'm strugglerling to find any resources, example projects or best practices within scalable SpriteKit projects to begin to understand as the most basic level its design patterns (or good patterns to adopt within or using Apples SK/GK offerings). Whilst I appreciate there is no silver bullet, I would be very interested to any updated thoughts you (or others) may have? or approaches/best pratcices you've through 'the school of hard knocks!'


I only stumbled across this forum posting by trying to google SpriteKit + dependency injection, hence reaching out to this disucssion to see if anyone can point me in the right direction of best practices architecture/design patterns/examples using SK..


thanks in advance!

Marcus


PS: for anyone willing to breakout discuss code examples in further detail ; Would be very happy to return the favour in anyway I can by reviewing anything you want relating to visual/motion/app/ux/game flow (in the form of) brutal honest feedback or from anything else to my best practices/opinions in managing areas of ux/component design/artwork components workflows I've anally adopted in my design/ux/animation/automation plugins/ 'life so far' through highly reusable granular/linked/states/comps/multi-document/linked design file structures! (personal email: myUserName at gmail Dot com)

Entity Component First Impressions
 
 
Q