0

I am writing a game following an Entity Component-style design pattern, and have run into an issue I have been able to solve, but am not sure if it is a best practice (or if there even is such a thing).

I have a state machine that handles the main states of the game (menu, in-level, paused, background), and an inner state machine in one of the gameplay components that handles more piecemeal game states (new level, level over, next level, game over and summary). I want to let the outer state machine know that the game has ended from the inner component, but it has no reference to the main controller class. Normally, I'd use a protocol to delegate information up the chain, but this seems to me, in my limited ECS experience, to break the paradigm. What I am doing is querying the app delegate for the window's root view controller, and calling convenience methods on it depending on the inner state...this would be a horrendous way to do MVC, but seems like it is fine in ECS.

Could anyone confirm that this is not as terrible as I think it is, or if it is, recommend a new paradigm? It would be greatly appreciated.

Basically it is working like this ( I think it is too much code to post in its entirety):

MainMenuViewController has an ApplicationEntity, which has an ApplicationLifecycleComponent that contains a state machine. On pressing a 'start game' button, the state machine passes into ApplicationGameState.

ApplicationGameState uses a weak reference to the MainMenu VC (which is root) to present a GameViewController that loads a SpriteKit scene. Game logic happens here through a bunch of inner components and state machines that eventually report a 'game over'.

On game over, the ApplicationLifecycle's state machine should exit ApplicationGameState and enter MainMenuState (or any other state, as necessary), but since I can't get at the root VC from the scene, I ask the AppDelegate for the root vc, cast it as a MainMenuViewController, grab its entity and tell its lifecycle component to change state, as below:

if let applicationController = UIApplication.sharedApplication().keyWindow?.rootViewController as? MainMenuViewController {
    applicationController.applicationEntity.applicationLifecycleComponent.enterMenuState()
} 

Rephrasing the question, should I push a weak reference of the root view controller down the chain from application start to get to this state? Is there a best practice for notifying a higher-level entity that something happened?

For reference, this is my first-ever foray into ECS.

diatrevolo
  • 2,782
  • 26
  • 45
  • 1
    If you could post your code, or at least pseudo-code that shows the setup and connection of statemachines and components. That would help making a suggestion. I don't think that going through the app delegate is necessary at all, in fact it's usually an unnecessary evil. You could for instance pass a (weak) reference to "inner" objects, or use NSNotificationCenter. – CodeSmile Aug 26 '15 at 09:12
  • @LearnCocos2D I tried to spell out the problem above without including a bunch of (in my view) cumbersome code. Hopefully this gives some insight? If not, I can post some classes. Thanks! – diatrevolo Aug 26 '15 at 18:06
  • I like the idea you propose of NSNotificationCenter with a publish/subscribe-type pattern to rule the overall application, actually. – diatrevolo Aug 26 '15 at 18:37
  • 2
    applicationEntity sounds like a global ... perhaps the core of this issue is that you think of entity as globally persistent objects? This might be code that's better left to the statemachine itself, which then informs entities/components. Also, statemachines needn't necessarily be inside a component, you could have your global "scene control" statemachine straight in the app delegate or better, the Sprite Kit view controller. Makes more sense. – CodeSmile Aug 26 '15 at 22:19
  • Thanks for the ideas, @LearnCocos2D. I appreciate the insight. – diatrevolo Aug 26 '15 at 22:31

0 Answers0