Support our educational content for free when you purchase through links on our site. Learn more
15 Best Coding Patterns for Mobile Games 🎮
Which coding design patterns are best suited for mobile game development? Start with State, Observer, Factory, Object Pool, Command, Strategy, Component, Facade, and Dependency Injection. Together, they keep gameplay modular, reduce unnecessary runtime work, simplify platform integration, and make future features less likely topple the project like a badly balanced Jenga tower.
The right mix depends on your game. A puzzle title may need only State, Observer, and Factory patterns, while a multiplayer RPG could benefit from Command, Repository, ECS, server-authoritative architecture, and carefully designed event messaging. There is no magic pattern; there is only the pattern that solves the problem you actually have.
We learned this the hard way while reviewing a mobile prototype where every enemy action passed through multiple interfaces, a service locator, and an event bus. The game had six enemy types, yet adding a seventh felt like excavating ancient ruin. We kept State for enemy modes, Strategy for attack behavior, and Object Pool for projectiles, then removed the abstractions that were merely showing off.
Mobile constraints make these decisions more practical than academic. Different devices, thermal throttling, app suspension, touch input, intermittent connections, and memory pressure all reward clear boundaries and measured performance. Tools such as the Unity Profiler, Unreal Insights, and Android game optimization guidance help reveal which patterns genuinely improve the player experience.
Key Takeaways
- Use State for game flow, menus, pause screens, quests, combat modes, and enemy AI.
- Use Observer or signals to update UI, audio, achievements, quests, and analytics without tightly coupling systems.
- Use Factory and Object Pool together for efficient spawning of enemies, projectiles, particles, and temporary effects.
- Use Command for touch input, replays, undoable actions, automated tests, and multiplayer requests.
- Use Strategy for interchangeable AI, combat, targeting, progression, and difficulty algorithms.
- Use Components or ECS when entities have reusable capabilities or the game must process large numbers of similar objects.
- Use Facade, Adapter, Repository, and Dependency Injection to isolate ads, purchases, authentication, cloud saves, analytics, and platform-specific APIs.
- Profile before optimizing. Object pooling, ECS, and data-oriented systems can help, but they also introduce memory, complexity, and maintenance costs.
- Avoid pattern overload. A small game rarely needs an enterprise architecture; choose the smallest abstraction that makes the next few changes safer.
Table of Contents
- ⚡️ Quick Tips and Facts
- The short answer: which patterns matter most?
- Design patterns versus game architecture
- When a pattern helps, and when it adds needless complexity
- 🎮 Mobile Game Development Design Patterns: Background and Evolution
- Why mobile games need different software architecture
- From monolithic game loops to modular mobile systems
- How Unity, Unreal Engine, Godot, and custom engines influence pattern choices
- 🧭 How to Choose the Best Coding Design Pattern for a Mobile Game
- Match patterns to gameplay systems and team size
- Evaluate performance, memory, battery life, and scalability
- Avoid pattern-driven overengineering
- A practical pattern-selection checklist
- 🏆 15 Best Design Patterns for Mobile Game Development
- 1. State Pattern for game states, menus, and player behavior
- 2. Observer Pattern for events, UI updates, and reactive gameplay
- 3. Factory Method Pattern for spawning game objects
- 4. Abstract Factory Pattern for themed assets and platform-specific objects
- 5. Object Pool Pattern for projectiles, enemies, and particle effects
- 6. Command Pattern for input handling, replays, and undoable actions
- 7. Strategy Pattern for interchangeable gameplay algorithms
- 8. Component Pattern for flexible entity composition
- 9. Entity-Component-System Pattern for data-oriented game architecture
- 10. Model-View-Controller Pattern for menus, HUDs, and game services
- 11. Model-View-ViewModel Pattern for mobile UI and data binding
- 12. Service Locator Pattern for shared game services
- 13. Dependency Injection Pattern for testable game systems
- 14. Singleton Pattern for carefully controlled global managers
- 15. Facade Pattern for simplified SDK and subsystem integration
- 🧱 Core Architecture Patterns for Mobile Games
- Game loop architecture and frame update responsibilities
- Scene management and screen transitions
- Layered architecture for gameplay, presentation, and services
- Clean Architecture for long-lived mobile game projects
- Data-oriented design and cache-friendly systems
- ⚡ Performance Design Patterns for Mobile Games
- Reducing garbage collection and runtime allocations
- Using object pooling without creating memory leaks
- Managing CPU, GPU, and draw-call budgets
- Battery-conscious update loops and background processing
- Asynchronous loading, asset streaming, and task scheduling
- 🎯 Gameplay Programming Patterns by Game Feature
- Patterns for player input and touch controls
- Patterns for combat, abilities, and status effects
- Patterns for enemy artificial intelligence and navigation
- Patterns for inventory, equipment, and progression systems
- Patterns for quests, missions, and reward systems
- Patterns for physics, collisions, and triggers
- Patterns for save data, checkpoints, and player profiles
- 📱 Mobile UI, UX, and Platform Integration Patterns
- Responsive UI for different screen sizes and aspect ratios
- Separating presentation logic from gameplay logic
- Handling Android and iOS platform services
- Ads, in-app purchases, analytics, and authentication
- Offline mode, connectivity changes, and cloud synchronization
- 🌐 Multiplayer and Live-Service Game Design Patterns
- Client-server architecture and authoritative game logic
- Command and event patterns for network messages
- State synchronization, prediction, and interpolation
- Matchmaking, lobbies, and session management
- Feature flags, remote configuration, and live events
- 🧪 Testing, Debuging, and Maintainability
- Unit testing gameplay systems and domain logic
- Integration testing scenes, services, and SDKs
- Testing frame-rate stability and device performance
- Mocking input, network calls, purchases, and analytics
- Using logging, profiling, and crash reporting effectively
- 🧩 How Design Patterns Work Together in a Real Mobile Game
- A sample architecture for a 2D action game
- A sample architecture for a 3D multiplayer game
- Combining State, Observer, Strategy, Factory, and Object Pool
- Keeping dependencies clear between systems
- 🚫 Common Design Pattern Mistakes in Mobile Game Projects
- Why overusing Singleton can make code fragile
- Why Service Locator can hide dependencies
- Why inheritance-heavy designs become difficult to extend
- Why premature abstraction slows down development
- Signs that a pattern should be removed
- 💻 Implementation Guidance for Unity, Unreal Engine, Godot, and Native Apps
- C# design patterns in Unity mobile games
- C++ patterns in Unreal Engine projects
- GDScript patterns in Godot
- Swift and Kotlin patterns for native mobile games
- Adapting patterns to ECS and data-oriented technology stacks
- 📊 Design Pattern Comparison Matrix
- Best patterns for performance
- Best patterns for flexibility and scalability
- Best patterns for testability
- Best patterns for small teams and prototypes
- Best patterns for multiplayer and live-service games
- 🛠️ A Step-by-Step Workflow for Applying Coding Patterns
- Start with gameplay requirements and constraints
- Identify repeated responsibilities and changing behavior
- Select the smallest useful abstraction
- Prototype, profile, test, and refactor
- Document architectural decisions for the team
- 📚 Essential Resources for Game Programming Patterns
- Game Programming Patterns by Robert Nystrom
- Gang of Four design patterns and object-oriented principles
- Official Unity mobile optimization resources
- Official Unreal Engine programming documentation
- Godot architecture and performance documentation
- ❓ Frequently Asked Questions
- Which design pattern is most important for mobile game development?
- Is Singleton suitable for mobile games?
- Should mobile games use ECS?
- Are design patterns necessary for a small game?
- Which patterns improve mobile game performance?
- What is the best pattern for enemy AI?
- How do design patterns affect Unity performance?
- Can multiple design patterns be used in one game system?
- Which patterns are best for multiplayer mobile games?
- Conclusion
- 🔗 Recommended Links
- 📖 Reference Links
The first rule of mobile game architecture is delightfully unglamorous: choose a pattern because it solves a real problem, not because a diagram looked impressive in a software engineering lecture. Our broader guide to coding design patterns covers the fundamentals; here, we’ll apply them touch controls, frame budgets, live updates, and the occasional enemy who refuses to behave.
The short answer: which patterns matter most?
For most mobile games, the strongest starting combination is:
- State Pattern for menus, gameplay modes, quests, combat, and enemy behavior.
- Observer or event-driven messaging for UI updates, achievements, audio, analytics, and loosely coupled systems.
- Factory Pattern for spawning enemies, weapons, items, and platform-specific services.
- Object Pool Pattern for bullets, enemies, particles, and other frequently created objects.
- Command Pattern for input, replays, undoable actions, and network commands.
- Strategy Pattern for swappable AI, combat rules, targeting, movement, and progression algorithms.
- Component or ECS architecture for scalable entities and data-heavy gameplay.
- Facade and Dependency Injection for simplifying SDK integrations and improving testability.
There is no universal winner. Game Programming Patterns says patterns should be selected “à la carte”, and that advice fits mobile development especially well. A puzzle game, an idle RPG, and a real-time multiplayer shooter have very different architectural appetites.
| Mobile game need | Best first pattern or approach | Why it fits | Main caution |
|---|---|---|---|
| Menu and gameplay flow | State | Makes transitions explicit | Avoid one enormous state machine |
| Rapid object spawning | Object Pool | Reduces allocation churn | Pools must release references correctly |
| UI reacting to gameplay | Observer/events | Separates systems cleanly | Hidden event chains can be hard to debug |
| Enemy variations | Strategy, State, Behavior Tree | Changes behavior without rewriting enemies | Too many abstractions slow iteration |
| Bulets, particles, damage numbers | Object Pool | Reuses short-lived objects | Pool sizing needs profiling |
| Platform SDKs | Facade, Adapter | Gives gameplay code one clean API | Keep platform errors visible |
| Large entity counts | ECS/data-oriented design | Improves locality and batch processing | Steper learning curve |
| Input and replays | Command | Converts actions into data | Commands can become overly granular |
| Testing services | Dependency Injection | Replaces real services with fakes | Avoid injecting every tiny object |
| Global configuration | Carefully scoped service or data asset | Centralizes stable configuration | Singleton abuse creates hidden coupling |
Design patterns versus game architecture
A design pattern solves a recurring design problem. An architecture organizes the entire game: its systems, data flow, scenes, services, assets, and build boundaries.
Think of patterns as tools in a tool belt. Architecture is the workshop layout. Owning twelve hammers does not make the furniture better.
A useful mobile game architecture usually separates:
- Presentation: UI, animations, camera, visual effects.
- Gameplay domain: combat, movement, inventory, quests, progression.
- Infrastructure: save files, networking, analytics, purchases, ads.
- Platform integration: Android, iOS, notifications, authentication, achievements.
- Data and content: configuration, levels, item definitions, localization.
This separation reflects the principle that architecture is about change, emphasized in Architecture, Performance, and Games. Mobile games change constantly: new events arrive, devices vary wildly, app-store requirements shift, and the “temporary” tutorial system somehow becomes a permanent resident.
When a pattern helps, and when it adds needless complexity
A pattern is earning its keep when it does at least one of these:
- Reduces dependencies between systems.
- Makes a likely change safer.
- Improves automated testing.
- Prevents repeated allocation or expensive work.
- Lets designers and programmers iterate independently.
- Makes runtime behavior easier to observe.
A pattern is probably premature when:
- The feature is tiny and unlikely to change.
- It introduces several files to replace one understandable function.
- Nobody can explain its benefit without drawing a twelve-box diagram.
- It adds virtual dispatch, messaging, or allocations inside a hot loop.
- The team is still discovering whether the feature is fun.
The developers at Stack Interface™ use a simple test:
If removing the pattern makes the next three likely changes easier, remove it.
That may sound blunt. It is also cheaper than maintaining a miniature enterprise framework for a game with one character, two enemies, and a suspiciously ambitious settings menu.
Why mobile games need different software architecture
Mobile games run under constraints that desktop developers can sometimes ignore:
- Limited and variable CPU performance.
- Thermal throttling during long sessions.
- Battery consumption concerns.
- Different screen sizes, aspect ratios, and refresh rates.
- Memory pressure from other apps.
- Intermittent connectivity.
- App suspension and lifecycle interruptions.
- Wide variation between low-end Android phones and flagship iPhones.
- Strict download-size and startup expectations.
The Android Developers performance guidance and Apple’s game development resources both emphasize measuring real device behavior rather than assuming a powerful development machine represents the audience.
A desktop prototype may happily allocate hundreds of short-lived objects every frame. A mobile build may respond with stutter, garbage-collection pauses, heat, and a one-star review that begins, “Great game, but…”
From monolithic game loops to modular mobile systems
Early game code often placed input, movement, collision, rendering, audio, and scoring into one large loop. That approach can work for a small prototype. It becomes painful when:
- A pause menu must freeze gameplay but not audio.
- A rewarded ad pauses the game and later resumes it.
- A network disconnect occurs during combat.
- A quest update must refresh three UI panels.
- A seasonal event adds new enemies without changing core combat.
- A tutorial intercepts input temporarily.
Patterns emerged as practical responses to these pressures. The Gang of Four design patterns formalized many object-oriented solutions, while game-specific resources such as Game Programming Patterns adapted them to sequencing, behavior, decoupling, and optimization.
How Unity, Unreal Engine, Godot, and custom engines influence pattern choices
The engine changes the mechanics, but not the underlying problems.
| Engine or stack | Common language | Useful built-in concepts | Patterns that commonly complement it |
|---|---|---|---|
| Unity | C# | MonoBehaviour, ScriptableObject, Animator, Addressables, Unity Test Framework | State, Observer, Factory, Object Pool, Strategy, DI |
| Unreal Engine | C++/Blueprints | Actors, Components, Gameplay Ability System, Behavior Trees, Subsystems | Component, State, Strategy, Facade, Command |
| Godot | GDScript/C#/C++ | Nodes, Scenes, Signals, Resources | Observer/signals, State, Factory, Component-like composition |
| Native Android | Kotlin/Java | Activities, Services, ViewModel, coroutines | MVM, Repository, Observer, Adapter, DI |
| Native iOS | Swift/Objective-C | SwiftUI/UIKit, Combine, async/await | MVM, Observer, Coordinator, Facade, DI |
| Custom engine | C++/Rust/other | Team-defined | ECS, data-oriented systems, explicit job scheduling |
The engine should not dictate every architectural decision. Unity’s Animator system already gives you a visual state-machine tool, while Godot’s signals provide an event mechanism. Rebuilding those features from scratch may be educational, but it is rarely the fastest route to a shippable mobile game.
Match patterns to gameplay systems and team size
Start with the problem, not the pattern catalogue.
Ask:
- What changes frequently?
- What must remain stable?
- Which objects are created repeatedly?
- Which systems need to communicate?
- Which code must run every frame?
- Which services need to be replaced in tests?
- Which feature is likely to become live content?
A two-person puzzle team may benefit from direct code plus a few targeted patterns. A 30-person live-service team needs stronger module boundaries, event contracts, build tooling, content pipelines, and automated testing.
Evaluate performance, memory, battery life, and scalability
Patterns affect runtime cost in different ways.
| Concern | Potentialy helpful patterns | What to measure |
|---|---|---|
| Garbage collection | Object Pool, value-oriented data | Allocations per frame, GC pauses |
| CPU frame time | ECS, batching, concrete data structures | Main-thread time, system time |
| Memory | Flyweight, pooling, asset references | Resident memory, texture memory |
| Battery | Event-driven updates, throttled services | Energy impact, sustained thermal behavior |
| Startup | Lazy loading, Facade, staged initialization | Time to first interaction |
| Network overhead | Command, snapshots, event messages | Bandwidth, packet frequency |
| Maintainability | State, Strategy, DI, modular architecture | Change impact, test coverage |
The Unity Profiler, Unreal Insights, and Android Studio Profiler can reveal whether a pattern is helping or merely wearing a fashionable hat.
Avoid pattern-driven overengineering
Our team once reviewed a prototype where every enemy action passed through an interface, a service locator, an event bus, and a generic behavior registry. The game had six enemy types. Adding a seventh required more archaeology than programming.
The fix was not “remove all architecture.” We kept:
- State objects for enemy modes.
- Strategy objects for attack selection.
- Object pooling for projectiles.
- Direct references for stable, local relationships.
That balance mattered. The point is not to eliminate abstraction; it is to place abstraction where change is likely.
A practical pattern-selection checklist
Before adopting a pattern, answer these questions:
- Problem: What specific pain does it solve?
- Frequency: Will this code change repeatedly?
- Scope: Is the pattern local or spreading across the project?
- Runtime: Does it execute in a hot loop?
- Memory: Does it allocate or retain references?
- Debuging: Can a new team member trace the control flow?
- Testing: Does it make tests easier?
- Removal: Can we remove it without rewriting the whole system?
If the answers are vague, begin with simpler code and revisit the design after profiling or a few feature iterations.
1. State Pattern for game states, menus, and player behavior
The State Pattern lets an object change behavior when its internal state changes. Typical mobile-game states include:
- Booting.
- Loading.
- Main menu.
- Playing.
- Paused.
- Showing an ad.
- Game over.
- Reconnecting.
- Returning from the background.
Instead of spreading conditions everywhere:
if (isPaused && !isShowingAd && hasLoadedSave && ...)
{
// More conditions arrive wearing tiny sunglasses.
}
``
you create explicit states with clear entry, update, and exit behavior.
```csharp
public interface IGameState
{
void Enter();
void Tick(float deltaTime);
void Exit();
}
public sealed class PausedState : IGameState
{
public void Enter() => Time.timeScale = 0f;
public void Tick(float deltaTime) { }
public void Exit() => Time.timeScale = 1f;
}
``
### Best uses
- Game flow.
- Enemy AI.
- Character combat modes.
- Quest progression.
- Tutorial stages.
- Animation phases.
- Connection states.
### Benefits
- Explicit transitions.
- Easier testing.
- Fewer boolean flags.
- Clear lifecycle behavior.
- Better designer communication.
### Drawbacks
- Too many tiny states can fragment logic.
- State transitions can become difficult to trace.
- Continuous systems may not fit naturally into discrete states.
The Unity community discussion on state machines describes them as **“very commonly used”** for overall game flow, AI, and animation, but also warns that **not every game-design problem should be reduced to a state machine**. That distinction is crucial. Use a state machine for a finite set of modes; do not force an entire ecosystem into one giant traffic-light controller.
## 2. Observer Pattern for events, UI updates, and reactive gameplay
Observer creates a one-to-many relationship: one subject broadcasts a change, and multiple observers react. The embedded [featured video](#featured-video) presents Observer as a way to **“BROADCAST”** information to subscribers, alongside State, Factory, Facade, and Mediator examples.
Mobile applications use similar ideas through:
- Unity events.
- Godot signals.
- C# events.
- Kotlin Flow.
- Swift Combine.
- Custom event buses.
- ECS event streams.
Example:
```csharp
public event Action<int> ScoreChanged;
public void AddScore(int amount)
{
score += amount;
ScoreChanged?.Invoke(score);
}
``
### Good uses
- Updating score labels.
- Triggering achievements.
- Playing sound effects.
- Refreshing inventory UI.
- Sending analytics events.
- Reacting to quest completion.
- Updating accessibility or tutorial prompts.
### Benefits
- Reduces direct dependencies.
- Allows multiple listeners.
- Makes optional features easier to add.
- Keeps gameplay logic separate from presentation.
### Drawbacks
- Event order can be unclear.
- Forgotten subscriptions cause memory leaks or duplicate reactions.
- Debuging becomes harder when control flow is hidden.
- High-frequency events can waste CPU time.
### Practical rule
Use events for **meaningful changes**, not every transform update. Broadcasting “health changed” is reasonable. Broadcasting “position changed” for every object every frame is usually an invitation to inspect the profiler.
## 3. Factory Method Pattern for spawning game objects
Factories centralize object creation. They are valuable when creation requires:
- Prefab selection.
- Configuration data.
- Dependency setup.
- Platform-specific implementations.
- Pool retrieval.
- Localization or content metadata.
```csharp
public interface IEnemyFactory
{
Enemy Create(EnemyType type, Vector3 position);
}
``
A factory prevents gameplay code from knowing every prefab path, constructor detail, or initialization rule.
### Mobile-game examples
- Enemy spawning.
- Weapon creation.
- Item generation.
- UI screen construction.
- Network message creation.
- Service selection by platform.
### Factory versus direct instantiation
| Approach | Strength | Weakness |
|---|---|---|
| Direct `new` or prefab instantiate | Simple and readable | Creation logic spreads |
| Factory Method | Centralized creation | Extra abstraction |
| Abstract Factory | Families of related objects | Can be excessive for small games |
| Factory plus Object Pool | Efficient repeated spawning | Requires lifecycle discipline |
Factories become especially useful when paired with [Unity Addressables](https://docs.unity3d.com/Packages/com.unity.addressables@latest/), because asset loading and instantiation may involve asynchronous operations.
## 4. Abstract Factory Pattern for themed assets and platform-specific objects
Abstract Factory creates families of related objects. Consider a game with:
- Medieval and sci-fi visual themes.
- Different control schemes.
- Android and iOS platform services.
- Multiple gameplay modes with distinct UI families.
```csharp
public interface IGameServicesFactory
{
IAuthentication CreateAuthentication();
ICloudSave CreateCloudSave();
IAchievements CreateAchievements();
}
``
An Android implementation can use Google Play Games services, while an iOS implementation can use Game Center. Gameplay code talks to interfaces rather than platform SDK classes.
### Benefits
- Platform isolation.
- Consistent themed content.
- Easier testing with fake families.
- Fewer conditional compilation blocks.
### Drawbacks
- More types and configuration.
- Family boundaries can become rigid.
- Small projects may not need it.
Use Abstract Factory when objects **must work together as a family**. If you only need one interchangeable service, a Factory Method or Dependency Injection is usually cleaner.
## 5. Object Pool Pattern for projectiles, enemies, and particle effects
Object Pooling reuses objects rather than repeatedly creating and destroying them. It is one of the most practical performance patterns for mobile games.
Typical pooled objects:
- Bulets.
- Rockets.
- Damage numbers.
- Hit effects.
- Particle systems.
- Temporary enemies.
- Floating combat text.
- Collectible items.
The [Unity object pooling documentation](https://docs.unity3d.com/ScriptReference/Pool.ObjectPool_1.html) provides a built-in implementation for Unity projects.
### Pool lifecycle
1. Create or preload a pool.
2. Request an inactive object.
3. Reset its transform and gameplay state.
4. Activate it.
5. Use it.
6. Return it to the pool.
7. Clear transient references.
8. Reset timers, health, effects, and ownership.
### Pooling checklist
✅ Reset velocity and physics state.
✅ Clear event subscriptions.
✅ Remove temporary status effects.
✅ Reset animation state.
✅ Return child effects to their own pools.
✅ Handle pool exhaustion deliberately.
❌ Do not pool everything automatically.
❌ Do not retain references to released objects.
❌ Do not assume pooling fixes expensive rendering or AI.
Pooling can reduce garbage collection, but it may increase memory usage because objects remain allocated. Profile both frame-time stability and resident memory.
## 6. Command Pattern for input handling, replays, and undoable actions
Command turns an action into an object or data record.
Examples:
- Tap to move.
- Swipe to rotate.
- Fire weapon.
- Buy item.
- Cast spell.
- Build structure.
- Undo tile placement.
- Replay a recorded match.
- Send an authoritative multiplayer action.
```csharp
public interface ICommand
{
void Execute();
}
public sealed class MoveCommand : ICommand
{
private readonly Player player;
private readonly Vector2 direction;
public MoveCommand(Player player, Vector2 direction)
{
this.player = player;
this.direction = direction;
}
public void Execute() => player.Move(direction);
}
``
### Why it suits mobile games
Touch input can be noisy, asynchronous, and platform-specific. A command layer converts raw gestures into meaningful game actions.
### Additional uses
- Input remapping.
- Tutorial playback.
- Automated testing.
- Replay systems.
- Server validation.
- Accessibility controls.
### Caution
Do not turn every property assignment into a command. Commands are most valuable when actions need to be queued, logged, replayed, validated, undone, or transmitted.
## 7. Strategy Pattern for interchangeable gameplay algorithms
Strategy separates an algorithm from the object that uses it.
A character might select:
- Melee attack strategy.
- Ranged attack strategy.
- Defensive strategy.
- Flee strategy.
- Boss-phase strategy.
An inventory might use:
- Stackable-item rules.
- Durability rules.
- Weight-based rules.
- Unlimited casual-game rules.
```csharp
public interface ITargetingStrategy
{
Transform SelectTarget(IReadOnlyList<Transform> candidates);
}
``
### Benefits
- Replace behavior at runtime.
- Test algorithms independently.
- Avoid inheritance explosions.
- Support difficulty levels and live events.
### Strategy versus State
| Question | Strategy | State |
|---|---|---|
| What varies? | An algorithm or policy | Current mode and lifecycle |
| Example | Target selection | Chasing, attacking, stunned |
| Can it change during runtime? | Yes | Yes |
| Typical relationship | State may use a strategy | Strategy may inform a state transition |
A boss might be in an **Enraged State** while using an **Aggressive Targeting Strategy**. Patterns can cooperate; they are not rival sports teams.
## 8. Component Pattern for flexible entity composition
Component-based design builds entities from capabilities:
- Health component.
- Movement component.
- Inventory component.
- Damage receiver.
- Interaction component.
- Network identity.
- Status-effect container.
This avoids deep inheritance such as:
`FlyingFirePoisonBossEnemyWithShield : FireEnemy : Enemy : Character : Entity`
### Benefits
- Reusable behavior.
- Flexible combinations.
- Easier content authoring.
- Smaller changes when features evolve.
### Drawbacks
- Component dependencies can become hidden.
- Initialization order matters.
- Too many components create lookup overhead.
- Debuging behavior spread across components takes discipline.
Unity’s [Entity Component System](https://unity.com/ecs) takes this idea further with data-oriented processing, but classic component composition works perfectly well without adopting a full ECS.
## 9. Entity-Component-System Pattern for data-oriented game architecture
ECS separates:
- **Entities**: identifiers.
- **Components**: data.
- **Systems**: logic operating on matching data.
For example:
- Position component.
- Velocity component.
- Health component.
- Movement system.
- Damage system.
- Rendering system.
ECS can improve cache locality and batch processing when many entities share the same data shape. Unity’s [Entities documentation](https://docs.unity3d.com/Packages/com.unity.entities@latest/) explains its ECS and data-oriented technology stack.
### Strong candidates
- Large crowds.
- Bullet-hell games.
- Simulation-heavy strategy games.
- Many repeated environmental objects.
- Networked entities with predictable data.
### Poor candidates
- Small games with few entities.
- Highly unique objects.
- Teams unfamiliar with data-oriented architecture.
- Projects whose primary bottleneck is asset loading or rendering.
ECS is not automatically faster. It can be faster when the data layout and workload suit it. The [Game Programming Patterns architecture discussion](https://gameprogramingpatterns.com/architecture-performance-and-games.html) makes the broader point: optimize concrete bottlenecks, not fashionable abstractions.
## 10. Model-View-Controller Pattern for menus, HUDs, and game services
MVC separates:
- **Model**: game data and rules.
- **View**: visual representation.
- **Controller**: input and coordination.
It can work well for:
- Account screens.
- Settings.
- Store interfaces.
- Quest journals.
- Profile management.
- Non-real-time mobile UI.
MVC can become awkward when gameplay and rendering both update continuously. In many game engines, the engine’s component lifecycle does not map neatly onto traditional web MVC.
### Best practice
Use MVC selectively for UI-heavy subsystems, not necessarily as the architecture for every gameplay object.
## 11. Model-View-ViewModel Pattern for mobile UI and data binding
MVM, sometimes shortened incorrectly as “MVM,” places presentation state in a ViewModel. Native Android and iOS teams commonly use related patterns:
- Android ViewModel with [Jetpack architecture components](https://developer.android.com/topic/libraries/architecture/viewmodel).
- SwiftUI observable models.
- Combine publishers.
- Kotlin Flow.
- Reactive UI frameworks.
### Where MVM helps
- Menus.
- Store screens.
- Account and profile pages.
- Settings.
- Cloud-save status.
- Login and authentication flows.
### Where it may struggle
- Per-frame gameplay.
- Physics-heavy entities.
- Animation timing.
- Large object graphs with frequent updates.
The Unity discussion that inspired this comparison mentions a developer’s positive experience with WPF and MVM-style separation. That experience is valid, but it does not prove MVM belongs everywhere in Unity. **UI architecture and real-time simulation have different rhythms.**
## 12. Service Locator Pattern for shared game services
Service Locator provides access to shared services such as:
- Audio.
- Save system.
- Analytics.
- Localization.
- Time.
- Cloud storage.
- Platform authentication.
It can be convenient in a game engine where scene objects need access to services.
### Advantages
- Simple call sites.
- Centralized service registration.
- Useful for engine-level services.
- Easy to replace in small tests if designed carefully.
### Risks
- Dependencies are hidden.
- Missing registrations fail at runtime.
- Global state complicates test isolation.
- Callers can become coupled to the locator.
Use it sparingly. Explicit constructor injection is generally clearer for domain systems, while a carefully scoped service registry can be acceptable at infrastructure boundaries.
## 13. Dependency Injection Pattern for testable game systems
Dependency Injection supplies dependencies from outside rather than constructing them internally.
```csharp
public sealed class RewardService
{
private readonly IAnalytics analytics;
private readonly Inventory inventory;
public RewardService(IAnalytics analytics, Inventory inventory)
{
this.analytics = analytics;
this.inventory = inventory;
}
``
Tests can provide fakes:
```csharp
var fakeAnalytics = new FakeAnalytics();
var fakeInventory = new FakeInventory();
var service = new RewardService(fakeAnalytics, fakeInventory);
``
### Excellent uses
- Save services.
- Analytics.
- Network clients.
- Random-number providers.
- Clock and time services.
- Purchase validation.
- Remote configuration.
### Avoid
- Injecting trivial value objects.
- Building a container for a tiny prototype.
- Hiding simple dependencies behind a huge registration file.
- Using interfaces solely to satisfy a theoretical future.
Dependency Injection is especially helpful for the app-service boundary, which connects naturally to [Back-End Technologies](https://stackinterface.com/category/back-end-technologies/) such as authentication, cloud saves, and live-service APIs.
## 14. Singleton Pattern for carefully controlled global managers
Singleton guarantees one shared instance. Common examples include:
- Audio manager.
- Configuration registry.
- Input manager.
- Session manager.
- Platform service coordinator.
But Singleton is often overused because it is easy. The first YouTube video’s discussion of Singleton correctly adds a language-specific caveat: in JavaScript, object literals can make a formal Singleton unnecessary.
### When Singleton can be acceptable
✅ One truly process-wide service.
✅ Stable lifetime.
✅ Explicit initialization and shutdown.
✅ Easy replacement in tests.
✅ No hidden gameplay dependencies.
### When it becomes harmful
❌ Every system accesses every other system globally.
❌ Scene reloads create duplicate instances.
❌ Tests depend on execution order.
❌ State survives between sessions unexpectedly.
❌ Multiplayer or split-screen requires multiple instances.
The strongest recommendation is not “never use Singleton.” It is **do not make Singleton your default architecture**.
## 15. Facade Pattern for simplified SDK and subsystem integration
Facade provides a simple interface over a complex subsystem.
Instead of gameplay code calling five ad, analytics, and purchase SDKs:
```csharp
monetization.ShowRewardedAd(onRewardGranted);
``
the Facade handles:
- SDK initialization.
- Consent status.
- Platform differences.
- Failure callbacks.
- Analytics.
- Retry behavior.
- Reward validation.
### Good Facade targets
- Ads.
- In-app purchases.
- Authentication.
- Cloud saves.
- Push notifications.
- Social sharing.
- Achievements.
- Device vibration.
- Haptic feedback.
The featured video uses jQuery as a familiar Facade example: a simpler interface hides lower-level complexity. In mobile games, a Facade protects the gameplay layer from SDK churn.
# 🧱 Core Architecture Patterns for Mobile Games
## Game loop architecture and frame update responsibilities
A mobile game loop should make timing responsibilities explicit:
1. Read input.
2. Convert input into commands.
3. Update gameplay simulation.
4. Process collisions and events.
5. Update animation state.
6. Render.
7. Present the frame.
Not every system needs to run every frame. Use different frequencies:
| System | Suggested cadence |
|---|---|
| Player input | Every frame or input event |
| Physics | Fixed timestep where appropriate |
| Enemy decisions | Throttled intervals |
| UI refresh | On meaningful data change |
| Analytics batching | Periodic or lifecycle-based |
| Cloud save | Checkpoint, background, or explicit save |
| Nearby audio | Frame-based but optimized |
| Remote configuration | Startup and controlled refresh |
Avoid using `Update()` as a universal junk drawer. Event-driven updates can reduce CPU usage and battery impact, especially for UI and infrequent systems.
## Scene management and screen transitions
A scene transition often needs to coordinate:
- Fade effects.
- Input blocking.
- Save progress.
- Asset unloading.
- Audio changes.
- Analytics events.
- Network state.
- Loading progress.
- Back-button behavior.
A State machine plus Facade works well:
- `LoadingState`
- `MenuState`
- `GameplayState`
- `PauseState`
- `ReconnectState`
Use an explicit transition manager rather than allowing every button to load scenes directly. This creates one place to handle lifecycle failures.
## Layered architecture for gameplay, presentation, and services
A practical layered model:
```text
Presentation
↓
Application orchestration
↓
Gameplay/domain rules
↓
Infrastructure interfaces
↓
Platform and external services
``
The gameplay layer should not know whether analytics is Firebase, GameAnalytics, or a custom server. It should know that a meaningful event occurred.
The [Firebase Unity SDK](https://firebase.google.com/docs/unity/setup) and [GameAnalytics](https://gameanalytics.com/) can be useful, but integrating them directly into combat classes makes future migration unnecessarily painful.
## Clean Architecture for long-lived mobile game projects
Clean Architecture can help large games separate:
- Use cases.
- Domain rules.
- Interfaces.
- External services.
- Presentation.
However, importing every Clean Architecture ceremony into a small arcade game can slow development. Use the principles rather than worshiping the folder structure:
- Keep core rules independent.
- Keep external systems at the boundary.
- Depend inward on stable abstractions.
- Test rules without launching a scene.
For a large RPG or live-service game, these boundaries become increasingly valuable. For a weekend prototype, a well-named script may be the healthier architectural choice.
## Data-oriented design and cache-friendly systems
Data-oriented design asks:
- What data is processed together?
- In what order?
- How often?
- By which system?
- Can it be stored contiguously?
- Can work be batched?
For thousands of entities, arrays of positions and velocities may outperform scattered object graphs. The trade-off is flexibility. Data-oriented structures often assume more about the world.
The key is timing: **prototype with flexible code, measure, then specialize hot paths**. That recommendation resolves a common conflict between maintainability and speed. You do not need to choose one forever; different layers can use different styles.
# ⚡ Performance Design Patterns for Mobile Games
## Reducing garbage collection and runtime allocations
Common allocation sources include:
- Creating temporary lists every frame.
- String concatenation in update loops.
- LINQ in hot paths.
- Boxing value types.
- Repeated delegate creation.
- Instantiate/destroy cycles.
- Unbounded event subscriptions.
- JSON parsing during gameplay.
Helpful techniques:
- Reuse buffers.
- Pool temporary objects where justified.
- Avoid per-frame string formatting.
- Batch analytics.
- Use profiling tools before rewriting code.
- Keep high-frequency data in compact structures.
The [Unity garbage collection best-practice guide](https://docs.unity3d.com/Manual/performance-garbage-collection-best-practices.html) provides practical guidance, while [Android game optimization](https://developer.android.com/games/optimize) emphasizes testing on representative devices.
## Using object pooling without creating memory leaks
A pool can hide bugs because objects live longer than expected. When releasing an object:
1. Unsubscribe from events.
2. Cancel timers and coroutines.
3. Clear parent references.
4. Reset health, velocity, and animation.
5. Clear ownership and target references.
6. Disable renders and colliders.
7. Return child effects.
8. Mark the object inactive.
A pooled object that still listens to a global event can resurrect itself emotionally, if not literally. It may respond to a later event while inactive, producing duplicate damage, UI ghosts, or mysterious analytics.
## Managing CPU, GPU, and draw-call budgets
Patterns alone cannot fix:
- Oversized textures.
- Excessive overdraw.
- Unbatched materials.
- Expensive shaders.
- Too many dynamic lights.
- Unoptimized animation rigs.
- Heavy post-processing.
Use engine profilers and platform tools. Measure:
- CPU main-thread time.
- Render-thread time.
- GPU frame time.
- Draw calls.
- Batches.
- SetPass calls.
- Texture memory.
- Mesh memory.
- Thermal behavior.
A pooled particle system may reduce allocations while still saturating the GPU. Performance is a system property, not a sticker you attach to a class.
## Battery-conscious update loops and background processing
Mobile games should respect lifecycle transitions:
- Pause simulation when backgrounded.
- Stop unnecessary network polling.
- Save at safe checkpoints.
- Reduce animation and particle work when hidden.
- Resume gracefully after interruption.
- Handle calls, notifications, and app switching.
Android’s [game activity and lifecycle resources](https://developer.android.com/games) and Apple’s [app lifecycle documentation](https://developer.apple.com/documentation/uikit/app_and_environment/managing_your_app_s_life_cycle) are useful references.
Use Observer or State to centralize lifecycle changes. Do not scatter “if app is paused” flags across every gameplay class.
## Asynchronous loading, asset streaming, and task scheduling
Use asynchronous patterns for:
- Scene loading.
- Addressable assets.
- Remote configuration.
- Cloud saves.
- Authentication.
- Store catalogs.
- Large localization files.
Good design separates:
- Request started.
- Progress reported.
- Request succeeded.
- Request failed.
- Request cancelled.
- App interrupted.
A Facade can shield gameplay from the underlying task system, while State handles the player-facing flow. Cancellation matters: a player can leave a screen before its network request completes.
# 🎯 Gameplay Programming Patterns by Game Feature
## Patterns for player input and touch controls
A clean input path is:
```text
Touch / controller / keyboard
↓
Input adapter
↓
Command
↓
Gameplay system
``
Use Adapter or Command to support:
- Touch.
- Gamepad.
- Keyboard.
- Accessibility input.
- Automated tests.
- Network replay.
Avoid having combat code inspect `Input.GetTouch()` directly. That makes testing and control remapping harder.
## Patterns for combat, abilities, and status effects
A robust combat system often combines:
- **Command** for player actions.
- **Strategy** for targeting or damage calculation.
- **State** for casting, cooldown, stunned, and interrupted modes.
- **Observer** for health and status updates.
- **Factory** for ability creation.
- **Object Pool** for projectiles and visual effects.
Represent status effects as data or components rather than deeply nested subclasses:
- Burning.
- Poisoned.
- Slowed.
- Shielded.
- Silenced.
- Vulnerable.
This approach makes stacking rules explicit and supports content designers without multiplying classes.
## Patterns for enemy artificial intelligence and navigation
Use State for discrete behavior:
- Patrol.
- Investigate.
- Chase.
- Attack.
- Flee.
- Stunned.
Use Strategy for replaceable decisions:
- Target selection.
- Path selection.
- Attack choice.
- Difficulty adjustment.
Use Behavior Trees when decisions become hierarchical and conditional. The Unity discussion specifically identifies behavior trees as an alternative when AI grows beyond straightforward state transitions.
A practical hybrid is common:
```text
Enemy State
└── Decision Strategy
└── Navigation Service
``
## Patterns for inventory, equipment, and progression systems
Useful choices include:
- Factory for item construction.
- Strategy for stat calculation.
- Observer for inventory UI.
- Command for equip, sell, consume, and undo.
- Repository for persistence.
- Flyweight or shared data assets for immutable item definitions.
Separate item **definition data** from item **runtime state**:
| Definition data | Runtime state |
|---|---|
| Item ID | Quantity |
| Display name | Durability |
| Icon reference | Upgrade level |
| Base stats | Ownership |
| Rarity rules | Random modifiers |
This reduces duplication and makes save data more stable.
## Patterns for quests, missions, and reward systems
Quest systems benefit from:
- State for quest stages.
- Observer for objective completion.
- Command for player actions.
- Factory for quest types.
- Strategy for reward calculation.
- Repository for persistence.
Avoid making every quest a bespoke script if quests share a data structure. Conversely, do not force wildly different narrative missions into a rigid generic schema. The content model should reflect the game’s actual variety.
## Patterns for physics, collisions, and triggers
Use event or Observer-style communication to notify gameplay systems of:
- Damage.
- Pickup.
- Trigger activation.
- Area entry.
- Destruction.
- Environmental hazards.
Keep collision detection close to the physics engine, but translate collision results into domain events. That prevents inventory, analytics, and quest code from depending directly on collider implementation details.
## Patterns for save data, checkpoints, and player profiles
A save system benefits from:
- Repository abstraction.
- Facade over local and cloud storage.
- Command or event logs for recoverability.
- Versioned data migration.
- Dependency Injection for testable storage.
Never assume a save format will remain unchanged. Add a version number and migration path early, especially for games expected to receive updates.
# 📱 Mobile UI, UX, and Platform Integration Patterns
## Responsive UI for different screen sizes and aspect ratios
Use presentation patterns that separate:
- Layout state.
- Gameplay data.
- Input handling.
- Platform safe areas.
- Localization expansion.
- Accessibility settings.
Test:
- Small Android phones.
- Large tablets.
- iPhone models with safe-area insets.
- Landscape and portrait.
- Notches and cutouts.
- High refresh rates.
- Large text settings where supported.
A responsive UI is not merely a scaled UI. Buttons may need different spacing, panels may reposition, and touch targets must remain usable.
## Separating presentation logic from gameplay logic
The score system should not know whether the score appears in:
- A TextMeshPro label.
- A SwiftUI view.
- A Godot Control node.
- A native Android screen.
- A floating world-space display.
Observer, MVM, MVC, and Presenter-style approaches can all help. Choose based on the UI framework and team experience.
## Handling Android and iOS platform services
Use Adapter, Facade, and Abstract Factory to isolate:
- Authentication.
- Achievements.
- Cloud saves.
- Notifications.
- Haptics.
- Share sheets.
- Store review prompts.
- Platform purchase validation.
The gameplay layer should receive a stable result such as:
```text
AuthenticationSucceeded
AuthenticationCancelled
AuthenticationFailed
``
rather than parsing platform-specific callback objects.
## Ads, in-app purchases, analytics, and authentication
Commercial SDKs change. Their APIs, consent requirements, initialization rules, and platform behavior evolve.
A monetization Facade should manage:
- Initialization status.
- User consent.
- Availability.
- Placement identifiers.
- Reward callbacks.
- Failure handling.
- Revenue analytics.
- Duplicate reward prevention.
For guidance on privacy and platform requirements, consult [Google Play’s policy center](https://support.google.com/googleplay/android-developer/topic/9858052) and [Apple’s App Store Review Guidelines](https://developer.apple.com/app-store/review/guidelines/).
## Offline mode, connectivity changes, and cloud synchronization
Use State for connection status:
- Online.
- Offline.
- Connecting.
- Reconnecting.
- Authentication expired.
- Sync conflict.
Use Repository and Facade to abstract storage. Design gameplay so that temporary connectivity loss does not corrupt progress. For competitive multiplayer, server authority remains essential; offline fallback should not quietly create invalid competitive data.
# 🌐 Multiplayer and Live-Service Game Design Patterns
## Client-server architecture and authoritative game logic
Competitive games should generally treat the server as authoritative for:
- Match results.
- Inventory grants.
- Currency.
- Ranked progress.
- Damage validation.
- Trading.
- Purchases.
The client can predict and render, but it should not be the final judge of valuable state.
Use Command to represent player requests and Strategy or State to process server-side rules. Keep client and server contracts versioned.
## Command and event patterns for network messages
Network commands might include:
- Move.
- Attack.
- Use item.
- Join match.
- Ready up.
- Claim reward.
Events might include:
- Damage applied.
- Match started.
- Objective completed.
- Player disconnected.
- Reward granted.
Use explicit message schemas. Avoid sending engine-specific object graphs across the network.
## State synchronization, prediction, and interpolation
Real-time multiplayer commonly combines:
- State snapshots.
- Client prediction.
- Server reconciliation.
- Interpolation.
- Interest management.
- Delta compression.
Patterns help organize responsibilities, but the result must be measured under latency and packet loss. Test on real mobile networks, not only a perfect office Wi-Fi connection.
## Matchmaking, lobbies, and session management
A lobby system naturally maps to State:
- Idle.
- Searching.
- Match found.
- Connecting.
- Loading.
- Ready.
- In match.
- Leaving.
- Reconnecting.
Facade can simplify the backend SDK, while Observer updates the UI. Keep timeout and cancellation paths explicit; players should never stare at “Connecting…” until the heat death of the universe.
## Feature flags, remote configuration, and live events
Strategy and Factory are helpful for controlled content variation:
- Holiday enemy sets.
- Limited-time rules.
- Difficulty experiments.
- UI promotions.
- Economy tuning.
- A/B tests.
Use validation, defaults, and versioning. Remote configuration should not be able to put the client into an impossible state.
# 🧪 Testing, Debuging, and Maintainability
## Unit testing gameplay systems and domain logic
Good unit-test candidates:
- Damage calculations.
- Reward rules.
- Inventory stacking.
- Quest transitions.
- State transitions.
- Cooldown behavior.
- Purchase validation.
- Save migration.
- Target selection.
Inject random number generators, clocks, and services so tests remain deterministic.
## Integration testing scenes, services, and SDKs
Integration tests should verify:
- Scene loading.
- Object pooling.
- Addressable asset retrieval.
- Save and restore.
- Authentication flows.
- Analytics dispatch.
- Purchase callbacks.
- Network reconnects.
Use sandbox environments for real services. Never let a test suite buy live items or send production analytics unless you enjoy explaining unusual dashboards.
## Testing frame-rate stability and device performance
Measure on:
- Low-end Android hardware.
- Mid-range devices.
- Recent iPhones.
- Different refresh rates.
- Thermal conditions.
- Low battery states.
- Long sessions.
Track:
- Average frame time.
- Worst-frame spikes.
- Memory growth.
- GC pauses.
- Startup time.
- Battery drain.
- Crash-free sessions.
A stable 30 FPS may be preferable to an unstable 60 FPS target on a thermally constrained device. The right target depends on genre and hardware audience.
## Mocking input, network calls, purchases, and analytics
Dependency Injection makes it possible to provide:
- Fake network responses.
- Simulated purchase success and failure.
- Deterministic input.
- Test clocks.
- Fake analytics sinks.
- Local save stores.
Command-based input is particularly useful for replaying bugs. If a player reports “the boss became immortal after opening the menu,” a recorded command sequence can be more valuable than a screenshot.
## Using logging, profiling, and crash reporting effectively
Use structured logs with:
- Session ID.
- Build version.
- Device model.
- Operating system.
- Scene.
- State.
- Event name.
- Corelation ID.
Tools such as [Firebase Crashlytics](https://firebase.google.com/products/crashlytics), [Unity Cloud Diagnostics](https://unity.com/products/cloud-diagnostics), and platform crash reports help identify device-specific failures.
Avoid logging sensitive data or flooding release builds. Logging is a communication pattern between the running game and the future developer who has not yet had coffee.
# 🧩 How Design Patterns Work Together in a Real Mobile Game
## A sample architecture for a 2D action game
A practical 2D action game might use:
```text
Input Adapter
↓
Command Queue
↓
Player State Machine
↓
Combat Strategy
↓
Damage Event
├── Health System
├── UI Observer
├── Audio Observer
├── Quest Observer
└── Analytics Facade
``
Projectile creation flows through:
```text
Weapon Strategy
↓
Projectile Factory
↓
Object Pool
↓
Physics / Collision
``
This design keeps the weapon from knowing how the HUD, audio, and analytics systems respond to damage.
## A sample architecture for a 3D multiplayer game
A larger game may use:
- State for connection and match flow.
- Command for player requests.
- Server-authoritative simulation.
- ECS or component architecture for many entities.
- Strategy for AI and weapons.
- Observer or event streams for UI.
- Facade for platform services.
- Repository for player data.
- Dependency Injection for test doubles.
The key is not the number of patterns. It is the clarity of ownership:
| Responsibility | Owner |
|---|---|
| Raw touch input | Input adapter |
| Player intent | Command |
| Local animation mode | State |
| Damage rules | Combat domain |
| Object creation | Factory |
| Repeated temporary objects | Pool |
| UI refresh | Observer/ViewModel |
| Platform SDK | Facade/Adapter |
| Persistence | Repository |
| Network authority | Server |
## Combining State, Observer, Strategy, Factory, and Object Pool
These patterns complement one another:
1. **State** decides what the character can do.
2. **Strategy** decides how the action is performed.
3. **Factory** creates the required object.
4. **Object Pool** supplies a reusable instance.
5. **Observer** informs interested systems.
6. **Facade** reports analytics or platform effects.
For example, a player in `CastingState` uses a `FireballStrategy`. The strategy asks a `ProjectileFactory` for a fireball, which retrieves one from a pool. On collision, the system emits `DamageApplied`, and observers update health UI, play audio, progress a quest, and record analytics.
That is a lot of machinery for one fireball. In a small game, direct calls may better. In a content-heavy RPG with dozens of abilities and live events, the separation can pay for itself.
## Keeping dependencies clear between systems
Use dependency diagrams and module rules:
- UI may depend on application events.
- Gameplay may depend on domain interfaces.
- Infrastructure implements interfaces.
- Platform code stays at the edge.
- Core simulation does not import ad SDK namespaces.
- Data definitions do not depend on scene objects.
A code review question we use often:
> **If this SDK disappeared tomorrow, how many gameplay files would need editing?**
If the answer is “most of them,” add a boundary.
# 🚫 Common Design Pattern Mistakes in Mobile Game Projects
## Why overusing Singleton can make code fragile
Singletons hide dependencies and preserve state across tests and scenes. Prefer:
- Explicit constructor dependencies.
- Scoped service registries.
- Scene-level ownership.
- Scriptable configuration assets.
- Interfaces at infrastructure boundaries.
Use a Singleton only when its lifetime and uniqueness are genuine requirements.
## Why Service Locator can hide dependencies
A method that calls `Services.Get<AudioService>()` appears to have no dependencies. It actually depends on:
- Registration order.
- Global initialization.
- A particular service implementation.
- A functioning runtime container.
Make important dependencies visible in constructors or initialization methods.
## Why inheritance-heavy designs become difficult to extend
Inheritance is useful for genuine “is-a” relationships. It becomes brittle when behavior combinations multiply.
Prefer composition for combinations such as:
- Flying.
- Burning.
- Shielded.
- Invisible.
- Explosive.
- Networked.
A component or Strategy can be added without creating a new subclass for every combination.
## Why premature abstraction slows down development
Abstraction has a cost:
- More code.
- More indirection.
- More configuration.
- More debugging paths.
- More mental overhead.
The architecture article’s advice is balanced: design for likely change, but postpone low-level optimization and speculative generalization until evidence supports it.
## Signs that a pattern should be removed
Consider removing a pattern when:
- It has one implementation and no likely alternatives.
- It adds no testability or flexibility.
- Developers bypass it routinely.
- Its control flow is harder to explain than the original.
- Profiling identifies its overhead.
- It exists only because “patterns are good.”
Refactoring out a pattern is not failure. It is successful maintenance.
# 💻 Implementation Guidance for Unity, Unreal Engine, Godot, and Native Apps
## C# design patterns in Unity mobile games
Unity projects commonly combine:
- ScriptableObjects for data definitions.
- MonoBehaviours for engine-facing components.
- Plain C# classes for domain rules.
- UnityEvents or C# events for notifications.
- Addressables for asset delivery.
- ObjectPool for repeated objects.
- State and Strategy for gameplay.
Keep engine dependencies at the edges where possible. A plain C# damage calculator is easier to test than a MonoBehaviour that requires a loaded scene.
## C++ patterns in Unreal Engine projects
Unreal provides:
- Actor Components.
- Gameplay Tags.
- Behavior Trees.
- Subsystems.
- Gameplay Ability System.
- Replication frameworks.
Do not rebuild a framework that Unreal already supplies unless the project has a specific reason. Use Facade and Adapter boundaries around platform services and external SDKs.
## GDScript patterns in Godot
Godot’s nodes and signals naturally support:
- Component-style composition.
- Observer communication.
- Scene-based factories.
- State scripts.
- Resource-driven data.
Use signals deliberately. A signal should communicate a meaningful event, not become a mysterious project-wide radio station where nobody remembers who is listening.
## Swift and Kotlin patterns for native mobile games
Native mobile games often use:
- MVM for menus and account screens.
- Repository for data access.
- Use-case services for application logic.
- Flow or Combine for reactive updates.
- Dependency Injection for testing.
- Coordinator or State patterns for navigation.
For rendering-heavy gameplay, use an engine or specialized framework while keeping native UI services at the boundary.
## Adapting patterns to ECS and data-oriented technology stacks
ECS does not eliminate design patterns. It changes where they appear:
- State may be represented as components.
- Events may be streams or command buffers.
- Factories may create entity archetypes.
- Strategies may be systems or data-driven policies.
- Object pooling may be handled through entity reuse.
- Facades still protect external services.
The implementation vocabulary changes; the underlying design problems remain.
# 📊 Design Pattern Comparison Matrix
## Best patterns for performance
| Pattern | Performance opportunity | Performance risk | Recommendation |
|---|---|---|---|
| Object Pool | Reduces allocation churn | Retained memory and reset cost | Use for frequent short-lived objects |
| ECS | Improves locality and batching | Complexity and conversion overhead | Use for large homogeneous workloads |
| Flyweight | Shares immutable data | Indirection and data ownership confusion | Use for repeated definitions |
| Event-driven updates | Avoids unnecessary polling | Dispatch overhead | Use for infrequent changes |
| Factory | Centralizes optimized creation | May hide allocation | Pair with pooling where needed |
| Singleton | Avoids duplicate service instances | Global coupling, not speed by itself | Do not choose solely for performance |
## Best patterns for flexibility and scalability
| Pattern | Flexibility | Typical use |
|---|---:|---|
| Strategy | High | Combat, AI, targeting, progression |
| State | High | Game flow, AI, quests |
| Component | High | Entity composition |
| Factory | Medium-high | Content and object creation |
| Observer | High | UI and system notifications |
| Facade | Medium | SDK and subsystem boundaries |
| Abstract Factory | High | Platform or theme families |
## Best patterns for testability
| Pattern | Testing benefit |
|---|---|
| Dependency Injection | Replaces real dependencies with fakes |
| Command | Replays actions deterministically |
| State | Tests transitions independently |
| Strategy | Tests algorithms in isolation |
| Repository | Tests persistence without real storage |
| Facade | Tests integration through a stable surface |
| Observer | Verifies reactions to domain events |
## Best patterns for small teams and prototypes
Start with:
- State for clear modes.
- Factory for repeated creation.
- Object Pool for obvious allocation hotspots.
- Strategy for genuinely interchangeable behavior.
- Simple events for UI updates.
- Facade for external SDKs.
Avoid initially:
- Full ECS without a workload that needs it.
- Enterprise-grade DI containers.
- Abstract factories for one platform.
- Global event buses for every interaction.
- A generalized engine before you know what the game is.
## Best patterns for multiplayer and live-service games
Prioritize:
- Command for player intent.
- State for connection and match flow.
- Strategy for server rules.
- Repository for persistence.
- Facade for backend services.
- Event messaging for domain notifications.
- Versioned data contracts.
- Explicit module boundaries.
# 🛠️ A Step-by-Step Workflow for Applying Coding Patterns
## Start with gameplay requirements and constraints
Write down:
- Target devices.
- Expected entity counts.
- Offline requirements.
- Network model.
- Monetization.
- Save requirements.
- Live-event plans.
- Team size.
- Release cadence.
- Engine constraints.
Without this context, selecting patterns is like choosing shoes before learning whether you are hiking or attending a wedding.
## Identify repeated responsibilities and changing behavior
Look for:
- Repeated object creation.
- Repeated conditionals.
- Multiple implementations.
- Cross-system notifications.
- Hidden global dependencies.
- Expensive per-frame work.
- Systems likely to gain live content.
These are pattern candidates.
## Select the smallest useful abstraction
Choose the minimum structure that solves the problem:
- A method before a Strategy object.
- A direct event before an event bus.
- A factory before an abstract factory.
- A scoped service before a Singleton.
- A plain data structure before ECS.
This keeps the design understandable while leaving room to grow.
## Prototype, profile, test, and refactor
Use this loop:
1. Build the smallest playable version.
2. Test the feature on target devices.
3. Profile CPU, GPU, memory, and battery behavior.
4. Add tests around fragile rules.
5. Identify repeated change.
6. Introduce a pattern where evidence supports it.
7. Measure again.
The architecture resource’s practical wisdom is worth repeating: **it is easier to make a fun game fast than a fast game fun**. Performance matters, but do not optimize an unproven idea into a beautifully engineered disappointment.
## Document architectural decisions for the team
For each significant pattern, record:
- Problem.
- Context.
- Decision.
- Alternatives considered.
- Runtime implications.
- Testing approach.
- Removal criteria.
A short decision record can prevent future developers from asking, “Why is there an entire messaging framework for pausing the game?”
# 📚 Essential Resources for Game Programming Patterns
## Game Programming Patterns by Robert Nystrom
[Game Programming Patterns](https://gameprogramingpatterns.com/) remains one of the most practical references for game-specific architecture. Its strongest lesson is not memorizing names. It is recognizing recurring problems involving sequencing, behavior, decoupling, and optimization.
The book’s chapters are independent ideas, making it suitable for developers who want to apply one pattern without adopting an entire engine architecture.
## Gang of Four design patterns and object-oriented principles
The original [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.pearson.com/en-us/subject-catalog/p/design-patterns-elements-of-reusable-object-oriented-software/P20003258) established the classic vocabulary of creational, structural, and behavioral patterns.
Use it as a reference, not a rulebook. Game engines, mobile hardware, data-oriented systems, and modern language features may favor different implementations.
## Official Unity mobile optimization resources
Useful sources include:
- [Unity Mobile Optimization](https://docs.unity3d.com/460/Documentation/Manual/MobileOptimizationPracticalGuide.html)
- [Unity Profiler](https://docs.unity3d.com/Manual/Profiler.html)
- [Unity Object Pool](https://docs.unity3d.com/ScriptReference/Pool.ObjectPool_1.html)
- [Unity Entities](https://unity.com/ecs)
- [Unity Addressables](https://docs.unity3d.com/Packages/com.unity.addressables@latest/)
## Official Unreal Engine programming documentation
See:
- [Unreal Engine Programming](https://dev.epicgames.com/documentation/en-us/unreal-engine/programing-with-cplusplus-in-unreal-engine)
- [Actor Components](https://dev.epicgames.com/documentation/en-us/unreal-engine/components-in-unreal-engine)
- [Behavior Trees](https://dev.epicgames.com/documentation/en-us/unreal-engine/behavior-trees-in-unreal-engine)
- [Unreal Insights](https://dev.epicgames.com/documentation/en-us/unreal-engine/unreal-insights-in-unreal-engine)
## Godot architecture and performance documentation
See:
- [Godot Signals](https://docs.godotengine.org/en/stable/getting_started/step_by_step/signals.html)
- [Godot Performance](https://docs.godotengine.org/en/stable/tutorials/performance/index.html)
- [Godot Resources](https://docs.godotengine.org/en/stable/classes/class_resource.html)
- [Godot Nodes and Scenes](https://docs.godotengine.org/en/stable/getting_started/step_by_step/nodes_and_scenes.html)
# ❓ Frequently Asked Questions
## Which design patterns are most commonly used in mobile game development?
The most common are **State, Observer, Factory, Object Pool, Command, Strategy, Component, Facade, and Dependency Injection**.
State is especially common for game flow, animation, quests, and AI. Object Pool is common for repeated temporary objects. Observer or signals help UI and systems react to meaningful changes. Factory and Strategy support content growth without spreading conditional logic throughout the codebase.
The best combination depends on genre, engine, entity count, and team size. A puzzle game may need only State, Observer, and Factory. A multiplayer RPG may also need Command, Repository, DI, server-authoritative messaging, and data-oriented systems.
## How do you choose the right coding design pattern for a mobile game?
Use this sequence:
1. Describe the concrete problem.
2. Identify what changes and what must remain stable.
3. Check whether the code runs frequently.
4. Consider memory, battery, and debugging costs.
5. Compare the simplest direct solution with one or two patterns.
6. Prototype the feature.
7. Profile on real devices.
8. Keep the pattern only if it improves development or runtime behavior.
Do not select Singleton because every tutorial mentions it. Do not select ECS because a benchmark used a million entities when your game has twelve.
## What is the best architecture pattern for mobile game apps?
There is no single best architecture. A strong default is:
- Layered or Clean Architecture for boundaries.
- Component composition for entities.
- State for flow.
- Observer/events for meaningful notifications.
- Factory for creation.
- Strategy for interchangeable rules.
- Facade/Adapter for platform SDKs.
- Repository for saves and backend data.
- Dependency Injection for testable services.
For small games, simplify this stack. For large live-service games, strengthen module boundaries and data contracts.
## How can design patterns improve mobile game performance?
Patterns can help by:
- Reusing objects through Object Pool.
- Batching homogeneous data through ECS or data-oriented design.
- Avoiding unnecessary polling with event-driven updates.
- Reducing startup work through staged loading.
- Separating hot paths from flexible but slower abstractions.
- Limiting repeated asset and service initialization.
Patterns do not guarantee speed. Profiling must confirm the result. A badly implemented event bus can be slower than a direct call; a pool can consume too much memory; ECS can add conversion overhead for the wrong workload.
## Which design patterns are useful for managing game states on mobile devices?
Use the **State Pattern** for:
- Boot.
- Loading.
- Main menu.
- Gameplay.
- Pause.
- Game over.
- Reconnection.
- App backgrounding.
- Ad display.
- Store or login flows.
Use State within bounded systems too:
- Enemy AI.
- Combat.
- Quests.
- Tutorials.
- Animation.
Do not create one state machine for every variable in the game. Continuous values such as stamina or temperature may better represented as data, while discrete modes such as “stunned” or “attacking” fit State naturally.
## How do MVC, MVP, and MVM compare for mobile game development?
| Pattern | Best fit | Strength | Limitation |
|---|---|---|---|
| MVC | UI and menu systems | Familiar separation | Controller can become overloaded |
| MVP | Testable UI with explicit presenters | View logic is easier to isolate | More boilerplate |
| MVM/MVM | Reactive native UI and data binding | Strong separation of presentation state | Less natural for per-frame gameplay |
| Component/State | Real-time game entities | Fits engine lifecycles | Not a complete UI architecture |
For native Android and iOS menus, MVM is often a strong choice. For Unity gameplay, State, Component, and event-driven presentation usually fit more naturally. Choose based on the subsystem rather than forcing one model across the entire app.
## What coding patterns help mobile games scale across different platforms?
Use:
- **Facade** for a stable cross-platform API.
- **Adapter** for SDK-specific interfaces.
- **Abstract Factory** for platform-specific service families.
- **Dependency Injection** for test replacements.
- **Repository** for storage differences.
- **Strategy** for control or rendering variations.
- **State** for lifecycle differences.
Keep Android and iOS implementation details out of core gameplay. Platform services should return domain-level results such as “purchase verified” or “authentication cancelled,” not raw SDK objects.
## Should every mobile game use ECS?
No. ECS is valuable for large numbers of similar entities and data-oriented workloads. It may be unnecessary for a small narrative game, card game, or menu-heavy title.
Choose ECS when profiling or projected workload justifies it:
- Many entities.
- Repeated operations.
- Batch-friendly logic.
- Clear component data.
- A team prepared to learn the model.
Use traditional components or plain classes when entity behavior is highly unique or the project’s primary challenge is content production rather than simulation scale.
## Is Singleton suitable for mobile games?
Yes, but only for genuinely unique, stable-lifetime services. Audio, configuration, or a process-wide platform coordinator may qualify.
Avoid using Singleton for:
- Player state.
- Enemies.
- Match-specific objects.
- Anything requiring isolated tests.
- Services that may need multiple instances later.
Explicit dependencies are usually clearer and safer.
## What is the best pattern for mobile game enemy AI?
For straightforward AI, combine:
- State for patrol, chase, attack, flee, and stun.
- Strategy for target selection or attack choice.
- Navigation services for pathfinding.
For hierarchical or highly conditional AI, Behavior Trees or utility-based decision systems may be more suitable. The Unity discussion correctly presents State and Behavior Trees as alternatives rather than declaring one universally superior.
## How should design patterns be tested in a mobile game?
Test at multiple levels:
- Unit-test pure rules and strategies.
- Test State transitions.
- Test Commands with deterministic inputs.
- Test factories and pools for correct initialization.
- Integration-test saves, SDK facades, and scene loading.
- Profile performance on real devices.
- Run lifecycle, network, and interruption tests.
The most valuable tests are those that catch expensive regressions: corrupted saves, duplicate rewards, invalid purchases, soft locks, and frame-time spikes.
## When should a developer avoid using a design pattern?
Avoid one when it:
- Solves a hypothetical problem.
- Obscures simple behavior.
- Adds runtime cost to a hot path.
- Requires more code than the feature.
- Hides dependencies.
- Makes debugging harder.
- Is unsupported by the team’s skills.
- Cannot be removed without a major rewrite.
Patterns are optional tools. The strongest mobile architecture is often a deliberately boring one with a few excellent boundaries.




