Seasonal events

Seasonal events can increase game sessions and overall interest in a game, because they give existing players new and fun content throughout the year to look forward to, and can entice new players to begin playing.This sample shows how you can set up seasonal events. It showcases four events, Fall, Winter, Spring, and Summer, however you can extend this example to configure events for anything you want. Each event displays the currency rewards you can win during the event, a countdown indicating how much time is left in the current event, and a Play Challenge button that opens a pop-up where players can collect their rewards for "winning" the challenge.

Overview

To see this use case in action, open the samples menu and navigate to Seasonal Events. To open this scene directly and interact with the use case:

  1. In the Unity Editor Project window, select Assets > Use Case Samples > Seasonal Events, then double-click SeasonalEventsSample.unity to open the sample scene.

  2. Press Play to enter Play mode.

Initialization

The SeasonalEventsSceneManager.cs script performs the following initialization tasks in its Start function:

  1. Initializes Unity Gaming Services.
  2. Signs in the player anonymously using the Authentication service. If you’ve previously initialized any of the other sample scenes, Authentication will use your cached Player ID instead of creating a new one.
  3. Retrieves and updates the player's currency balances from the Economy service.
  4. Calls the GetServerTime Cloud Code function in order to base Game Override and Remote Config data off the server time.
  5. Queries the Remote Config service to get the current values for event-related keys (see section on event parameters below).

Event parameters

The Remote Config service stores key-value data for displaying the active event name, the potential rewards for completing the event challenge. These keys are also used to retrieve the event’s themed interface visuals from the Addressables service.

Remote Config also conveys when the event ends, which the CountdownManager.cs script references to determine how much time remains for the current event. When that time runs out, it triggers a new call to Remote Config to get the updated values for the next event.

Note: This sample determines which Game Override data to return based on the last digit of the number of minutes in the current server time. This is a simplification to be able to frequently observe the season change. In a real app, developers likely set up a Game Override to have specific start and end dates, then Remote Config determines when the Game Override is shown based on the server’s date and time. In that case, the client and server implementations can be a bit different.

Functionality

Collect Rewards

The Play Challenge button is an abstraction for gameplay that the player might engage in to earn event rewards. Clicking it opens a pop-up where players can collect rewards for "winning" the challenge. When you click the Collect Rewards button, the following occurs:

  1. The button’s OnClick method calls the SeasonalEvents_GrantEventReward.js Cloud Code script, which queries the Remote Config service to determine which rewards to distribute.

    Note: Rewards could potentially differ from what the player expects, if they're altering their device clock or if they initiated their claim at the very end of an event.

  2. Cloud Code then calls the Economy service to grant the appropriate rewards and update the player’s currency and inventory balance.

  3. Once rewards are distributed, the calling script updates the currency HUD and closes the collect rewards pop-up.

You can only play the challenge once per active event, so after the Cloud Code script distributes rewards, it saves the current event name and timestamp to Cloud Save. The client uses this information to determine whether the current event has already been played, and if it has, to disable the Play Challenge button.

Additionally, Analytics custom events are sent each time the scene loads (SceneOpened), whenever a button is pressed (ActionButtonPressed), and when the back button in the scene is pressed.

Setup

Requirements

To replicate this use case, you'll need the following Unity packages in your project:

Package Role
Addressables Allows asset retrieval by address. Wherever the asset resides (local or remote), the system will locate it and its dependencies and then return it. In this sample, it retrieves event-specific images and prefabs based on information from Remote Config.
Analytics Sends events to track a player's in-game interactions, retention, and other information that you can use to analyze and improve the game experience.
Authentication Automatically signs in the user anonymously to keep track of their data on the server side.
Cloud Code Contains important validation logic on the server side. In this sample, it distributes rewards for the event challenge. It also independently verifies the timestamp at the time of reward distribution on the server-side to confirm which event rewards to distribute.
Cloud Save Stores a flag for whether the current challenge has already been played, to prevent the player from participating multiple times.
Economy Retrieves the player's starting and updated currency balances at runtime.
Remote Config Provides key-value pairs that can be changed server-side, either manually or based on specific Game Overrides. In this sample, the Game Overrides feature contains four seasonal events and returns different values for certain keys based on the active Game Override.

