Unity Integration Guide

This is how you integrate Machinations UP into your Unity production

Let's get coding

Even though our integration has reached Beta maturity, this section will see some changes in the future.

🧙♂At this point, you've probably been through our Quick Start tutorial and/or have UP operational in your project.

The simplest way to use Machinations UP is to integrate it into your game's Scriptable Objects. This is one of the common ways Unity handles game-related data.

Let's jump right into it, and deal with additional details later. For now, you shouldn't look too deeply into anything, just take this as a quick tour. You'll be up in running in minutes.

You can either create a new Scriptable Object or, why not, extend one of your current ones by infusing it with some MachiMagic :). Whatever the case, you need to either create or pick an int value in your ScriptableObject.

Being an abstraction & design tool, Machinations only works with integers. If you need floats, send a larger integer from Machinations and divide it as necessary. For example, if you measure speed on a scale of 0.0 to 10.0, just use 100 from Machinations and divide by 10

  • If you created the value, give it the type ElementBase. If you are modifying an int value you already had in your ScriptableObject, just change its type to ElementBase. Let's say you're adding/modifying a Movement Speed value:

public ElementBase MovementSpeed; //This is visible in Unity's Property Inspector.
  • You need to implement the IMachinationsScriptableObject interface. Our MachinationsDataLayer (lovingly called the MDL henceforth) will call methods in this interface throughout your development session, both when the game is running and when it is not (this will be configurable in the future).

public class SomeScriptableObject : ScriptableObject, IMachinationsScriptableObject
  • To define how you will connect your value to Machinations, you will declare a MachinationsObjectManifest and enroll it with the MDL. You must do this in the OnEnable function of your Scriptable Object:

public void OnEnable ()
{
//Manifest that defines what the Scriptable Object uses from Machinations.
Manifest = new MachinationsObjectManifest
{
Name = "Rectangle's Properties",
DiagramMappings = new List<DiagramMapping>
{
new DiagramMapping
{
GameElementBase = MovementSpeed,
PropertyName = M_MOVEMENTSPEED,
DiagramElementID = 102,
DefaultElementBase = new ElementBase(15, null)
}
}
};
//Register this Scriptable Object with the MDL.
MachinationsDataLayer.EnrollScriptableObject(this, Manifest);
}
  • Now, let's implement the IMachinationsScriptableObject interface. That's going to be way easier than you'd think, and the code is pretty self-explanatory.

public void MGLInitCompleteSO (Dictionary<string, ElementBinder> binders)
{ //Once the value is fetched from Machinations, make sure it is associated
//with this Scriptable Object.
MovementSpeed = binders[M_MOVEMENTSPEED].CurrentElement;
}
public void MGLUpdateSO (DiagramMapping diagramMapping = null, ElementBase elementBase = null)
{
//Want to do something special when the value changes from Machionations-side? Do it here!
}
  • And that's it. Congratulations. You now have a value that pulls its data from Machinations. Now go and put that to good use! :)

Mind your play state

It's possible that your game will begin playing before new Machinations data arrives from the server. You may not like that. For this reason, UP can interact with your game engine via the IGameLifecycleProvider interface.

public interface IGameLifecycleProvider
{
/// <summary>
/// Return current GameState.
/// </summary>
GameStates GetGameState ();
/// <summary>
/// Notifies a Game Engine that Machinations is undergoing Initialization.
/// Perhaps the Game wishes to pause itself during Machinations Initialization?
/// </summary>
void MachinationsInitStart ();
/// <summary>
/// Notifies a Game Engine that Machinations has completed Initialization.
/// Perhaps the Game wishes to un-pause itself?
/// </summary>
void MachinationsInitComplete ();
}

In the UP package, check the class SampleSceneStartupHandler. If you uncomment the RuntimeInitializeOnLoadMethod attribute, this class will instantiate our crudest implementation of an IGameLifecycleProvider.

The SampleGameEngine we provide will simply pause/unpause the game by tampering with Time.timeScale. The MDL will request unpausing the game when it completes its first request at game startup.

More complex behaviors can be achieved by using the MDL.Prepare() method, which will let you schedule your Machinations initialization as you see fit. This method will also notify your game engine of the ongoing initialization.

Troubleshooting

As you prepare to run your game and see the results of your changes, now would be a good time to also check that UP's internal logging works. Open the class MachinationsEntryPoint. This is the class that controls Machinations behavior during your editor/game session.

The first line in the InitMachinations function is:

L.Level = LogLevel.None;

Change it to Debug.

Upon starting your game, you should see some debug messages in the console. Search for "Game Auth Request" and if you correctly set up your User Key & Diagram Token, you should see a "Success" there.

You can also search for "MDL" to see what the Machinations Data Layer has been up to.

Wrap-up

If you're curious to read more about the classes involved, please check the UP developer documentation.

It's important to understand we've built UP to be a versatile solution. There are multiple ways to obtain the same result, depending on what features you'd like to use. We are here to offer some best practices (and, with your feedback, to perfect those best practices).

We will have more integration examples & use cases in the near future.

🎬 As a reminder, here's a start-to-finish Scriptable Objects integration (the same from our Quick Start tutorial). It covers all the above steps.