Pull to refresh

Technical Game Design. Configs, balance and content in the example of PC strategy

Level of difficultyMedium
Reading time13 min
Original author: Konstantin Sakhnov

One of the common tasks that both beginners and experienced game designers face is describing a large amount of content to pass its parameters to the engine. This is not an easy task, given that it is very difficult to find materials on the technical aspects of game design. Well, let’s figure out how to transfer data to the engine.

Let's formulate a task: imagine we are working on a product that has a lot of typical content. Our task is to write all the content in a format that the game engine will accept.

I will review the whole process using the example of a game I am currently working on to make it clearer. It's a planetary terraforming sim/strategy with a StarCraft-like mission sequence, focused on story and narrative mechanics. The player is a representative of the Civilization of the Ancients, turning lifeless planets into paradise and populating them with elves, orcs and other intelligent beings.

Key mechanics:

- Construction of buildings on the planet and its terraforming;

- Development of the Void Generator talent tree.

The described mechanics let us know that there will be a large number of buildings in the game, and each will have a number of specific parameters. Resources are needed for the construction of buildings and their upgrades. Buildings can both produce them and add various effects that affect game entities. Increasing the efficiency of other buildings, for example.

1. Data Format Approval

The first task is to agree with programmers on the format in which we will transfer information about content to the engine.

There are many options for this. If the content that the game designer wants to see in the game is in a single instance, we could use the ScriptableObject mechanism or write data in scripts directly in Unity/UE. This is convenient when it is known for sure that there will be exactly 3 buildings in the game, or if we are dealing with unique objects in a scene.

In our case, there can be 30 or 100 buildings. Each of them has many levels of progression, each of which applies a certain effect on the planet, zone or building or produces resources. And most importantly, we cannot guarantee that in the future we will not want to add a couple of dozen more buildings or to remove some of the existing ones.

To complete this task, it is better to use JSON or XML data markup scripting languages. The implementation of configurations on the old Lua or more advanced YAML is far less common.

Fig 1. A fragment of the Confluence page with a list of parameters of a JSON script that describes scenarios
Fig 1. A fragment of the Confluence page with a list of parameters of a JSON script that describes scenarios

The game designer’s task in this case is to form a complete list of parameters for each type of object, indicating the type of data and possible limits.

The resulting list must be agreed with the programmers. They will turn the document created by the game designer into a description of the data structure in the game code.

Fig. 2. Screenshot of the data structure description for the JSON-config cost of upgrading buildings in Unity
Fig. 2. Screenshot of the data structure description for the JSON-config cost of upgrading buildings in Unity

2. Relationship Links and Data Structure

No objects in large games are usually isolated, they are always somehow interconnected with others. To make it easier and clearer to see all these connections and to form the game data structure, use database terminology (for example, SQL) and consider the list of the same buildings as a separate table.

Then it is important to remember such concepts as:

- Foreign keys — identifiers (usually in the form of natural numbers) by which objects from one table can receive information from others;

- Relationship types — the logic behind the use of internal and external keys. Usually there are:

— One-to-one: the identifier of an object, for example, a building, in one table fully corresponds to the same identifier in another;

— One-to-many: one building has many upgrade levels, each of which can have different properties;

— Many-to-many: Different building levels can apply different effects. For example, the Four-dimensional Plant building at level 5 opens an additional building slot in the zone where it is located. And Celestial Filatures also apply an effect that adds a new building slot to the zone. Note: If it is technically possible, try to create effects and other fields with unique IDs, preferring a one-to-many relationship.

- The normal form of a database is a set of rules that prevent data redundancy. There are several of them, there is quite a lot of information about this on the Internet.

It is easier to show the formation of the data structure of the project’s configuration files with an example. Let’s take a quick look at the mechanics of building construction.

The player’s planet is divided into zones, each consisting of hexes. Each hex can contain one building. In addition to buildings, there may be Sources and Anomalies on the map. The Source is a foundation for a building. For example, a quartz deposit will allow you to build in a given cell only one specific building that will mine stone. The Anomaly is a virtual container that contains effects that will start working after researching it, and / or resources that can be taken away by researching this anomaly.

Buildings can have various levels. Each level has a price that must be paid to upgrade a building to that level, a set of effects that the building gives at that level, and resources that are produced at that level.

