Hello, world! I’m Matt Graber. I just finished my undergrad at the University of Maryland. I started my game development career back in freshman year in the UMD AR club. I used to teach other students how to create augmented and virtual reality experiences with Unity, a cross-platform game engine. I also enjoy informal game jams and larger projects in Unity with fellow developer friends.
Recently, I won the sponsored prize at the Bitcamp hackathon for building Package Person —an arcade game that notifies players of their status on the leaderboard. It was an exciting hackathon and also a learning experience for me. I learned how to use Courier and also how to use Unity with C# to create automatic POST requests to an API server—a teaser of what I will share later on.
I got featured in Courier’s live stream to build a notification-based game with Unity Engine, Courier, Twilio, and Mailjet. In this article, I will walk through the design of this game, called Rain Spikes, and provide a step-by-step explanation of how I used Courier to integrate notifications into the game.
Rain Spikes: The design of the game
People are naturally competitive. Even though Rain Spikes is simple, it’s addicting because players get notified about their score via email and text messaging, which prompts them to try it again and again and again.
Once the game starts, the player uses arrow keys to move a square from left to right to dodge the falling spikes. The more spikes they dodge, the more points they gain. If a spike hits your square, the game ends with a prompt to fill in your details—name, phone number, email, and memo (a message to include in the email). When you click submit, an automated email or an SMS message is sent showing your end score and the memo. Here’s how the game works:
Let’s go into a little bit of the design architecture for this game. First, if you don’t know, everything in Unity is object-oriented and is based on game objects. For example, the player game object (the object the player controls) is the square. The player game object has two components attached to it: the Sprite Renderer, which renders 2D and 3D objects, and Box Collider 2D, which detects collisions (in this game, with the falling spikes).
Finally, the last component I implemented as a script is the player control component, which enables the player to move the box with the left and right arrow keys independently of the frame rate.
As I said earlier, I wanted to add notifications to give Rain Spikes a competitive, addicting edge. So here’s how I did it.
How I added notifications using Courier to notify players of their score
Courier’s API allowed me to use the information collected in the end-game form to send notifications whenever the game ends. Of course, the emails and text messages are opt-in, of course—nobody wants to design an app that spams people with unwanted emails.
Step 1: I created a basic game with Unity Engine. While this article focuses on my Courier integration into the game, here is a recommended beginner-friendly tutorial to create a game with Unity Engine. Feel free to check out my code for this game
on GitHub.
Step 2: I already had an account on Courier, so all I needed was to login and click on create a notification. If you don’t have a Courier account, it’s a simple sign-up.
Step 3: Courier has different channels to deploy notifications from the exact location. So all I had to do was choose the specific channels for this game: Mailjet for emails and Twilio for SMS messages.
Step 4: Next, I had to write out the email message for Mailjet:
Hello {playerName},
You recently scored {score} while playing that Courier-Unity integration demo game!
You sent the following memo to yourself:
{memo}
You should play again sometime!
playerName, score, and memo are assigned variables to fetch data from the game. So by assigning these variables, I sent values from the game to display as part of the message. For the memo and score variable, I made them conditionals—if the memo is not empty, the memo will be displayed. So these fields will only be displayed if the player actually submitted a memo or has a score. Adding conditionals on Courier is a lot easier than figuring out all the logic on the C# side.
Step 5: The next thing was to replicate the same message for Twilio. In Courier, it is easy to drag and drop the text because they are shared components. Thus, it saves the time of typing everything out again.
Step 6: After adding the messages, I went over to preview and wrote a test event, and checked if the notifications were working. The test event contains the assigned variables—playerName, score, email, phone number—and test values.
{
"data": {
"playerName":"Billy",
"score":4,
"memo":"hello billy here"
},
"profile": {
"email":"dummyemail@gmail.com",
"phone_number":"555555555"
},
"override": {}
}
Step 7: After previewing the notifications and testing everything was working, I published changes.
Step 8: Now, this is the tricky part. Currently, Courier has SDKs for Ruby, Python, Go, Java, etc. Unfortunately, there is none for C#. These SDKs generate sample code for sending notifications to the programming languages. It was not much of an issue. All I had to do was create a web request from Unity following the curl logic on Courier.
Step 9: Before starting the notification script code, I had to get references for each input field to fetch data to the script. In the Unity Engine inspector, the input field has a component called TextMeshPro (TMP). TMP is the “ultimate text solution” in Unity Engine.
Here’s what the notification script code looks like:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using TMPro;
public class Notifications : MonoBehaviour
{
public TMP_InputField nameInput;
public TMP_InputField emailInput;
public TMP_InputField phoneInput;
public TMP_InputField memoInput;
private GameManager gameManager;
const string EVENT_ID = "";
const string AUTH_KEY = "";
// Start is called before the first frame update
void Start()
{
gameManager = GetComponent<GameManager>();
}
public void Submit()
{
StartCoroutine(SendNotification());
}
private IEnumerator SendNotification()
{
WWWForm form = new WWWForm();
form.AddField("event", EVENT_ID);
form.AddField("recipient", nameInput.text);
form.AddField("override", "{}");
form.AddField("data", "{\"playerName\":\"" + nameInput.text + "\"," +
"\"score\":" + gameManager.GetScore() + "," +
"\"memo\":\"" + memoInput.text + "\"}");
form.AddField("profile", "{\"email\":\"" + emailInput.text + "\"," +
"\"phone_number\":\"" + phoneInput.text + "\"}");
using (UnityWebRequest www = UnityWebRequest.Post("https://api.courier.com/send", form))
{
www.SetRequestHeader("Authorization", "Bearer " + AUTH_KEY);
yield return www.SendWebRequest();
if (www.result != UnityWebRequest.Result.Success)
{
Debug.Log(www.error);
}
else
{
Debug.Log("Form upload complete!");
// reload the scene to play again
SceneManager.LoadScene(0);
}
}
}
}
Don’t get overwhelmed: Here’s a breakdown of the different methods and classes I used in this script.
-
public class notifications: public class notifications handle the input fields for name, email, phone number, and memo.The GameManger input field is private because that is where the score will be stored. In order to create this method, I imported the TextMeshPro with a
using
statement. Importing TMP gives the flexibility to use input fields in Unity Engine. - void Start: void Start method handles the private GameManager reference to the game object in the Unity engine inspector.
- public void Submit: The Submit method handles what happens when a player hits the submit button. It basically starts a coroutine (StartCoroutine) in order to send a message. The coroutine in Unity is responsible for executing the game logic over a number of frames. A coroutine is important because it sends web requests in Unity.
- private IEnumerator SendNotifications: The private IEnumerator method is the coroutine that handles all frame iterations. In this method, I used the class WWWform to construct a form that would hold all the data that will be sent to Courier.
- UnityWebRequest: UnityWebRequest class is the class that sends the POST request(form) to Courier.
- SetRequestHeader: For the request to work, I had to set a request header to handle the authorization and authentication.
- yield return: yield return handles an async operation (POST request to Courier API) and pauses the execution until the request is sent.
- Debug.Log: Debug.Log is used to print to the console in Unity.
- SceneManager: The SceneManager is responsible for reloading the scene or restarting the game once the submit request is sent. Check out the Courier Live Stream for some additional explanation of the notifications script code.
Step 10: After coding the Notification script, I attached it to the GameManager gameObject, populated its input fields, and assigned the Submit button to be executed onClick event.
Step 11: Next, I went over to the Courier notification to map out the event ID selected in the code and get the authentication token.
Step 12: Now’s the fun part! I gave the game a test play.
With Courier, I integrated notifications in under an hour
This process would have been a bona fide nightmare without Courier’s API. I would have had to program the logic myself, which would have taken hours, if not days.
With Courier’s pre-built logic and conditionals for the message content, I was able to build email and text SMS notifications into the game in less than an hour. Heck, you can watch me do the entire process in the live stream.
While Rain Spikes was mainly an exercise in building notifications into a game, I see a ton of potential for Courier to be used for more complex and sophisticated projects in the future. For example, notifying players when someone has achieved a special reward or my idea for modernizing Courier messaging in Package Person is to send gamers updates about the game via Discord.
Illustration by Rebekka Dunlap
Top comments (0)