The Engage in game campaign engine can be used to serve promotional images back to your game to populate fixed slots in your user interface.
The following tutorial shows how to setup campaigns to deliver promo images to each specific banner location in your game based on player segment and campaign logic that you configure on the deltaDNA portal.
It also shows how to instrument your game to check for banner images, download and apply them.
Some of the promotional images in this tutorial contain dynamic text configured on the server and rendered on the client, allowing a common image to be re-used in multiple scenarios.
Setting up the promotional banner images
Your banner image content can be uploaded to the deltaDNA platform in the Engage > In Game > Actions interface. Create a new “Image Message” action for each banner image that you want to serve to the game.
We won’t be using all the features of an image message with these banner images, no need to add buttons. But we will take advantage of the fact that the images are uploaded to deltaDNA and served to the game client from our CDN. We will also be able to leverage the localization capabilities of the image message and the ability to assign game parameters and actions to the image. But for now, just create an image message for each image, give it a name, upload your image into the background and ensure that the “send Image contents on every Engage request” option is selected.
Setting up campaigns to deliver images to the game.
In this example we have 3 promotional banner slots in fixed positions in our game, so we will create 3 campaigns in the Engage > In Game > Campaigns interface to send content to them. Ultimately you could have more than three campaigns directing content in to these fixed slots, based on different segmentation and campaign criteria logic, but for now 3 campaigns will be used to demonstrate some different behaviours.
You can view these campaigns in the Engage > In Game > Campaigns interface by filtering it for the promoCheck decision point.
- The content in promotional banner slot 1 will show the same daily quest content on every request
- Slot 2 will repeatedly cycle through a sequence of 4 promotional images
- Slot 3 will use an AB Test to deliver either a Facebook Like or Rewarded Video banner depending on the test variant the player belongs to. Please Note : None of these campaigns have been setup with conversion events to track when the players interact with them.
There are two crucial things to note about these campaigns:
- They all use the same promoCheck decision point
- The each rely on their own promoLocation parameter that will be passed in to the decision point check from the client and used to determine which campaigns deliver a response.
Instrumenting the game with promo banners
In this Unity tutorial we have created a re-usable promo image prefab object. This means that the game designer can simply drag and drop as many promo image prefab objects in to the game scene as required and give each a unique promoLocation identifier. The promo image instances will each be able to check with the Engage campaign system for new image content, display it or revert to their default image. The value entered in to the promoLocation slot on the Unity game object instance will determine which campaigns react to its requests.
Essentially, each promo image instance will make a request to the Engage campaign engine each time it is Started or if it is told to Refresh itself.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
// Use this for initialization void Start() { // Check for a Promo Image from deltaDNA Engage // if the promo location request parameter is set if(string.IsNullOrEmpty(promoLocation)) { Debug.Log("Promo Slot Location Name not Set"); return; } // Make sure deltaDNA SDK is running before making Engage requests if (DDNA.Instance.isActiveAndEnabled) { Debug.Log("Check Engage for Promo Image for " + promoLocation); promoCheck(); } else { Debug.Log("Check Engage for Promo Image for " + promoLocation + " Failed, deltaDNA SDK not running, try again later (Hit Refresh)"); } } // Method used when the PromoImage is told to refresh itself // This public method can be triggered from the Promo Image's parent // with a BroadcastMessage("PromoRefresh") call public void PromoRefresh() { Debug.Log("Refreshing Promo Image : " + promoLocation); Start(); } |
The actual Engage request looks like this, note the decisionPoint and promoLocation values being set. If the response from Engage is good we then download the promo image file, any game parameters that could contain data to control dynamic text overlays or expiry timers and any event parameters that will contain campaign metadata that we want to communicate back to deltaDNA if the player clicks on the promotion.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// Make an Engage In-Game campaign request // To check for a promo image for this promo location void promoCheck() { var engagement = new Engagement("promoCheck") .AddParam("promoLocation", promoLocation); // Make request DDNA.Instance.RequestEngagement(engagement, (response) => { // Check Response if (response != null && response.StatusCode == 200) { // Get Image info from Engage Response FetchPromoImage(response); parameters = FetchParams(response); eventParams = FetchEventParams(response); } }, (exception) => { Debug.Log("Engage reported an error: " + exception.Message); }); } |
From there we simply parse the Engage response to find the image URL,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// Get image info from Engage Response void FetchPromoImage(Engagement response) { // Check for Image Object if(response.JSON.ContainsKey("image")) { JSONObject image = response.JSON["image"] as JSONObject; // Check for Image URL if (image.ContainsKey("url")) { string imageUrl = image["url"] as string; // Download Image from URL StartCoroutine(LoadResourceCoroutine(imageUrl)); } } // TODO - Add logic to download additional game parameters from Engage // To handle deeplinks, rewards, promo durations, expiry ... } |
download the image and apply it to our Banner Image
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// Download Image from URL to a Texture private IEnumerator LoadResourceCoroutine(string url) { // Download Image from URL in to a Texture #if UNITY_2017_1_OR_NEWER using (var www = UnityWebRequestTexture.GetTexture(url)) . . . . . // Create Sprite from Texture and apply to Promo Image if (downloadedImage != null && promoImage != null) { Debug.Log("Updating " + promoLocation); promoImage.sprite = Sprite.Create(downloadedImage, new Rect(0.0f, 0.0f, downloadedImage.width, downloadedImage.height), new Vector2(0.0f, 0.0f), 1.0f); } } |
The promo image prefab contains two UI Text controls that will be populated and displayed if the Engage response contains offerTitle or offerText game parameters. The game has also been instrumented to react to an offerDurationSeconds game parameter which will cause the Offer Text control to be dynamically updated as an expiry timer, based on the value of the game parameter, counts down.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
// Fetch GameParamters sent with the image action // These should be used by the game to react to Game Parameters // Placed in the promo image action by the marketer private JSONObject FetchParams(Engagement response) { offerDurationSeconds = -1; offerExpiry = DateTime.MinValue; if (response.JSON.ContainsKey("parameters")) { JSONObject parameters = response.JSON["parameters"] as JSONObject; if (parameters.ContainsKey("offerTitle")) { offerTitle.text = parameters["offerTitle"] as string; } if (parameters.ContainsKey("offerText")) { offerText.text = parameters["offerText"] as string; } if (parameters.ContainsKey("offerDurationSeconds")) { offerDurationSeconds = Convert.ToInt32(parameters["offerDurationSeconds"]); offerExpiry = DateTime.Now.AddSeconds(offerDurationSeconds); UpdateExpiry(); } return parameters; } return null; } |
Finally, there is an OnClick() method that we can use to react to button clicks. We also use it to record an event that will be sent back to deltaDNA so we can analyse and report on the player’s interaction with our various promotions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
. . . // Record an event in deltaDNA using eventParams Enagage meta data to indicate Campaign Action GameEvent promoImageClicked = new GameEvent("promoImageClicked") .AddParam("promoLocation", promoLocation) .AddParam("promoImageClickType", clickType); if (!string.IsNullOrEmpty(clickValue)) { promoImageClicked.AddParam("promoImageClickValue", clickValue); } if (eventParams != null) { promoImageClicked.AddParam("responseDecisionpointName", eventParams["responseDecisionpointName"] as string) .AddParam("responseEngagementID", eventParams["responseEngagementID"]) .AddParam("responseEngagementName", eventParams["responseEngagementName"]) .AddParam("responseEngagementType", eventParams["responseEngagementType"]) .AddParam("responseTransactionID", eventParams["responseTransactionID"]) .AddParam("responseVariantName", eventParams["responseVariantName"]) .AddParam("responseMessageSequence", eventParams["responseMessageSequence"]); } DDNA.Instance.RecordEvent(promoImageClicked); . . . |
It also fires a callback, so you can react to button clicks in your game code
1 2 3 4 5 6 7 8 9 10 |
if (parameters != null) { // Callback method to be populated in your game code in order to react to player clicking on promo images // will contain an object indicating the name and value of the promo image action along with any game parameters attched to it. PromoImage.PromoClickArgs promoClickArgs = new PromoImage.PromoClickArgs(parameters, clickType, clickValue); if (this.PromoImageClicked != null) { this.PromoImageClicked(promoClickArgs); } } |
You can download the full Unity project and source code for this tutorial from the deltaDNA Git Hub repository
Please let us know at [email protected] if you have any use cases that you would like us to explore further in this tutorial, or any suggestions for new tutorials.