In this post you will learn what architecture patterns exist and discuss the most popular ones. This post is not tied to any particular programming language, but it is tied to OOP, so you can safely read it and project the information to any OOP language you know.
Let’s start with the question “Why do I need it?”. Let’s say you’ve written a tic-tac-toe game in a single Game class. A couple days later, you decide to add an AD-viewer at the end of the game. Where would you add it? In the Game class, of course. After a couple more days, you want to add a leaderboard so that the player knows who wins one level faster. For this you need to implement player accounts and saving the results on the server. And you boldly add all the code to the Game class too. And then you decide to add online tournaments to your game. And then… you realize that your Game class already takes more than 10 thousand lines! What do you do? That’s right, you have to start breaking it down into classes. And after some time of refactoring, instead of the Game class you have the classes Game, Board, Account, ServerStorage, Tournaments and so on. All that remains is to figure out how the Tournaments class can get information from Account or how Board should know some information from Game.
Everything is static

The first and easiest thing that 90% of developers think of is to use static fields. You go to the Game class and create all the other classes in it and make the references public and static. Now the Board class can easily find out the player’s name via Game.Account.Name or Tournaments can find out how long it took you to complete a level via Game.Board.TimeWhenLevelFinished. Congratulations, you have invented the Singleton pattern.
However, it can get to the point where such references can become very large, such as “Game.Board.Round.Bot.LastChoice.Id“. If you don’t like it, this problem is solved by a pattern called ServiceLocator. You can create a class with this name and make it static. The purpose of this class is to store references to all other classes and give any of them on request. You should have something like this:
static class ServiceLocator:
MapCollection<type, class> gameClasses;
static method void Add(class classToSave):
gameClasses.Add(classToSave);
static method class Get(type typeOfClass):
findedClass = gameClasses.Find(myClass where myClass.type == typeOfClass);
return findedClass;
Now somewhere in the Game class you create all your other classes.
...
Board board = create Board();
ServiceLocator.Add(board);
...
And then in any other class you get all the information you need. For example:
class Tournament:
...
Board board = ServiceLocalot.Get(type(Board)) as Board;
integer lastId = board.Round.id;
...
And so you can store absolutely any class in ServiceLocator. There is only a restriction that it must be one and unique. But this problem is also solved if you have interfaces in your language. Then you can make many classes as descendants of one interface, and in ServiceLocator make one more Get method, which will return a collection of descendants from one interface.
Now you have no limitations to write a game of any complexity and elaboration. Experienced programmers probably think I’m kidding, but I’m not. Most of the games that I know and that are very popular are written this way. And this code didn’t stop them from making millions. Or maybe even contributed to it? Who knows 😀 So if you are a beginner or a developer who doesn’t have a professional disease of always writing clean code, you can safely stop reading this article and go make a game. But if you are interested in how you can organize your code differently, then keep reading.
MV* – Most wanted *
While you were implementing the Tournament class, you noticed that it became responsible for scoring, for sending scores and player data to the server, and for rendering information on the screen. It would be nice to do these things separately, because it will be much more convenient to write code in the future and find the causes of bugs. The Model View * family of architectures will help you. What does this asterisk stand for? It is an unknown entity that controls the first two. Unfortunately or fortunately, developers have not agreed among themselves what this entity is, so a whole variety of these architectures have appeared. Here are the most popular ones: MVC (C – Controller), MVP (P – Presenter), MVVM (VM – ViewModel). To understand their differences, let’s look at each one separately.
MVC

- Model is a class that stores some data in the form of fields and properties (position, color, hp, time etc.). It should not contain any logic.
- View is what the player sees and hears. It can contain methods DrawPicture, PlayAnimation, and everything that relates to the visualization of our data.
- Controller – a class that takes data from Model and calls methods from View based on them. It can often store multiple Models and manage multiple Views at the same time.
In an MVC View, everything is managed by both Controller and Model. A Controller can update a Model and then directly call the View to update by passing data, or it can simply update a Model and the View will update automatically on an event.
Let’s take a simple example: a player presses the Pause button in a mobile game. Controller creates a Pause button (this is our View). Inside the View there is an onClick event. The Controller subscribes to this event and waits. Once onClick is called, the Controller accesses another View, PausePopup, and calls its Show method and takes the Model GameState and makes IsPause = true in it. I suggest you think of Controller as a description of behavior.
class PauseController:
PauseModel model;
PauseButtonView buttonView;
PausePopupView popupView;
...
buttonView.onClick.Listen(onButtonClicked);
...
method void onButtonClicked():
buttonView.SetInteractable(false);
popupView.SetVisible(true);
model.GameState.IsPause = true;
...
MVP

- Model is a class that stores some sort of data in the form of fields and properties. As in MVC.
- View is what the player sees and hears. As in MVC.
- Presenter is a class that listens to View, takes data from Model and updates View based on it.
Unlike Controller, which can control multiple Views, Presenter controls only one View or only a part of it. That is, in MVP it is normal for the same window to be updated by multiple Presenters. Also in MVP, often a View has public properties so that the Presenter updates the View by itself.
The same example with the pause button fits here, but now the View can’t be updated by the Model itself, and the Presenter, unlike the Controller, can’t be associated with both the button and a separate popup at the same time. In this case there will be a PauseButtonPresenter for the button and a PausePopupPresenter for the popup, and they work separately through the Model binding.
class PauseButtonPresenter:
PauseModel model;
PauseButtonView buttonView;
...
buttonView.onClick.Listen(onButtonClicked);
...
method void onButtonClicked():
buttonView.Interactable = false;
model.PauseInvoked();
...
class PausePopupPresenter:
PauseModel model;
PausePopupView popupView;
...
model.IsPauseInvoked.Listen(ShowPopup);
...
method void ShowPopup():
model.GameState.IsPause = true;
popupView.Graphic.Show();
popupView.Animation.PlayPopAnimation();
...
MVVM