One building can have different second levels. This means that when upgrading a building to level 2, the player chooses how to upgrade it.

Fig. 3. A fragment of the Confluence page with a description of building upgrades
Fig. 3. A fragment of the Confluence page with a description of building upgrades

As you can see in the screenshot, the Planet Cracker building (yes, I’m a Dead Space fan!) requires Metal for construction. Once built, it starts producing 1 Stone per turn. The player has the option to upgrade it twice. When upgrading to level 2, the player chooses one of two options: to increase the Stone production by another 1 or immediately by 2. The second option will cost the player more by 100% + 30% (upgrades inflation factor). When the building is upgraded to level 3, this building not only produces Stone, but also receives a special effect of player’s choice: gain 1 additional Metal or Stone per turn with a 50% chance.

Let’s design a data model that would allow us to describe such building upgrade possibilities.

Fig. 4. Relationships between content lists (tables) in configurations of buildings
Fig. 4. Relationships between content lists (tables) in configurations of buildings

The main table of the current model is Buildings. It lists all the buildings available in the game. Each of them has a unique numerical number — id (natural number). We will identify the building in all tables by this number. Let’s say we need to get a text description or an asset (for example, a 3D model) of a specific building. In this case, the program code runs through the Buildings table and finds an entry with a unique id. After that, it takes the necessary information from this entry.

Fig. 5. Google Sheets screenshot showing the Buildings table content snippet
Fig. 5. Google Sheets screenshot showing the Buildings table content snippet

In addition to the Buildings table, there is the Building_Levels table. It contains a list of all levels of all buildings. In particular, there will be 5 entries for the Planet Cracker building: one for the 1st level of construction and 2 each for the 2nd and 3rd levels. All of these entries will have a different id but the same building_id. It is a foreign key by which you can find a unique building from the Buildings list. Such a data structure allows the product to have a different number of levels with different bonuses for each building. Game designers will be able to design source-buildings that will simply extract resources and upgrade up to 10 times. Or complex spaceports that can only be upgraded a couple of times, but in 5 different ways. This is a demonstration of how a one-to-many relationship works.

Fig.6. Google Sheets screenshot showing the Building_Levels table content snippet
Fig.6. Google Sheets screenshot showing the Building_Levels table content snippet

As we have already said, upgrading a building to a new level, and choosing one of the options for such improvements, can have different costs. It makes sense that +3 production expansion should cost more than +1 expansion. Otherwise, we will make a mistake called the “imbalance of uselessness or hyper-usefulness”, according to Garfield: “Why buy something for a high price that is worse than a cheaper analogue?”. To design a different upgrade cost for each level, it is more convenient to introduce an additional table Building_Upgrade_Costs. Its structure is similar to the Level table, but now the foreign key referenced by entries in this table is not buildings, but specific levels. There is a list of resources needed for an upgrade on each level.

Fig.7. Google Sheets screenshot showing the Building_Upgrade_Costs table content snippet
Fig.7. Google Sheets screenshot showing the Building_Upgrade_Costs table content snippet

The Building_Effects and Building_Production tables have similar descriptions, they are responsible for special effects, like “50% probability of producing 1 Metal or 1 Stone” and for the amount of resources produced, respectively. An attentive reader might wonder about Cards and Cards_rares tables that are marked in the data structure of construction mechanics. In our game the player constructs buildings by playing cards and by moving them to the hex of choice.

3. Content Generation Pipeline

Let me remind you that we are looking at the process of working with configuration files and content description in the example of a PC strategy, which is being developed by the author. The game takes place on a planet, the player places buildings by dragging the corresponding cards on its hexes. Each turn player gets 1 card: a building foundation or a spell. From this brief description, the first steps to understanding the whole process are already being formed:

  1. Preparing of design documentation for game mechanics (buildings construction and upgrade);

  2. List of Possible Building Effects creation: Resource production. For example, +1 Energy per turn; Random drop. For example, gives a random resource every turn, with a 75% probability; Economic modifiers (coefficients). For example, +5% population growth rate; Complex effects with selectors and conditions. For example, all Stone sources in the area consume 1 less energy per level.

  3. List of Content (buildings) creation;

  4. Formation of the Excel / Google (or other) table structure, in which data will be written;

  5. Filling the table with content and its balancing;

  6. Formation and validation of data in the project’s own format or in one of the generally accepted formats for data transfer. For example, JSON, YAML, LUA …

  7. Transferring data to the engine, and creation of the build;

  8. Testing game data validity and balance.

