Skip to main content

Player Controller

The PlayerController is the preferable and the fastest way to initialize the game. The controller wraps all boilerplate needed to wire Spinorium pieces together and exposes overridable hooks for project-specific logic. The current PlayerController instance is exposed via System.controller property.

As a developer, you can customize the controller by overriding the following methods:

  • createParameters() – Creates game parameters, which contain information about the player session used for backend authentication and game initialization (e.g. language, jurisdiction). Usually based on URL query parameters as data source.
  • createSettings() – Creates game settings, which store player-specific preferences such as sound volume and turbo spin state. Usually based on local storage as data source.
  • createTemplateConfig() – Customizes the template config, which includes game loading and initialization steps.
  • createModel() – Creates a custom player model tailored to your backend and game type.
  • createSystemConfig() – Customizes the engine config, including the initial configuration for all engine managers and systems, such as the renderer.

In addition, you can override built-in managers or create custom ones. All managers receive the PlayerModel and must be created once per controller instance:

  • createRoundManager() – Creates a custom round manager responsible for handling game rounds. This includes creating the model, generating features from the backend, and handling round interruptions.
  • createIntegrationsManager() – Creates a custom integrations manager to handle bridge between the game and external services.
  • createJurisdictionsManager() – Creates a custom jurisdictions manager to handle jurisdiction-specific logic.
  • createCustomManagers() – Allows creating custom managers that can be used throughout the game. The default implementation registers AutoplayManager.

System Config Customization

The SystemConfig is used to configure the engine. It includes the initial configuration for all engine managers and systems, such as the renderer and state machine. The config can be merged with project defaults via ConfigUtil.overrideConfig().

Define only the sections that need adjustments. Everything else can fall back to template defaults and environment-specific overrides.

  • application – Renderer setup, ticker limits, device wrapper, auto-resize strategy, and canvas details.
  • dependencyManager – Dependency inversion container with optional dependency replacements, timeline extensions, and component registrations.
  • inputManager – Toggles context menu handling on the game canvas.
  • performanceMonitor – Placement, colors, and visibility of the runtime performance overlay.
  • localeManager – Default language and fallback languages for translations.
  • viewportManager – Available viewport configurations and supported resolutions.
  • stateMachine – Startup transitions and default state for the template state machine.
  • soundManager – Default volume and auto-mute behaviors during blur and loading.

System Config Override Example

export class GameController extends PlayerController {
protected override createSystemConfig():Optional<SystemConfig> {
return ConfigUtil.overrideConfig(super.createSystemConfig(), {
application: {
backgroundColor: '#000000',
displayEngineVersion: false,
clearBeforeRender: true,
applicationCanvas: '#game-canvas'
},
inputManager: {
disableContextMenu: true
},
soundManager: {
enableAutoMute: true,
enableLoadingAutoMute: true,
defaultVolume: 0.6
}
});
}
}

Template Config Customization

Template config controls the loading pipeline, splash screen, and main scene activation. To customize game loading steps, such as backend authentication, override the template config. You can use several parameters to insert custom steps:

  • initialLoaderStepsQueue – A list of steps executed right after loading initial resource bundles. Useful for initializing UI components, such as popups with localized error messages.
  • preLoaderStepsQueue – Steps executed before loading resources. Ideal for backend player authorization or integration setup.
  • postLoaderStepsQueue – Steps executed after loading resources.

Authentication Step Example

To add a backend authentication step, extend the GameController and add a custom step to the preLoaderStepsQueue:

export class GameController extends PlayerController {
protected override createTemplateConfig():Optional<TemplateConfig> {
return ConfigUtil.overrideConfig(
super.createTemplateConfig(), {
preLoaderStepsQueue: [
AuthorizePlayerStep
]
}
);
}
}

Then define the custom loader step:

export class AuthorizePlayerStep extends LoaderStateStep {
public override async enter(loader:LoadingState):Promise<void> {
super.enter(loader);

const response = await authorizePlayer();
// handling the response

this.complete();
}
}

Parameters and Settings Customization

Spinorium provides built-in storage adapters to simplify access to multiple data sources. The PlayerController supports different data sources for parameters and settings. There are two methods to extract data from storage:

  • createProxyObject(config) – Creates a static object based on the current storage state. Changes to the storage or object are not reflected in each other. Use it for launch parameters that should not be mutated later.
  • createProxy(config) – Creates a live proxy bound to storage. Changes to the proxy update the storage and vice versa. Perfect for runtime preferences that must persist between sessions.

PlayerController caches both objects, so construct them once and let the controller reuse them. Switching to live proxies is handy for mutable player preferences such as volume sliders, while a plain object keeps initialization parameters deterministic. Every storage entry must define its type and default value, ensuring that the controller never starts with undefined data.

Storage Usage Example

export interface GameParameters {
playerToken:string;
language:string;
}

export interface GameSettings {
turboSpin:boolean;
showSplashScreen:boolean;
volume:number;
}

export class GameController extends PlayerController<GameModel, GameParameters, GameSettings> {
protected override createParameters():GameParameters {
return System.urlStorage.createProxyObject<GameParameters>({
playerToken: { storeType: StorageValueType.STRING, value: null },
language: { storeType: StorageValueType.STRING, value: 'en' }
});
}

protected override createSettings():GameSettings {
return System.localStorage.createProxy<GameSettings>({
turboSpin: { storeType: StorageValueType.BOOLEAN, value: false },
showSplashScreen: { storeType: StorageValueType.BOOLEAN, value: true },
volume: { storeType: StorageValueType.NUMBER, value: 1 }
});
}
}

Studio Template

Studio templates typically provide a CommonController class that extends the base PlayerController with additional properties and functionality specific to the studio's requirements:

  • Custom loading steps such as authentication.
  • Custom managers initialization (usually at least BackendManager, UIManager and DebugManager).
  • Custom modules configuration.
  • Default game parameters, settings and player model.
  • Default system and template configs.