Is it possible to create a protocol like this:
protocol SetupProt {
func setup()
}
then at the end of my didMove function, tell the app to run all the setup functions from all the subclasses that implement this protocol?
Or will I need to store references to all these objects that are implementing the protocol and iterate through them?
Currently I have that protocol in use right now.
Then I have a global array like this:
setups = [SetupProt] = []
I have subclass for "a platform" in my game. I subclass it in the XCODE editor. And within the aDecoder init function, I add that node to this global array...
I do this because the scene property is nil at this moment, so I can't access it yet, it hasn't finished loading I"m guessing.
At the end of my scenes didMove, I iterate through this array:
for set in setups { set.setup() }
And this gets the job done.
I'm wondering if instead of storing an array of all these objects, can I just tell the app: "Hey, run the setup function for anything that is implementing this protocol.
You are doing this in GameplayKit, so what you want to do is go through your components
entities.foreach{
($0.components.filter({$0 as? SetupProtocol != nil}) as? [SetupProtocol]).foreach{
$0.setup()
}
}
This will avoid having to attach notification listeners to every item that uses this protocol. Setup is usually a one and done type deal, so to have your instances "listen" for a message that is sent only once could end up being a waste of resources.
What is nice with gameplay kit is technically you do not even need the protocol, you could have a component that is designed for setup, then we can avoid the needless filtering,casting, and looping.
entities.foreach{$0.component(ofType:SetupComponent).setup()}
--Inside SetupComponent
class SetupComponent : GKComponent
{
func setup()
{
guard let entity = entity as? SetupProtocol else {return}
entity.setup()
}
}
You can then take things one step further, and create "buckets" for all your components. This will help you manage things a lot better.
let setupBucket = entities.flatmap{$0.components.filter({$0 as? SetupProtocol != nil})} as? [SetupProtocol]. //I may need to verify this syntax is correct when I get home, doing it from memory.
You could add things like a setup bucket, update bucket, etc, and all these are are arrays of each type of component. This way if you ever need to call a method on all entities of a given component type, you have the bucket you can run through. Of course you are going to have to properly manage the buckets, and make sure you add/remove when a component is attached/removed to/from an entity.
Now I seem to recall coming across an issue with components in iOS 10 where I had to make sub component classes because subclassing was not properly working, but I do not know the state of it in iOS 11. I can tell you that Scenekit builder components are broken in XCode 9, so I would avoid using this if you can for now (You are on Sprite Kit, I do not know if they broke it on Sprite Kit also)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With