Let’s take a closer look at some of the steps.

I will skip the creation of design documentation and the development of game mechanics, since this is a topic for a separate article.

Fig. 8. Screenshot of a fragment of the Confluence page with a description of the planet and buildings construction
Fig. 8. Screenshot of a fragment of the Confluence page with a description of the planet and buildings construction

The screenshot above shows that in order to describe the construction mechanics alone, we have prepared several documents at once, telling what is a planet, zones and hexes on it, how cards are played to create buildings, how they are placed in the scene, and so on. It is better to divide a huge document into small articles that reveal individual elements of the mechanics, connected into a single structure by a system of links that permeate the entire narrative. Fortunately, services for maintaining project and product documentation, such as Confluence, Notion and similar ones, are perfectly suited for this.

It is a good practice to separate content and mechanics description. It is not necessary to combine information about how buildings work, what kind of economy is behind them, and the list of these buildings itself into one big article. However, this is not a universal rule. This is just for the convenient information consumption. If your mechanics is limited and does not require hundreds of units, spells, levels, then it can be convenient to describe everything on one page.

I will skip the creation of a list with possible building effects (modifiers and game economy), as well as the list of all buildings in the game, since this block is specific to a particular game and everything can be completely different in your project. The main thing to know here is the logic of organizing the content structure, described in the Relationship Links and Data Structure section.

4. Formation and Filling of the Table of Contents

When game designer has approved content and product documentation, the question arises as to how to describe all this in technical terms. From the article, you already know that we have chosen the JSON markup language as one of the popular ways to describe content. Some people say that its advantage is in the familiar syntax that came from JavaScript, some that it’s easy to learn. I think that the main plus is the availability of ready-made free modules for serializing data from JSON / XML, you can find them at the asset store for Unity and UE. The experience of my students shows that learning JSON is a matter of several days of practice. It’s not the same as learning an engine or programming language. But to come up with your own data format and write a parser for it is a separate task for programmers. Moreover, each new game designer and programmer on the project will have to learn this format, while JSON, more or less, is already known to them or can be easily learned in order to apply it on other projects in the future.

Fig. 9. Screenshot of the Resources table in Google Sheets
Fig. 9. Screenshot of the Resources table in Google Sheets

To start working with buildings, you must first describe everything related to them: resources, cards, economy… An example of a table with a list of resources can be seen in the screenshot above.

Some studios and individual developers are wondering as to why waste time creating such tables if you can manually write configuration files in the Unity / Visual Studio editor or even enter all the data with the Scriptable Object. The answer to this question is quite simple.

If your game has 10 rows of data, you don’t need Google Sheets, JSON and such. The problem begins when you need to fill in hundreds of configuration files to describe the content, and if editing the balance of one game unit affects dozens of different tables.

Automation allows you to:

  1. Significantly speed up the description of current content and the addition of game updates;

  2. Implement automatic data integrity and validity checks to avoid broken information getting into the engine or game code;

  3. Automate the balance calculation;

  4. Automatically generate code to avoid typos caused by human error.

Fig. 10. Screenshot of the Buildings table in Google Sheets
Fig. 10. Screenshot of the Buildings table in Google Sheets

Please note that there is no information in the Buildings table on what each building does and how much it costs to build and to level up. The first part of the article details the relationship of tables describing buildings and how information about them is divided into separate scripts.

I will note that the text in the Name field is used solely for the convenience of game designers, and the real texts of the artistic description, the names and even the effects descriptions are placed in the localization file. The logic of its operation is based on the same principles as other tables.

Fig. 11. Screenshot of the localization file
Fig. 11. Screenshot of the localization file

