Motive’s UI system is built on the concept of stacks of Panels inside of “Panel Containers” with push and pop semantics. Your app requires a PanelManager, which is just a special singleton Panel Container.
Each Panel Container manages a set of Panels. The Panels in a Container follow one of three sets of rules when it comes to their push/pop stack behavior:
- Normal – Panels get pushed on top of other panels and, when popped, reveal the panel they were pushed on top of
- One at a time – only one Panel is on the stack at a time. If pushed over an existing panel, the existing panel is popped.
- No rule – Panels are pushed and popped independently of other panels
All panels belong to the Panel Manager container by default unless explicitly assigned to another container. Panels within a container can also be assigned to different stacks by name which operate independently of one another, although in most cases this approach is largely deprecated by the ability to have multiple panel containers in your app. (In early versions of Motive, the Panel Manager was the only container, so stacks were required to isolate unrelated panels from each other.)
The Panel Class
You can attach the Panel monobehaviour to any object to let it be controlled by Panel Manager. A Panel receives a number of calls that lets you manage its data. A subset is described here:
- DidPush – called when pushed, optionally with data from the caller
- DidPop – called when popped
- Populate – called after did push
If you use the Motive SDK long enough, you’ll notice a slow evolution away from specific panels for each screen (TasksPanel, InventoryPanel, ScreenMessagePanel, etc.) towards the use of “Panel Components”. Panel components give you much more flexibility when building a Motive UI since you can mix and match different functionality very easily and lets you isolate components that can display certain types of information from the screen that’s showing that information. As an example, consider Screen Message. A Screen Message can be shown as Playable Content, but can also be attached to a Collectible. Without Panel Components, you would be forced to create two different panels that do essentially the same thing: one to display a screen messaging coming in as a Playable, the other to display Screen Message content attached to a collectible. With Panel Components, you can simply re-use the Screen Message Component on both panels without creating a bunch of overlapping classes.
Panel Components expose many of the same lifecycle methods that Panels do.
One of the tricky elements of building Motive UIs that make heavy use of prefabs is linking the Panels together. Panels and other UI elements often need to display other Panels. In Motive, UIs are laid out directly in the scene so that they can be easily edited and pre-loaded on launch so they display very quickly. That said, you definitely want to break up your scene into multiple prefabs to make it easier to collaborate.
Initially, Motive Panels were linked directly to each other in the scene. This made it easy to see where the links went (just clicking on the link in the scene would show you exactly where the other Panel was), however this doesn’t work well with prefabs since the prefab can’t save connections that exist only in the scene. This problem led to a lot of headaches if you ever “reverted” your prefab–you would suddenly lose all of the links to other panels and you could easily lose a half a day of work trying to wire them all back up.
To work around this issue, we introduced the notion of a “PanelLink”. A PanelLink lets you link to other panels by name or by a direct link. The direct link still has the prefab revert problem, but if this isn’t a concern for you (maybe you aren’t using prefabs or you’re not collaborating so you’re not worried about losing your link), then it’s the quickest way to wire them up. You can optionally link Panels by their name in the scene. This of course leads to a lot of issues if you decide to rename a bunch of your screens, but the rest of the time it creates a prefab-safe link between screen elements.