Beamable Documentation

Welcome! Here is everything you need to get setup and become a Beamable expert.

Begin with the Getting Started section, learn more about Beamable features in the Manual, and check out the Script Reference APIs for advanced workflows.

Choose from the following...













.








.

Microservices (Beta) - Sample

Create and deploy server-authoritative C#

❗️

Experimental

This Beamable functionality is currently in-development and subject to change. Game makers are invited and encouraged to try it out, send feedback, and help shape the future of the product.

Overview

Welcome to "Beamable Boss Battles" (BBB). This downloadable sample game project showcases the Beamable Microservices FeatureFeature - An individual aspect of the Beamable product used to create a great user experience.

This document and the sample project allow game makers to understand and apply the benefits of Microservices in game development.

The Hero has reached the dungeon. Battle the Boss to win.

Download

These learning resources provide a better way to build live games in Unity.

Source

Detail

  1. Download the Microservices BBB Sample Project
  2. Open in Unity Editor ( Version 2019.4 LTS )
  3. Open the Beamable Toolbox
  4. Sign-In / Register To Beamable. See Step 1 - Getting Started for more info
  5. Complete the Docker setup. See Microservices for more info
  6. Click to "Start" the server. See Microservices for more info
  7. Open the 1.Intro Scene
  8. Play The Scene: Unity → Edit → Play

Note: Each sample project is compatible with Mac & Windows and includes the Beamable SDK. Each sample project requires internet connectivity.

Screenshots

The player navigates from the Intro Scene to the Game Scene, where all the action takes place.

Intro Scene

Game Scene

Project

Player Experience Flowchart

Here is the high level execution flow of user input and system interactions.

The player battles the boss and the workload is appropriately divided between the C# game client code and the C# Beamable Microservice code. Goals of using server-authoritative programming include to increase the game's security (against any malicious hackers in the game's community) and to improve live ops workflows.

  • StartTheBattle () - Public Microservice method to reset the BossHealth StatStat - Active data entity used for read/write of player state and randomize HeroWeaponIndex StatStat - Active data entity used for read/write of player state
  • AttackTheBoss () - Public Microservice method to reduce the BossHealth StatStat - Active data entity used for read/write of player state based on Weapon ContentContent - The primary data concept within the Beamable Content Manager

Game Maker User Experience

During development, the game maker's user experience is as follows. There are 3 major parts to this game creation process.

Steps

Follow these steps to get started.

📘

Related Guides

A common use case for the feature is covered in the guides. It is recommended to read the guide before continuing with the sample steps below. See Microservices for more info.

Step 1. Setup Beamable Content

Step

Detail

  1. Setup Beamable Microservices

• See Getting Started With Beamable Microservices

  1. Create Weapon Stat Class

[ContentType("weapon")]
public class Weapon : ContentObject
{
public float HitChance = 0.5f;
public int MinDamage = 25;
public int MaxDamage = 50;
}

  1. Create Weapon Stat Objects
  1. Populate all data fields
  1. Create Boss Stat Class

[ContentType("boss")]
public class Boss : ContentObject
{
public int MaxHealth = 100;
}

  1. Create Boss Stat Object
  1. Populate all data fields
  1. Save the Unity Project

• Unity → File → Save Project

Best Practice: If you are working on a team, commit to version control in this step.

  1. Publish the content

• Press the "Publish" button in the Content Manager Window

Step 2. Create Game Client Code

This step includes the bulk of time and effort the project.

Step

Detail

  1. Create C# Client Code (Basics)

• The details vary wildly depending on the needs of the project's game design.

  1. Create C# Client Code (To Call Microservices)

• See BBBGameManagerSA.cs below.

Inspector

Here is the BBBGameManagerSA.cs main entry point for the Game Scene interactivity. The "SA" in the class name indicates server-authoritative.

The "Content" references are easily configurable

Here is the Configuration.cs holding high-level, easily-configurable values used by various areas on the game code.