In this example, you can see all the advantages of automation that we have identified above:

  1. Automatic checks in Google Sheets protect the game designer from incorrect content entry. Well, at least it warns them if incorrect data is entered. So, for example, when you select a group related to the localized text, options suitable for this group are automatically loaded in the sub-group field. For example, if we will select the Planet group, then it will not be possible to select sub-group keys that are not related to the planet. The same is true for all other tables: when specifying the range of numbers that the resource value in the resource table can take (min_value, max_value), you can only input a rational number from -maxInt to maxInt. Any other text will cause an error, warning the game designer that for the data input only digits are allowed. As a result, programmers can be certain that they will receive verified and valid configs from game designers.

  2. Cells highlighting helps you understand which data is not yet filled in. For example, in the screenshot with the localization file, we can see that the second line contains a template for the next localization key. We have chosen the Planet group and the Building sub-group, but have not yet described what kind of text will be written in this key. Therefore, the file highlights the Item field in red. In one of the lines below, the text in the Item field is filled in, but the translation is not entered, so the ru field is highlighted after the key (localization key). If the original language of the game is Russian, then you can set the table so that it highlights all fields in English, Spanish and other languages in which game designers have changed something for the Russian localization.

This way we will never forget to send the text, the original of which has changed, for re-translation.

An equally important part of content entry automation is the balance calculation. A typical situation is when game designers have to constantly add new content (in our case, buildings) and calculate their production, purchase costs, upgrades, and many other parameters from scratch. This is not only a waste of time, but also another area where one can make a mistake.

The basic principle in all game projects I’ve worked on is to automate everything, and never write the code yourself. Any manual work is another chance to make a mistake.

Fig. 12. Screenshot of the table showing the buildings upgrade cost per level
Fig. 12. Screenshot of the table showing the buildings upgrade cost per level

In the screenshot above, you can see that some of the parameters are calculated automatically. For example, we know that a building has no effects other than producing resources. Let’s say the Planet Cracker at level 1 produces 1 Stone per turn. Our task is to calculate the cost of this building construction. The game designers decided that at level 1 only Metal would be used for its construction. Therefore, we are going to calculate how much Metal would be needed for a building that produces 1 Stone. To do this, we need to know two things:

- The relation between the values of Metal and Stone;

- The number of turns in which the building pays off.

The first parameter is set by the weight coefficient in the resource table (see Fig. 9). The second one — by a constant fixed on a separate page. Knowing all this, the table calculates the cost of construction in Energy (the cheapest resource), and then translates it into a given resource — Metall. The table also takes into account a lot of other nuances and coefficients. For example, inflation caused by increased building levels or by the number of buildings in the zone.

I deliberately talk about the balance process not in great detail, because in order to fully describe it, you will need material for a separate small 3-hour lecture. Our current task is to understand and to make sure that balance and mathematics can and should also be automated.

5 Validating and Transferring Data to the Engine

The next step on the difficult path of a game designer creating content is to somehow encode the data from the calculated tables so that it can be transferred to the engine.

As I have mentioned before, we use the JSON format for this, however, nothing prevents you from choosing any other format to present data.

Pay attention to any screenshot from Google Sheets with configs (Fig. 5, 6, 7).

The last column always contains a cell for the JSON script.

Fig. 13. Screenshot of JSON script generation formula
Fig. 13. Screenshot of JSON script generation formula
Fig. 14. Screenshot of the final JSON script generated by the formula
Fig. 14. Screenshot of the final JSON script generated by the formula

Each data row eventually ends in a cell with a script, that contains the information written in the row. The next step is to check that the script generated by the formula contains working code without errors. To do this, you can use various online validators. They are easy to find in a search engine using the query “JSON online validator”.

Fig. 15. Screenshot of JSON code in an online parser that checks it for errors
Fig. 15. Screenshot of JSON code in an online parser that checks it for errors

After checking the data for errors, the last step is to use a script to merge all rows into one cell, from which you can copy the final text into the editor.

If you are not creating a build manually, but are using automatic creators instead, you can also add the function to automatically pull text from a given cell by overwriting a specific configuration file.

The final algorithm for the automated content creation can be briefly depicted in the diagram:

Fig. 16. Scheme of Work for content
Fig. 16. Scheme of Work for content

6 Instead of Conclusions

Thanks for reading this article to the end. I hope our example has been helpful to you. Although reading technical texts with a lot of tables can be quite boring, it is very important for the development of the so-called production culture in your team, company or indie startup. It doesn’t matter if your game is a big project with a multi-million budget or a small adventure from an independent team: if you are aiming for commercial success, automating the technical side of the development process is one of the most important elements of game creation. Truly great ideas are most often killed by production hell and project management mistakes.

Thank you for reading this long article!

Total votes 2: ↑2 and ↓0+2