💾 JSON Game Data #
In this post, we look at parsing JSON game data using the C++ nlohmann/json
library, written in C++11. I am working on a clone of the Arkanoid arcade from the 1980s, and
decided using a JSON file was the best way to store and load game configuration data. Here, I run
through my first impressions of the library.
Although the focus is a game that uses raylib for rendering, the code has wider applications in game code as well as wider C++ applications.
This is a learning in public post, so I would love to hear your opinion, especially if there is something here I might be able to improve on.
🧱 What we’re Building #
I have been working on a C++ clone of the Arkanoid arcade game using raylib for rendering. In the original game, the player has to destroy rows of bricks at the top of the screen. The rows are populated with bricks of different colours, and destroying bricks of some colours earns more point than others. Most bricks take a single hit to destroy, though silver bricks need two hits and gold bricks are indestructible.
Taking those scoring details and maintainability into account, I decided to put the brick
properties into a JSON file loaded on setup. I picked the nlohmann/json
library to parse JSON. There are other C++ JSON libraries available , and I settled on this one mostly because it looked popular and has good CMake integration.
I am loading JSON at initialization, and the JSON config file is small, so speed was not at the top of my wish list. If you are concerned about speed, for your project though, see these benchmarks comparing C and C++ JSON libraries .
In the rest of the post, we take a quick look at eh JSON file, the CMake nlohmann/json
config and then, some code snippets to see the library in action. You will find a link, further
down, to the project repo, which has full code examples.
JSON Config File #
I placed the file in an assets
directory at the root of the project:
nlohmann/json
supports importing data with default values, so although
I included hitsToDestroy
values for silver and gold bricks, I omitted
the value for the other coloured bricks. For those I will import with a default value of 1
.
⚙️ CMake nlohmann/json
Config #
The CMake integration was quite straightforward. I use CPM (instead of CMake FetchContent
) in the project to manage third-party libraries, and the CPM repo includes an nlohmann/json
example .
Observations:
-
You can download the CPM.cmake file from the CPM repo , and place it in a project
cmake
directory. -
With CPM you can pick a tag from a repo, just using its tag name, though I prefer to use commit
hashes, as above (line
2
). -
I included the
ASSETS_PATH
definition in line12
-13
to make the path available in source code (see examples, further down).
🖥️ Adding JSON parsing code #
I am used to serde for parsing JSON in Rust , which has quite detailed type checking. nlohmann/json
is a little
more relaxed in this regard, though I suppose an advantage is that you can get going quicker, and it
might suit workflows with high levels of iteration.
Parsing JSON Game Data #
To parse the JSON file, I just called nlohmann::json::parse()
,
passing in the file std::ifstream
. That function returns an nlohmann::json
object with the JSON data that has convenient access methods (see following section). I used the
spdlog library for logging.
The nlohmann/json
parse
function throws an exception if it encounters an unexpected token in the JSON or encounters an issue in converting input bytes
to Unicode (the library has full UTF-8 support and partial UTF-16 support).
Using the ASSETS_PATH
variable set in the CMakeLists.txt
file above, I can create a variable for the path to my JSON data file (assets/level_bricks.json
), in C++ source code, thus:
Reading Parsed Game Data #
There are three common methods for accessing JSON data returned by the nlohmann:json::parse
function:
-
data["KEY"]
for unchecked access, -
data.at("KEY")
for checked access; and -
data.value("KEY", <default_value>)
to return the provided default value when the key is absent.
Unchecked Element Access #
The first, like the std::map
accessor can be used to mutate the JSON
data. It returns null
if the key is absent.
I used the []
operator here to access the root level levelBricks
array, then again, to index into the rows
field of the array’s
first element.
You also see the size
method in use here, which will return the length
of a JSON array, the number of fields in a JSON object or 1
, if it
is called on a scalar. It returns 0
if called on a null
nlohmann::json
object, which happens if you access a field that does
not exist in the parsed data.
Checked Element Access #
This time I use checked access, via the at
method (in line 7
). This throws an exception if the colour
field is missing. The library
also provides a C++11 range-based loop access to elements, as used in line 3
.
Value or Default Element Access #
Finally, we have value or default access. For the game, most bricks only need one hit to be
destroyed, and the silver needs two, while the gold brick is indestructible. Rather than add a
value for this field for all bricks, I decided to set the value to 1
, as a default when it is absent.
The value
member on the nlohmann::json
object (used in line 5
) does exactly what I am looking for
here. Of course, it works similarly for string fields, for example.
🗳 Poll #
🙌🏽 Parsing JSON Game Data: Wrapping Up #
In this post on parsing JSON game data, we saw how you might use nlohmann/json
to load data in a C++ game. More specifically, we saw:
-
how to set up
nlohmann/json
CMake config; - the main JSON data object access methods; and
- parsing and other useful methods provided by the library.
I hope you found this useful. As promised, you can get the full project code on the Rodney Lab GitHub repo . Do let me know if you found this content useful and would like to see more similar content. Also reach out if there is anything I could improve to provide a better experience for you.
🙏🏽 Parsing JSON Game Data: Feedback #
If you have found this post useful, see links below for further related content on this site. Let me know if there are any ways I can improve on it. I hope you will use the code or starter in your own projects. Be sure to share your work on X, giving me a mention, so I can see what you did. Finally, be sure to let me know ideas for other short videos you would like to see. Read on to find ways to get in touch, further below. If you have found this post useful, even though you can only afford even a tiny contribution, please consider supporting me through Buy me a Coffee.
Finally, feel free to share the post on your social media accounts for all your followers who will find it useful. As well as leaving a comment below, you can get in touch via @askRodney on X (previously Twitter) and also, join the #rodney Element Matrix room. Also, see further ways to get in touch with Rodney Lab. I post regularly on Game Dev as well as Rust and C++ (among other topics). Also, subscribe to the newsletter to keep up-to-date with our latest projects.