To use these services in your game, activate each service for your Organization and project in the Unity Dashboard.

Dashboard Setup

To replicate this sample scene's setup on your own dashboard, you will need to:

  • Configure custom Analytics events and parameters.
  • Publish two scripts in Cloud Code.
  • Create four Currencies for the Economy service.
  • Configure Remote Config values and Game Overrides.

Analytics

The Analytics custom events configuration contains a long list of potential parameters that are sent with some of the events. This extended list allows for a more flexible analysis of different parameter groupings in the Data Explorer on the Analytics dashboard. Alternatively, you could send only the ungrouped parameters (for example, buttonName or sceneName), and perform any kind of grouped analysis by using the Data Export feature within the Data Explorer on the dashboard.

Important: This sample demonstrates the code that is needed to trigger Analytics events. However, additional code might be necessary to meet legal requirements such as GDPR, CCPA, and PIPL. For more information, see the documentation on managing data privacy.

Configure and enable the following custom Analytics events:

Event name Description Custom parameters
SceneOpened Sent each time you load the scene.
  • sceneName
ActionButtonPressed Sent each time you click a button in the scene.
  • buttonName
  • buttonNameByRemoteConfigEvent
  • buttonNameBySceneName
  • buttonNameBySceneNameAndRemoteConfigEvent
  • remoteConfigActiveEvent
  • sceneName
SceneSessionLength Sent to indicate the time spent in the scene (measured as the length of time between when AnalyticsManager.Start() triggers and the player presses the back button in the scene).
  • remoteConfigActiveEvent
  • sceneName
  • timeRange
  • timeRangeByRemoteConfigActiveEvent
  • timeRangeBySceneName
  • timeRangeBySceneNameAndRemoteConfigActiveEvent

Configure the following custom parameters to support your custom events:

Parameter name Type Description
buttonName string The name of the button that the player clicked.
buttonNameByRemoteConfigEvent string Groups the name of the button clicked with the active Remote Config event. The string format is "Button name - Event key".
buttonNameBySceneName string Groups the name of the button clicked with the current scene's name. The string format is "Button name - Scene name".
buttonNameBySceneNameAndRemoteConfigEvent string Groups the name of the button clicked with the scene's name and active Remote Config event. The string format is "Button name - Scene name - Event key".
remoteConfigEvent string The active event as defined in and determined by Remote Config.
sceneName string The name of the scene where the event is triggered.
timeRange string The amount of time spent in the scene when the event is triggered.
timeRangeByRemoteConfigEvent string Groups the time spent in the scene when the event is triggered with the active Remote Config event. The string format is "Time range - Event key".
timeRangeBySceneName string Groups the time spent in the scene when the event is triggered with the scene's name. The string format is "Time range - Scene name".
timeRangeBySceneNameAndRemoteConfigEvent string Groups the time spent in the scene when the event is triggered with the scene's name and the active Remote Config event. The string format is "Time range - Scene name - Event key".

Cloud Code

Publish the following scripts in the LiveOps dashboard:

Script Parameters Description Location in project
GrantEventReward None

Verifies and distributes rewards.

Assets/Use Case Samples/Seasonal Events/Cloud Code/SeasonalEvents_GrantEventReward.js
GetServerTime None Retrieves the current timestamp from the server in order to base the UI on server-authoritative time. Assets/Use Case Samples/Seasonal Events/Cloud Code/SeasonalEvents_GetServerTime.js

Note: The Cloud Code scripts included in the Cloud Code folder are local copies because you cannot view the sample project's dashboard. Changes to these scripts do not affect the behavior of this sample because they are not automatically uploaded to the Cloud Code service.

Economy

Configure the following resources in the LiveOps dashboard:

Resource type Resource name ID Description
Currency Coin COIN A challenge reward during the fall, winter, and spring events.
Currency Gem GEM A challenge reward during the winter and summer events
Currency Pearl PEARL A challenge reward during the fall and summer events
Currency Star STAR A challenge reward during the spring and summer events

Remote Config

Set up the following config values in the LiveOps dashboard:

Key Type Description Value
EVENT_NAME string The name of the event to display in the scene. ""
EVENT_KEY string The key used to look up event-specific values, such as the addresses for the specific images. ""
EVENT_END_TIME int The last digit that matches in the Audience JEXL statement, i.e. the last digit of the latest timestamp that would return this campaign. 0
CHALLENGE_REWARD JSON The json that specifies what rewards are distributed when a challenge has been "won".
Copy

  "rewards": [{ 
    "id": "COIN", 
    "quantity": 100, 
    "sprite_address": "Sprites/Currency/Coin" 
  }] 
}

Game Overrides

Configure the following Overrides in the LiveOps dashboard:

Details Name the Override “Fall Event”.
Targeting

Select Stateless JEXL with the following JEXL code:

Copy
user.timestampMinutes % 10 == 0 || user.timestampMinutes % 10 == 1 || user.timestampMinutes % 10 == 2
Content

Select Choose content type > Config Overrides, then enter override values for the following keys:

  • EVENT_NAME: “Fall Event
  • EVENT_KEY: “Fall
  • EVENT_END_TIME: 2
  • CHALLENGE_REWARD:
    Copy
    {
      "rewards":[
        {
          "id": "COIN",
          "quantity": 100,
          "spriteAddress": "Sprites/Currency/Coin"
        },
        {
          "id": "PEARL",
          "quantity": 50,
          "spriteAddress": "Sprites/Currency/Pearl"
        }
      ]
    }
Scheduling

Set the following start and end dates:

  • Set Start Date to Update content immediately.
  • Set End Date to Run indefinitely.

Details Name the Override “Winter Event”.
Targeting

Select Stateless JEXL with the following JEXL code:

Copy
user.timestampMinutes % 10 == 3 || user.timestampMinutes % 10 == 4
Content

Select Choose content type > Config Overrides, then enter override values for the following keys:

  • EVENT_NAME: “Winter Event
  • EVENT_KEY: “Winter
  • EVENT_END_TIME: 4
  • CHALLENGE_REWARD:
    Copy
    {
      "rewards":[
        {
          "id": "COIN",
          "quantity": 100,
          "spriteAddress": "Sprites/Currency/Coin"
        },
        {
          "id": "GEM",
          "quantity": 50,
          "spriteAddress": "Sprites/Currency/Gem"
        }
      ]
    }
Scheduling

Set the following start and end dates:

  • Set Start Date to Update content immediately.
  • Set End Date to Run indefinitely.

Details Name the Override “Spring Event”.
Targeting

Select Stateless JEXL with the following JEXL code:

Copy
user.timestampMinutes % 10 == 5 || user.timestampMinutes % 10 == 6 || user.timestampMinutes % 10 == 7
Content

Select Choose content type > Config Overrides, then enter override values for the following keys:

  • EVENT_NAME: “Spring Event
  • EVENT_KEY: “Spring
  • EVENT_END_TIME: 7
  • CHALLENGE_REWARD:
    Copy
    {
      "rewards":[
        {
      "id": "COIN",
      "quantity": 100,
      "spriteAddress": "Sprites/Currency/Coin"
    },
    {
      "id": "STAR",
      "quantity": 50,
      "spriteAddress": "Sprites/Currency/Star"
    }
      ]
    }
Scheduling

Set the following start and end dates:

  • Set Start Date to Update content immediately.
  • Set End Date to Run indefinitely.

Details Name the Override “Summer Event”.
Targeting

Select Stateless JEXL with the following JEXL code:

Copy
user.timestampMinutes % 10 == 8 || user.timestampMinutes % 10 == 9
Content

Select Choose content type > Config Overrides, then enter override values for the following keys:

  • EVENT_NAME: “Summer Event
  • EVENT_KEY: “Summer
  • EVENT_END_TIME: 9
  • CHALLENGE_REWARD:
    Copy
    {
      "rewards":[
        {
          "id": "STAR",
          "quantity": 50,
      "spriteAddress": "Sprites/Currency/Star"
    },
    {
      "id": "PEARL",
      "quantity": 50,
      "spriteAddress": "Sprites/Currency/Pearl"
    },
    {
      "id": "GEM",
      "quantity": 50,
      "spriteAddress": "Sprites/Currency/Gem"
    }
      ]
    }
Scheduling

Set the following start and end dates:

  • Set Start Date to Update content immediately.
  • Set End Date to Run indefinitely.

Important: After configuring your Overrides, remember to enable them by selecting the Override from the list and clicking the Enable button.