Optional: Game Makers may experiment with new Delay values in the Attack section and allow the players' turn to occur faster or slower.

The "Configuration" values are easily configurable

Code

namespace Beamable.Samples.BBB
{
   public class BBBGameManagerSA : MonoBehaviour
   {
      //  Fields ---------------------------------------

      [SerializeField]
      private GameUI _gameUI = null;

      [SerializeField]
      private HeroView _heroView = null;

      [SerializeField]
      private BossView _bossView = null;

      [SerializeField]
      private PointsView _pointsViewPrefab = null;

      [SerializeField]
      private Configuration _configuration = null;

      [SerializeField]
      private BossContentRef _bossContentRef = null;

      [SerializeField]
      private List<WeaponContentRef> _weaponContentRefs = null;

      private PointsView _pointsViewInstance = null;
      private BBBGameMicroserviceClient _bbbGameMicroserviceClient = null;

      //  Unity Methods   ------------------------------
      protected void Start()
      {
         _gameUI.AttackButton.onClick.AddListener(AttackButton_OnClicked);

         // Block user interaction
         _gameUI.CanvasGroup.DOFade(0, 0);
         _gameUI.AttackButton.interactable = false;
         
         _bbbGameMicroserviceClient = new BBBGameMicroserviceClient();
         StartTheBattle();

      }

      //  Other Methods --------------------------------
      private void StartTheBattle ()
      {
         int heroWeaponIndexMax = _weaponContentRefs.Count;

         // ----------------------------
         // Call Microservice Method #1
         // ----------------------------
         _bbbGameMicroserviceClient.StartTheBattle(_bossContentRef, heroWeaponIndexMax)
            .Then((StartTheBattleResults results) =>
            {
               _gameUI.BossHealthBarView.Health = results.BossHealthRemaining;
               _gameUI.AttackButtonText.text = BBBHelper.GetAttackButtonText(results.HeroWeaponIndex);

               // Find the Weapon data from the Weapon content
               _weaponContentRefs[results.HeroWeaponIndex].Resolve()
                  .Then(content =>
                  {
                     //TODO; Fix fade in of models (Both scenes)
                     BBBHelper.RenderersDoFade(_bossView.Renderers, 0, 1, 0, 3);
                     BBBHelper.RenderersDoFade(_heroView.Renderers, 0, 1, 1, 3);

                     // Allow user interaction
                     _gameUI.AttackButton.interactable = true;
                     _gameUI.CanvasGroup.DOFade(1, 1).SetDelay(0.50f);

                  })
                  .Error((Exception exception) =>
                  {
                     Console.WriteLine("_bossContentRef.Resove() error: " + exception.Message);
                  });

            })
            .Error((Exception exception) =>
            {
               UnityEngine.Debug.Log($"StartTheBattle() error:{exception.Message}");
            });
      }

     
      private IEnumerator Attack()
      {
         _gameUI.AttackButton.interactable = false;

         // Wait - Click
         yield return new WaitForSeconds(_configuration.Delay1BeforeAttack);
         SoundManager.Instance.PlayAudioClip(SoundConstants.Click02);

         // Wait - Backswing
         yield return new WaitForSeconds(_configuration.Delay2BeforeBackswing);
         SoundManager.Instance.PlayAudioClip(SoundConstants.Unsheath01);
         _heroView.PrepareAttack();

         bool isDone = false;

         // ----------------------------
         // Call Microservice Method #2
         // ----------------------------
         AttackTheBossResults attackTheBossResults = null;
         _bbbGameMicroserviceClient.AttackTheBoss(_weaponContentRefs)
            .Then((AttackTheBossResults results) =>
            {
               isDone = true;
               attackTheBossResults = results;

            })
               .Error((Exception exception) =>
            {
               UnityEngine.Debug.Log($"AttackTheBoss() error:{exception.Message}");
            });

         while (!isDone)
         {
            yield return new WaitForEndOfFrame();
         }

         // Wait - Swing
         yield return new WaitForSeconds(_configuration.Delay3BeforeForeswing);
         SoundManager.Instance.PlayAudioClip(SoundConstants.Swing01);
         _heroView.Attack();

         // Show floating text, "-35" or "Missed!"
         if (_pointsViewInstance != null)
         {
            Destroy(_pointsViewInstance.gameObject);
         }
         _pointsViewInstance = Instantiate<PointsView>(_pointsViewPrefab);
         _pointsViewInstance.transform.position = _bossView.PointsViewTarget.transform.position;

         // Evaluate damage
         if (attackTheBossResults.DamageAmount > 0)
         {
            // Wait - Damage
            yield return new WaitForSeconds(_configuration.Delay4BeforeTakeDamage);
            SoundManager.Instance.PlayAudioClip(SoundConstants.TakeDamage01);
            BBBHelper.RenderersDoColorFlicker(_bossView.Renderers, Color.red, 0.1f);
            _bossView.TakeDamage();

            // Wait - Points
            yield return new WaitForSeconds(_configuration.Delay5BeforePointsView);
            SoundManager.Instance.PlayAudioClip(SoundConstants.Coin01);

            _pointsViewInstance.Points = -attackTheBossResults.DamageAmount;

         }
         else
         {
            // Wait - Points
            yield return new WaitForSeconds(_configuration.Delay5BeforePointsView);
            SoundManager.Instance.PlayAudioClip(SoundConstants.Coin01);

            _pointsViewInstance.Text = BBBHelper.GetAttackMissedText();
         }

         if (attackTheBossResults.BossHealthRemaining <= 0)
         {
            _bossView.Die();
            SoundManager.Instance.PlayAudioClip(SoundConstants.GameOverWin);
         }
         else
         {
            _gameUI.AttackButton.interactable = true;
         }

         _gameUI.BossHealthBarView.Health = attackTheBossResults.BossHealthRemaining;
      }

