Welcome to this tutorial about utilizing Contentful within the game development lifecycle. Contentful can be a powerful tool for game studios to efficiently create game content across many disparate teams.
In this post, we will be focusing on getting quickly set up within Unity and having live content displaying within a scene during gameplay. You can check out the source code on GitHub for reference.
Unity is a real-time 3D development platform that is widely used in the video game industry. While video games were originally the platform’s main focus, other sectors such as film and TV, automotive, and geospatial have been starting to adopt Unity into their pipeline.
We will be creating an in-game shop that will display a set of specified items, their prices, and stats, as well as a highlight section to display items that you really want your players to see.
You will need the following in order to complete this guide:
A Contentful account. If you don't have one, you can sign up for one here.
A Unity account. If you are new to Unity, sign up here.
Intermediate knowledge of Unity and C#.
Unity Hub. You can download it here.
Unity Editor version 2022.3.15f1 LTS or later.
Note: This tutorial will be using Visual Studio 2022 since this is what ships by default with Unity. But any other IDE suited for C# development will work.
Creating content types in Contentful
Content types are an integral part of Contentful. They are a model of your content. These are the equivalent of structs or classes within C#. Building games by leveraging Contentful encourages a data-first approach to planning which allows you to easily integrate your content into a game.
While logged in, navigate to Contentful and create a new space.
We will be creating a shop inside Unity. So, we will first need to create a series of content types.
1. Game Item
We will need to define the data a game item will contain.
Create a content type named Game Item. Then add the following fields:
Title (Short text): The title of the game item (We want to avoid using Name, as this is a reserved word inside of Unity)
Strength (Integer): This is an in-game stat
Defense (Integer): This is an in-game stat
Speed (Integer): This is an in-game stat
2. Shop Item
Next, we need to create a content type that will hold data pertaining to the game item within the shop.
Create a content type named Shop Item. Then add the following fields:
Title (Short text): This is the title that will be displayed on the shop card
Description (Long text): A description about the item
Price (Integer): How much the item will cost
On Sale (Boolean): Let the player know if the item is on sale
Game Item (One reference, that only accepts the Game Item content type): The actual game item
3. Shop Container
Lastly, we need to create a container to hold all of the shop items. These containers will be how we retrieve all of our shop data in-game.
Create a content type named Shop Container. Then add the following fields:
Title (Short text): Name of the shop
Highlight (Many References in content model that only accepts the Shop Item content type): The highlight section of the store
Shop Items (Many References in content model that only accepts the Shop Item content type): The rest of the in-game shop’s inventory
Creating entries in Contentful
Entries are instances of the content. Similar to how ScriptableObjects are based off of a class defining the data, entries are based on content types within Contentful.
Create a few different Game Items. Ensure all of the fields are filled out.
Then, for as many Game Items you have, create the same amount of Shop Items. Don’t forget to link your Game Item!
Finally, create one Shop Container and link every Shop Item you’ve created in either the Highlight or Shop Items field.
Creating the Unity project
From the Unity Hub click on “New Project.”
Verify that your Editor Version is 2022.3.15f1 or later.
Select the “3D Core” template.
Give your project a fun name and click “Create Project.”
Install Contentful CSharp library
There are many ways to install Nuget packages in Unity.
Select “Download Package” in the sidebar.
This will download a .nuget file, which is just a fancy zip. (https://stackoverflow.com/questions/62929717/why-do-many-file-formats-are-disguised-zip-files)
Use your file unpacker of choice (WinRAR, 7zip, etc.).
Extract the lib folder.
Create a Libraries folder in your Unity Assets, add your contentful.csharp.<VersionNumber> folder.
Setting up a connection to the ContentDeliveryAPI
One of Contentful’s most powerful features (among many) is our globally distributed CDN, known as the Content Delivery API (CDA). This prioritizes servers closest to your players, minimizing latency as well as improving overall availability of content. Using the Contentful CSharp library we just downloaded allows us to easily tap into the CDA.
Obtaining the credentials
In the upper right hand corner of Contentful there is a Settings dropdown. Click on Settings and then select “API keys.”
For this guide, we will be creating our own API key. Click on “Add API Key” in the upper right hand corner and name it “UnityGame.”
Once you’ve created your new API key, it should take you to a page showing the Space ID and Content Delivery API-access token. Copy these somewhere you can easily reference; we will need these when we start using the Contentful CSharp library.
Creating the service
To work with the Contentful Delivery API, we will create a singleton called ContentfulService. This class will be responsible for setting up the ContentfulClient and getting a specified entry.
Right click in the Project view and select Create > Folder and name it Services.
Then inside the Services folder, right click and select Create > C# Script, naming this script ContentfulService. Give ContentfulService the following code:
In order to set up a ContentfulClient correctly, we will need to fill out three pieces of data:
deliveryToken — The Contentful Delivery API token.
spaceId — The ID of the space that the CDA token is related to.
environment — By default, this is “master” but your team may be utilizing other environments (such as a staging environment).
When the game starts, the Awake() method in ContentfulService will run, instantiating a new ContentfulClient. All subsequent requests will be made with that ContentfulClient until the player closes their game.
This service also provides a GetEntry() method. This method is generic and will require us to specify the data we are expecting to get back from the CDA.
In this guide, we will be utilizing the ContentfulClient.GetEntries() method, with the QueryBuilder class, to create a call that will fetch the singular shop entry.
We will be requesting that the sys.id of the entry matches our Shop Container’s entry ID.
Since our entry has three layers (Shop Container > Shop Item > Game Item), we must use the QueryBuilder.Include() method to specify how many layers we wish to receive.
var builder = new QueryBuilder<T>().FieldEquals(f => f.Sys.Id, entryId).Include(3);
Creating the data structures around our content types
In order for us to map data from Contentful to C#, we will need to create some classes that represent our content types.
Create a new folder named EntryData, this will house all of our content type classes.
Next, we will want to create an interface that the classes, which represent the content types, will utilize. This enables us to ensure that all entries will have SystemProperties.
Create a C# script named IEntity and give it the following code:
SystemProperties is all the metadata pertaining to a Contentful entry. Including data such as content type, modified date, created date, etc.
Now that we have our interface, let’s create our game item! As you can see, it’s a one-to-one representation of our content type. Short text becomes a string, and integer becomes int.
Note: If you want to exclude a property, you can simply just not include it in the class. But know that the data will still be transmitted to the player’s game client.
One class down, two to go. Logically, the Shop Item class comes next, since it is reliant on a GameItem reference.
You can see that referencing a GameItem in C# is exactly the same as referencing a GameItem content type in Contentful!
Last but not least, the Shop Container. Everything is pretty much the same as the last two classes, except we are now dealing with many references. Thankfully, these simply convert to Lists in C#.
Displaying your content from Contentful
We will want to first create a game object in our scene to hold our ContentfulService:
Right click in the hierarchy and create a new empty game object.
Attach the ContentfulService script to the game object.
Fill out deliveryToken, spaceId, and environment with the correct data.
Hit play and verify no console errors appear. Now we'll create the UI.
Creating the UI: ShopCard Prefab
Step one is to create a Canvas.
Then create a Panel and set it to a width of 200 and a height of 250.
Next, add a TextMeshPro component for the title.
Then add a TextMeshPro component for the price.
Add a TextMeshPro for the description.
Add a TextMeshPro for the “On Sale” status.
Create a new empty GameObject and add a Vertical Layout Group. Make sure to check Height for the “Control Child Size” option.
Add a TextMeshPro inside of this new Vertical Layout Group for the Strength, Defense, and Speed stat.
Creating the UI: Shop Prefab
Create a Panel and add a Vertical Layout Group component. Make sure to check Width and Height for the “Control Child Size” option.
Inside the previously created Panel, nest two new Panels with Horizontal Layout Group components attached to them.
We designed our UI, now we need to create some scripts to control it. Each prefab we’ve created will have its own script to control what is displayed.
Controlling the UI: ShopCard UI
Next we will create the ShopCardUI class. This controls the data shown on the shop card.
Attach this script to the ShopItem prefab and make sure to assign all the fields.
Controlling the UI: Shop
Lastly, the Shop class will be responsible for requesting the shop data from the service. Then populating the shop with ShopCards.
Attach this script to the Shop prefab and fill it out.
We will need the entry id of the shop we created in Contentful to fill out the ShopId property. To get the entry id:
Go to the content tab in Contentful.
Click the triple dot to the right of the shop.
Click “Copy entry ID” and then paste it into the ShopId field in Unity.
Now that we have all of our code and UI created, we can test out our creation. Make sure the ContentfulService and Shop prefab are in the scene. Hit the play button at the top and watch your shop populate!
Look how easy you can change it!
We are at the point where we are ready to build and show off the true magic of using Contentful: live content updates.
Let’s create a build of your Unity game now:
In the upper left corner, select File > Build And Run.
This will ask for a folder. Create a new folder named Builds and select that folder.
You have successfully built your game! It should automatically run. Please close this and head back to Contentful.
Make a few changes to some items inside of Contentful and hit publish.
Run your game’s executable from the Build folder again. You can see the changes you made within Contentful, all without having to rebuild your game.
To summarize what we have done:
Created a new Contentful space to house our game’s content types.
Made entries to represent our game’s items and shop.
Created a service that applies our credentials and allows us to easily use the CDA throughout our game, by utilizing the ContentfulClient.
Created classes to mirror our content types from contentful.
Created a shop that displays up-to-date items based off of content within Contentful, without the need for a new development build.
This article just scratches the surface of what Contentful can do to empower the game development process. Here are a few quick potentials:
Composition of many different types of assets (3d models, textures, sound, etc.).
A straightforward localization solution. Enable game designers and content teams to make changes to game content regardless of technical expertise.
Thanks for reading, I hope you found this guide useful! And don't forget, you can check out the complementary repo on GitHub for reference.