Antillery Devlog #4
States, Events, and Application Flow
May 25, 2025
Planning for a modular, event-driven application flow architecture
Problem
Before building any gameplay systems in Antillery, I needed a reliable, flexible way to manage the overall structure of the game. This includes switching between scenes like the Main Menu, Match Setup, the active game loop, and Post-Match summary.
Key Challenges
- Prevent tight the tight coupling that would occur if states handled their own transitions.
- Ensure that scene transitions are clean, observable, and modular.
- Allow for easy debugging and extensibility of the application flow.
- Support a flexible architecture that can adapt to future gameplay systems.
- Maintain a clear separation of concerns between state logic and transition management.
- Allow designers to create and modify game flow without needing to write code.
- Ensure that the application flow is version-control friendly and inspector-friendly.
Approach
I designed a modular architecture to provide flexibility and clear separation of concerns between different aspects of the application flow.
Architecture Overview
The implemented application flow architecture uses a modular, ScriptableObject-driven state machine backed by a polymorphic
IStateinterface, enabling clean, observable transitions between game scenes.
Architecture
- Interface-Based Design: States implement
IStatefor flexibility and separation of concerns - Event-Driven Communication: States define their own event contracts that external systems can subscribe to
- Decoupled Transitions: GameFlowManager centralizes transition logic separate from the states themselves
- Inspector Support: StateMachine works with interfaces while maintaining Unity editor compatibility
- Scene Management: Scenes load additively to preserve persistent game systems
Core Systems
IState.cs- interface contract for all state logicState.cs- base SO implementation with lifecycle + scene handlingStateMachine.cs- tracks active/previous state, handles transitions with safety guardsAppManager.cs- SO configuration container for initial state and registrationGameFlowManager.cs- MonoBehaviour that connects state signals to transition logic
Example state and transition flow:
public event Action OnPlaySelected;
public override void Update()
{
if (Input.GetKeyDown(KeyCode.P))
OnPlaySelected?.Invoke();
}
mainMenuState.OnPlaySelected += () =>
{
stateMachine.ChangeState(matchSetupState);
};
Note: The actual implementation uses Unity's new Input System package with action-based input events, not the legacy Input.GetKeyDown shown in this simplified example.
Results
The application state system is complete and functional:
Scene Boot Flow
- App starts from
BootstrapScene BootstrapSceneloadsMainMenuScene
Modularity & Debugging
- All state assets are inspectable and reusable
- Debug logs clearly trace lifecycle events
Limitations
Centralized Transition Management
One limitation of the current architecture is that the GameFlowManager becomes a central point that must be aware of all systems that could trigger state transitions. As the project grows, this could lead to:
- A bloated GameFlowManager that knows too much about disparate game systems
- Potential tight coupling between the manager and various specialized systems
- Scalability challenges when adding new types of state transitions
Forced Additive Scene Loading
A significant limitation I've discovered is that using a persistent GameFlowManager MonoBehaviour forces all scenes to be loaded additively rather than replacing the current scene:
- This creates performance overhead from maintaining multiple scenes simultaneously (e.g., having the menu scene still loaded while playing)
- Requires complex management to hide/show objects between scenes
- Increases memory usage by keeping multiple scenes resident
- Creates potential conflicts between scene-specific systems and resources
- Complicates object references and scene hierarchy management
Future Improvements
For the next iteration, I'm exploring potential solutions such as:
- A more decentralized event bus system that allows systems to broadcast state change requests
- State transition rules defined in data rather than hardcoded in the GameFlowManager
- Hierarchical state machines that handle domain-specific state changes locally
- A DontDestroyOnLoad-based service locator pattern that persists without requiring additive scenes
- Scene-independent state persistence using ScriptableObjects to maintain state between full scene transitions
For now, the centralized approach is sufficient for the current scope, but future scalability will require addressing these architectural considerations.
Project Impact
This architecture milestone sets the foundation for all gameplay systems in Antillery.
By developing a clean, modular, event-driven app flow with interface-backed flexibility, I've removed friction for future development of in-match logic, input context switching, UI overlays, and more.
The project is now version-control friendly, inspector-friendly, and scalable, ready for iterative solo work but also cleanly extensible for future collaborators.
Editor's Note
Since drafting this devlog post, I've continued exploring alternative architecture patterns and have designed a new state machine/game flow system that addresses several of the limitations mentioned above. I'll be discussing this evolution in a future devlog post, showing how iterative design thinking leads to better solutions!