      //  Event Handlers -------------------------------
      public void AttackButton_OnClicked ()
      {
         StartCoroutine(Attack());
      }
   }
}

Alternative API

Beamable Microservices supports a Promise-based workflow. The availability of the result of the Promise may be handled using .Then() within synchronous scopes as shown above or handled with .IsCompleted within Coroutines as shown here.

Game makers may choose either syntax.

// ----------------------------
// Call Microservice Method #2
// ----------------------------
Promise<AttackTheBossResults> attackTheBossPromise = _bbbGameMicroserviceClient.AttackTheBoss();

while (!attackTheBossPromise.IsCompleted)
{
   yield return new WaitForEndOfFrame();
}

AttackTheBossResults attackTheBossResults = attackTheBossPromise.GetResult();

Step 3. Create Game Server Code (Microservices)

Create the Microservice and the project-specific C# code to meet the game's needs.

Name

Detail

  1. Open the "Microservices Manager" Window

• Unity → Window → Beamable → Open Microservices Manager

  1. Create a new Microservice

• Unity → Window → Beamable → Create New Microservice

• Populate all form fields

  1. Implement the Microservice method

See the BBBGameMicroservice.cs code snippet below the table

  1. Build the Microservice

• See Beamable Microservice Manager Window

  1. Run the Microservice

• See Beamable Microservice Manager Window

  1. Play the Scene

• Unity → Edit → Play

Note: Verify that the code properly functions. This varies depending on the specifics of the game logic

  1. Stop the Scene

• Unity → Edit → Stop

API

Read these method diagrams along with the following code snippet for a full understanding of the client-server data exchange.

Call Microservice Method #1

