Prism Management

In Lumin Runtime applications typically run inside three dimensional segments of real-world space known as prisms. The first time your MagicScript application is launched, a new process will be created. If the application is launched again while the first is still running, a new process will not be created.

This article walks through various techniques for managing prisms with their associated pros and cons.

Plain App

The simplest possible app is one that creates a prism at invocation and places something visible in it. It is expected that an app will create a new prism for each invocation.

import { LandscapeApp } from "lumin";
export class App extends LandscapeApp {
onAppStart() {
// Create a new prism that's half a meter cubed.
let prism = this.requestNewPrism([0.5, 0.5, 0.5]);
// Load a model file into a node.
let id = prism.createModelResourceId("res/Leaper.glb", 0.3);
let model = prism.createModelNode(id);
// Attach the model to the scene graph so it renders.
prism.getRootNode().addChild(model);
}
}

Note that we used the onAppStart() hook for our main logic instead of init(). This will be called every time the application is launched. If we had put our code instead in init(), it would work for the first invocation, but a second launch would result in nothing happening.

The problem with this comes in if we wish to use the updateLoop(delta) or eventListener(event) hooks. They are global hooks for all invocations. If there are multiple instances of the app running, how do we route these events to them? We can't store per-invocation data in this because there is only one global app instance for all app invocations.

  • app.init() is called only at process startup (the first invocation.)
  • app.onAppStart(arg) is called for every invocation (after init for the first.)
  • app.updateLoop(delta) is called once per update loop, no matter how many times the app was invoked.
  • app.eventListener(event) is also a global event hook.

Prism Controller

Prism controllers can be used to set a scope for events so that a particular handler is used for a prism (or even subset of a scene graph).

The most basic app is similar, but with one more custom class.

import { LandscapeApp, PrismController } from 'lumin';
export class App extends LandscapeApp {
onAppStart() {
// Create a new prism that's half a meter cubed.
let prism = this.requestNewPrism([0.5, 0.5, 0.5]);
// Set a custom prism controller to handle the rest.
prism.setPrismController(new Controller());
}
}
class Controller extends PrismController {
onAttachPrism() {
let prism = this.getPrism();
// Load a model file into a node.
let id = prism.createModelResourceId("res/Leaper.glb", 0.3);
let model = prism.createModelNode(id);
// Attach the model to the scene graph so it renders.
this.getRoot().addChild(model);
}
}

In this new Controller class we can set event hooks that are scoped to this controller.

  • onAttachPrism() - Called once per attach.
  • onDetachPrism() - called once per dettach.
  • onEvent(event) - Called only for events under this controller's hierarchy.
  • onUpdate(delta) - Called for update ticks.

Also with this pattern there is a new instance of the controller for each prism and each app invocation. This means we can put state inside this in the controller and it will be local to each invocation.