1
\$\begingroup\$

I'm writing a SpriteKit game in swift and making use of GameplayKit's entity-component system. There are many components that do different stuff but share the same methods in which they do it, so I thought I'd group them into categories. At first I thought about using protocols, but component(ofType:) only accepts classes. So then I thought about making a base class for each category, define methods and variables there and have the actual components classes override them to implement their own functionality (you know like basic OOP). So I had something like:

class InputComponent: GKComponent {
    func handleInput() {
        //Whatever
    }
}

class ControllerComponent: InputComponent {
    override func handleInput() {
        //Do something
    }
}

class KeyboardComponent: InputComponent {
    override func handleInput() {
        //Do something different
    }
}

Then somewhere in my code I'd call

entity.component(ofType: InputComponent)

and I thought I'd get both ControllerComponent and KeyboardComponent type objects. But I am getting none, it seems component(ofType:) doesn't return instances of subclasses.

I guess I can make an extension to GKEntity and define something like

component<P>(conformingTo protocol: P.Type)

and implement that behavior myself but I want to know if I can use the built in function to achieve the same.

\$\endgroup\$
1
\$\begingroup\$

Well it appears as if no one here seems to know it so I'll just post what I used which is a new method that I added in an extension to GKEntity (which I was actually trying to avoid)

extension GKEntity {
    func component<P>(conformingTo protocol: P.Type) -> P? {
        for component in components {
            if let p = component as? P {
                return p
            }
        }

        return nil
    }
}

Actually you can pass not only protocol types as an argument, you can actually pass any type (like classes) - so actually the results are similar to the native method provided by Apple, though I am not sure how similar these are so I wouldn't use them interchangeably, I use it solely for when I need to get a GKComponent that conforms to a protocol instead of a specific type of GKComponent.

\$\endgroup\$
  • \$\begingroup\$ Thanks for sharing! Are there any concerns about having multiple components that all conform to the same protocol on an entity and only getting back one? I'm not sure if the component(ofType) one has similar issues, but it seems like this approach could exacerbate it at the very least. \$\endgroup\$ – idolize Nov 19 '18 at 3:05
  • \$\begingroup\$ Well this function will just return the first component conforming to the protocol, ignoring any other components conforming to the protocol. But you can just make an array (or a set), add any component conforming to the protocol to the array, and return that instead. \$\endgroup\$ – lsauceda Nov 24 '18 at 14:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.