The Boss data is passed along via ContentRef to set the initial BossHealth Stat value (e.g. 100). The heroWeaponIndexMax (e.g. 2) is passed and used as a random value is rolled (e.g. 1) for which weapon the Hero will use for the duration of the battle. This is stored in the `HeroWeaponIndex' Stat for subsequent use.

Note: The use of randomization for the `HeroWeaponIndex' is a simplified solution fit for this sample project. However, its likely a production game would feature deeper game play and allow the player to select the Hero's weapon, instead of using a random.

Call Microservice Method #2

A list of Weapon data is passed along via ContentRef. The Microservice uses only one index in the list (via HeroWeaponIndex Stat), calculates the damage done to the Boss and returns data to the client used for rendering of animations and UI text.

Code

Here is the code for the steps above.

Beamable auto-generates this original version of the BBBGameMicroservice as the starting point.

using Beamable.Server;

namespace Beamable.Server.BBBGameMicroservice
{
   [Microservice("BBBGameMicroservice")]
   public class BBBGameMicroservice : Microservice
   {
      [ClientCallable]
      public void ServerCall()
      {
         // This code executes on the server.
      }
   }
}

The game maker updates the code to meet the needs of the game project.

Here is final version of the BBBGameMicroservice.

namespace Beamable.Server.BBBGameMicroservice
{
   [Microservice("BBBGameMicroservice")]
   public class BBBGameMicroservice : Microservice
   {
      [ClientCallable]
      public async Task<StartTheBattleResults> StartTheBattle(BossContentRef bossContentRef, int heroWeaponIndexMax)
      {
         // Find the Boss data from the Boss content
         var boss = await bossContentRef.Resolve();

         // Set boss health to 100
         await BBBHelper.SetProtectedPlayerStat(Services, Context.UserId,
                BBBConstants.StatKeyBossHealth,
                boss.MaxHealth.ToString());

         // Set hero weapon index to random (0,1)
         int heroWeaponIndex = new System.Random().Next(heroWeaponIndexMax);

         await BBBHelper.SetProtectedPlayerStat(Services, Context.UserId,
                BBBConstants.StatKeyHeroWeaponIndex,
                heroWeaponIndex.ToString());

         return new StartTheBattleResults
         {
            BossHealthRemaining = boss.MaxHealth,
            HeroWeaponIndex = heroWeaponIndex
         };
      }

      [ClientCallable]
      public async Task<AttackTheBossResults> AttackTheBoss(List<WeaponContentRef> weaponContentRefs)
      {
         // Get the weapon index
         string heroWeaponIndexString = await BBBHelper.GetProtectedPlayerStat(Services, Context.UserId,
            BBBConstants.StatKeyHeroWeaponIndex);

         // Get the weapon
         int heroWeaponIndex = int.Parse(heroWeaponIndexString);

         // Find the weapon data from the Weapon content
         var weapon = await weaponContentRefs[heroWeaponIndex].Resolve();

         // Calculate the damage
         Random random = new Random();
         int damageAmount = 0;
         double hitRandom = random.NextDouble();

         if (hitRandom <= weapon.HitChance)
         {
            damageAmount = random.Next(weapon.MinDamage, weapon.MaxDamage);
         }

         // Return the damage
         return await DamageTheBoss(damageAmount);
      }

      public async Task<AttackTheBossResults> DamageTheBoss(int damageAmount)
      {
         // Get the health
         string bossHealthRemainingString = await BBBHelper.GetProtectedPlayerStat(Services, Context.UserId,
            BBBConstants.StatKeyBossHealth);

         int bossHealthRemaining = int.Parse(bossHealthRemainingString);

         // Decrement the health
         bossHealthRemaining = Math.Max(0, bossHealthRemaining - damageAmount);

         // Set the health
         await BBBHelper.SetProtectedPlayerStat(Services, Context.UserId,
             BBBConstants.StatKeyBossHealth,
             bossHealthRemaining.ToString());

         // Return the health
         return new AttackTheBossResults { 
           DamageAmount = damageAmount, 
           BossHealthRemaining = bossHealthRemaining
         };
      }
   }

