The subject
My question is about the division of the update cycle when combining Apple's frameworks in order to respect the typical patterns and good practices on the subject, since most of the documentation and example code has not been adapted to Swift yet (or at least I can't find it anywhere).
There are so many ways to manage the update cycles in GameplayKit that I'm not too sure what is a good way of combining everything.
The elements
First and foremost: every class (GKComponent
and GKEntity
(sub)classes) in the Entity/Component has an update()
method that you can override to perform per-frame updates. That has to come from the update cycle of the current GKScene
/SKScene
.
Then you have the GKComponentSystem
that you can use to fire up the update()
methods of every component from a given type that has been added to it. I see the point, it's very handy.
But I also want to use the state machine system and it also has an update cycle of it's own... Combining all that got me confused.
My situation
In the case where I have a subclass of GKEntity
with an instance of a GKStateMachine
created on initialization. The state machine has a few states (for the moment: 'Spawn', 'Normal', 'Stunned' and 'Death'.
Right now, I'm creating a big "cookie cutter" with my GKEntity
subclasses and create all the components it's gonna use during the initialization. But it's becoming very impractical. For instance, I have a MovementComponent
, which is a subclass of GKAgent2D
. I created a singleton that manages entity creation, so after the instance is created, if loops through all the entity's components and add them to the related GKComponentSystems
. The singleton has an update() method of it's own that updates passes the call to the GKComponentSystems
. Some of the components I use do not need per-frame update, so no GKComponentSystem
has been created for them and I update them manually as required.
If I come back to my entity, since I create everything at once and use GKComponentSystems
to update the components, my component's update method is loaded with guard
and if-let
statements because I need to access the entity's state machine, check if it's a state where the entity can move (Normal state) and do its thing or escape the function. This is not efficient in my view: the move component doesn't need to get updated when it's spawning, stunned, or dying.
On top of that it makes my use of GKStateMachine
completely overkill since my update methods are empty: the components get updated by the GKComponentSystem
anyway.
My ideas
Drop the GKComponentSystems
completely and simply loop through all my entities (maybe sort them in different collections at some point if need be) and call their update()
methods. Dispatch the updates to the state machine which in turn will update the components involved in that state.
Keep the GKComponentSystems
and use the state machine to juggle with the components, for example by adding and removing the MovementComponent
from the component systems when entering and exiting the Normal state.
Option 1 is straightforward but could cause problems on the long run when my structure gets more complex becasue some components could need to be updated before others. Having each entity update its own components would scatter the update process.
Option 2 can get confusing too in a way, but my biggest concern is about the creation/removal of the components. Do I only take them out of the GKComponentSystems
or do I take them out of the entity completely? What is the most efficient way of doing it?
The actual question
which one of my options would be the best? is there any better way of doing it.
If you are using GKComponentSystem
to perform updates, then I would go with just that. I think a component should update only once per frame.
It's not clear from your question what you need to do with StateMachines, but there is no reason to not have them involved either directly in your GKEntity
or contained within a GKComponent
like the DemoBots IntelligenceComponent.
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