- Model is a class that stores both data and business logic.
- View is what the player sees and hears. It is updated automatically through ViewModel via the data binding.
- ViewModel is a class that listens to View, takes data from Model and changes View values. In doing so, the View is updated reactively by itself.
It is important to know that ViewModel can manage multiple Views. For example PlayerViewModel can update the number of lives above the character and somewhere in the UI at the same time.
For example, a weapon shot is called. View reports that a shot has been fired, ViewModel changes the number of bullets in Model, and View that draws the number of bullets is updated automatically.
class PlayerModel:
int BulletsCount;
class PlayerView:
event Shoot;
uiText bulletsLabel;
method void Initialize(PlayerModel model):
buttetsLabel.bind(model.ButtetsCount);
method void OnShoot():
Shoot.Invoke();
class PlayerViewModel:
PlayerModel model;
PlayerView view;
...
view.Shoot.Listen(OnShoot);
...
method void OnShoot():
model.BulletsCount = model.BulletsCount - 1;
Which one to choose?
In fact, the choice of architecture is always a personal preference and experience of the developer. Any project can be written on any architecture. But if you ask me, I will answer like this:
- MVVM – if you have a project with a huge amount of View and information, and it’s hard for you to come up with a proper mechanism to update and interact this data without “macaroni” (MMO, RTS).
- MVC– if your project is casual and mostly based on UI only. Then it will be easy to organize connections of multiple Controllers through Models (Hyper-Casual, Casual games).
- MVP – all other projects. If you have direct control over characters and this game is not about UI control, then it is better to have a specific Presenter control your View and have easy access to data modification and visualization (Shooters, Roguelike, Actions).
Entity Component System

Entity Components System, or ECS, is a completely different view to the approach of organizing code and relationships in a project. Unlike the previous ones, here you need to know some nuances:
- ECS is about flexibility in modifying objects
- ECS is a flat architecture (know everything about everything)
- There is no single place to store data in ECS. That is, there are no Models
Many developers will say that ECS is primarily about high performance, but that’s not true. Yes, if you start searching on the internet how ECS works, you can see articles about arrays, bit operations, smart memory handling and so on. But in fact ECS only allows you to implement a framework with high performance. In fact, ECS is about convenience, flexibility and creating objects like in a constructor.
Let’s look at the main parts of this approach:
- Entity (E) – the object/structure and/or even the id of any object.
- Component (C) – a data structure that stores some information and is related to Entity.
- System (S) – a class that walks Entities through sets of Components and changes data in Components.
I advise you to consider Entity as a normal container for a set of Components and nothing more. Even if it is a class in your framework, it still won’t have any logic inside. Entity is usually stored in a World container. There can be one or many, but the goal is to store a set of Entity and output them to systems on request. Their Component can be anything: player coordinates, number of lives, any boolean, text, a reference to a 3D model or sprite, a reference to an animation component, and so on. A component cannot exist separately, it is always part of an Entity. Think of a Component as a Lego construction cube. System has 2 purposes: to find Entity by a set of components and to modify data in these or other components.
There are a lot of ECS implementations, but I will try to show how to use them using pseudocode:
struct Health is Component:
int Value;
struct Player is Component:
//empty
struct Enemy is Component:
//also empty
struct HasDamage is Component:
//empty
class CreateCharactersSystem:
method Initialize():
Entity playerEntity = EcsWorld.CreateEntity(); //create entity and add to World
playerEntity.Add(Health(10)); //Add Health component with 10 value
playerEntity.Add(Player); //Add Player component (as a tag)
Entity enemyEntity = EcsWorld.CreateEntity();
enemyEntity.Add(Health(5));
enemyEntity.Add(Enemy)
class DamageEnemySystem:
method Execute():
Array<Entity> entities = EcsWorld.GetWith(Health, HasDamage).Without(Player); //find entities by components names
foreach(Entity entity in entities): //collection of 1 entity with components(Health, Enemy, HasDamage)
Health health = entity.Get(Health); //get component by name
health.Value = health.Value - 1; //change value
entity.Replace(health); //replace with new value
And this is the simplest use case. Imagine you have a Burning component and a system that creates fire particles on Entities that have that component. Now, by adding this component, you can make your character, grass, wood, and water burn. Wait, water can’t burn. Exactly, and that’s one of the two main problems with ECS. Since it allows you to add any components to any Entity, it’s sometimes hard to predict the future behaviour of all objects and possible bugs. So in a BurnSystem you have to check that the object is not water, or add a Wet component so that you don’t create fire particles on everything.
The second problem is the rapid growth of the amount of code in the project. If in Singleton or MVP to implement a first-person camera with the functionality of walking, rotating the camera and jumping, you can do with 1-2 classes, in ECS you will have about 10 classes or more.
So if you are an new developer, I wouldn’t recommend going straight to ECS. Try your hand at MV* architectures for a start, and when you feel confident in them and want more flexibility, you can safely try to make a new project on ECS.
So what kind of games is this architecture suitable for. Many will say “those with lots of data and lots of the same or similar objects”. Most often they mean RTS or simulations with 100 thousand fish. Indeed, since the system does not work with specific objects but operates on a set of components, these are the examples that people think of first, because it makes sense. But in fact with the help of ECS you can write a project of any complexity, even if you have all objects are unique and present in a single instance. After all, we should not forget that ECS is about flexibility. However, I would not advise you to write tic-tac-toe games without support and development plans or similar games on ECS, because if this game is faster and easier to write in one or two classes in an hour, why spend the whole day on it.