   public class AttackTheBossResults
   {
      public int DamageAmount;
      public int BossHealthRemaining;
   }

   public class StartTheBattleResults
   {
      public int BossHealthRemaining;
      public int HeroWeaponIndex;
   }
}

Congratulations! With the Beamable content setup, the client code created, and the server code finished, the game is ready.

Verify Success

As an optional step, verify that everything is properly setup. Display the current player’s DBIDDBID - The database identification. Beamable generates an anonymous account for the player when the project first runs on-screen and in the Unity Console Window.

Step

Detail

  1. Play the Intro Scene

• Unity → Edit→ Play

  1. Click the "Start Game" button

Note: The game is playable with or without the client services. This helps game makers to study the differences in implementation

  1. Click the "Attack" button

Note: Repeat until the BossHealth reaches zero to win

  1. Stop the Intro Scene

• Unity → Edit→ Stop

Additional Experiments

Here some optional experiments game makers can perform with the sample project.

Did you complete all the experiments with success? We'd love to hear about it. Contact us.

Difficulty

Scene

Name

Detail

Beginner

Game

Add More Hero Weapons

• The current game randomizes between weapons. Add more weapons (Weapons are non-visual)

  1. Update list of Weapons in existing Microservice

Beginner

Game

Hide the Microservice Latency

• The current game A) animates the Hero's backward swing, B) calls the Microservice, C) waits for Microservice D) animates the Hero's forward swing

  1. Try reordering (e.g. B,A,C,D) to 'hide' the latency for a smoother user experience. What complications may arise?

Intermediate

Intro

Add Hero Weapon Selector

• The current game randomizes between weapons. Allow player to choose instead

  1. Add new method(s) to existing Microservice
  2. Add UI Buttons to Intro Scene
  3. Call new method(s) from Intro Scene

Advanced

Game

Add Boss Attacks Hero

• The current UI displays the Hero's health (always 100%). Allow the Boss to attack the Hero

  1. Add new method(s) to existing Microservice
  2. Call new method(s) from Game Scene after each Hero Attack
  3. Update UI, Boss Animation, & Hero Animations

Advanced

Here are a few advanced configuration options and workflows.

What about latency?

As with any asynchronous client-server setup, each Beamable Microservice method call will incur some latency. In rare cases, the method call will time-out (e.g. after 10 seconds) or error out.

Design the game-client to account for latency (e.g. temporarily disable UI buttons) and to handle errors (e.g. display a UI dialog box).

What is the Beamable Microservice development cycle?

This is a work-in-progress. At this stage of maturity, the process is as follows.

Editing Non-Microservice code

  1. Save your C# script(s)
  2. Click to focus the Unity Editor Window
  3. Wait Unity to recompile
  4. Play the Scene
  5. Enjoy the game
  6. Stop the Scene

Editing Microservice code

  1. Save your C# script(s)
  2. Click to focus the Unity Editor Window
  3. Wait for Unity to recompile
  4. Stop the Server (Unity Microservice Manager Window)
  5. Build the Server
  6. Start the Server
  7. Play the Scene
  8. Enjoy the game
  9. Stop the Scene

Learning Resources

These learning resources provide a better way to build live games in Unity.

Source

Detail

  1. Download the Microservices BBB Sample Project
  2. Open in Unity Editor ( Version 2019.4 LTS )
  3. Open the Beamable Toolbox
  4. Sign-In / Register To Beamable. See Step 1 - Getting Started for more info
  5. Complete the Docker setup. See Microservices for more info
  6. Click to "Start" the server. See Microservices for more info
  7. Open the 1.Intro Scene
  8. Play The Scene: Unity → Edit → Play

Note: Each sample project is compatible with Mac & Windows and includes the Beamable SDK. Each sample project requires internet connectivity.

Updated 5 days ago


Microservices (Beta) - Sample


Create and deploy server-authoritative C#

Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.