P3-SDK 0.9
P3 Software Development Kit
Loading...
Searching...
No Matches
Creating Your Playfield Module

Introduction

Upper playfield modules contain all of the playfield features beyond the row of scoops on the P3 playfield and in some cases additional features that mount elsewhere, such as over the lower playfield or on top of the bbackbox (eg. a topper). New game developers can optionally develop new upper playfield modules for their game, or they can write their game to work with one or more existing playfield modules. Creating a new playfield module involves both creating the physical module and also creating a "module driver" so software running on the P3 knows how to interface to the playfield module's features.

Mechanical Specs

Multimorphic publishes mechanical specifications and some CAD files useful for creating the physical playfield module.

This includes:

  • The playfield surface and backpanel
  • Physical mechanisms (ramps, loops, toys, coils, LEDs, switches, etc)
  • Launch tubes for interfacing to the P3's ball trough / launching system
  • Templates for artwork (cabinet, backbox, apron, side target, slingshot, translite)

To access the hardware specifications, first create an account on the Multimorphic's Account Page. Then click over to the Support page -> Maintenance, troubleshooting, technical manuals, how-to videos, tutorials, etc. -> 3rd-Party Development Kit.

For more details on the mechanicals, please contact support@multimorphic.com

Electronic Specs

In order to communicate with the rest of the P3 system, playfield modules generally need SW-16 switch boards that keep track of the states of every switch on the playfield, and they need PD-16 and/or PD-LED driver boards to control coils/DC-motors/magnets and LED/Servos/Steppers, respectively.

For more details on the electronics, please contact support@multimorphic.com

Playfield Module Identifier

Every upper playfield module design has a unique identifier (string) that is read by the P3 at startup. This identifier is assigned by Multimorphic. To request an identifier for a new module, contact support@multimorphic.com. That identifier will then be used in a number of places to help inform the P3 when a specific module is installed and to tell the P3 what files to load to understand how an app can interact with the module.

Playfield Module USB Device

To identify itself to the P3 machine when installed, playfield modules need a USB storage device with specific contents, including an identification certificate provided by Multimorphic. Please contact support@multimorphic.com for more information about the USB device.

Playfield Module Driver

A playfield module driver includes a number of files that allow apps on the P3 to interact with features on the playfield module. It is installed in the ~/.multimorphic/P3/ModuleDrivers/<module_identifier>/<module_driver_version>/ folder. When installing a module driver package on the P3, System Manager will ensure the files are installed in the right place. For simulating on a development machine, the module driver files should be installed in the ~/.multimorphic/P3/ModuleDrivers/<module_identifier>/<module_driver_version>/ folder.

On Windows development machines, ~/ refers to "%HOMEDRIVE%%HOMEPATH%". To find the .multimorphic directory on a Windows machine, open up a command line and type cd /d "%HOMEDRIVE%%HOMEPATH%". When writing your game app, you simply define the ModuleID field in AppConfig.json, and the framework will handle the rest, loading the appropriate hardware configuration file, if it finds a matching module driver.

The files a module developer should create and include in the module driver are:

  • <module_identifier>.json : The Module Definition File (required)
  • <module_identifier>.dll : The compiled source code for controlling the module's features (required if the module has any features with switches or drivers)
  • <diagnostics-assets-file> : A Unity asset bundle that includes the Unity assets to be displayed/controlled when the Playfield Module option is selected in the P3's Diagnostics application for testing playfield module features.
  • UsageInstructions.txt : One or more files to help app developers understand how to interface to various features included in the module driver DLL.

Module Definition File

A playfield module definition file is what tells an app some specific details of features on the playfield. These details are required to be written in the JSON format, with specific fields as described below:

Available Sections:

Section Description
Game Global parameters for the game
Flippers One entry for each device that is automatically driven by the hardware when the flipper buttons are hit
Bumpers One entry for each device that is automatically driven by the hardware when the corresponding switch is hit
UpperDisplay Information on the presence and resolution of the mini-display on the playfield module
TroughLaunchers Information required by game applications to configure trough-based ball launchers.
Switches One entry for each switch
Coils One entry for each coil
LEDs One entry for each LED
LEDStrings One entry for each WS2812-compatible string of LEDs
Servos One entry for each servo motor
Steppers One entry for each stepper motor
BallPaths One entry for each playfield-specific shot and target

Coordinate System

Some fields specify a position on the playfield as an array of 3 floats [x, y, z]. The coordinate system is measured in inches, where [0,0,0] is the front left corner of the playfield module at the surface of the playfield. Positive x increases towards the right of the machine. Positive y increases towards the back of the machine. Positive z increases upwards from the playing surface. This means positions over the playfield screen use negative y coordinates.

Example:

"TroughLaunchers": [
{
"Name": "LeftVUK",
"VUKNumber": 3,
"HighSwitch": "vukExit3",
"LowSwitch": "vukEntrance3",
"Bidirectional": true,
"CustomCode": false,
"Destination": "LeftInlane",
"EntrancePosition": [3.750,7.5,0],
"ExitPosition": [3.750,7.5,0]
}
],

Game Section

This section describes a few global parameters:

Field Type Description
Name string Name of the playfield module
machineType string Must be "PDB"
numBalls int Minimum number of balls that must be installed for normal operation of apps on this module. This is informative and not strictly enforced. Installing more balls is possible. Some apps may try to compensate if fewer balls are installed, but that normally results in a degraded experience.

Example:

"Game": {
"Name": "LL-EE",
"machineType": "PDB",
"numBalls": 17
},

Flippers Section

This section describes each flipper that is part of the playfield module design. Flippers are devices that are automatically driven by the hardware when the flipper buttons are hit.

Playfield module definition files should contain descriptions of flippers on the module itself plus the upper flippers (right above the side targets) that are safe and/or intended to be used with the module. Playfield module definition files must not contain descriptions of the lower main flippers, nor upper flippers that must remain disabled by design.

The Flipper definitions include the following fields:

Field Type Description
Name string Name of the flipper
SettingsPrefix string Prefix for the GameAttributes associated with the flipper. These GameAttributes appear under "Service Menu/Settings/Mechs/Coils".
SwitchName string Switch name for the button used for primary activation.
SecondarySwitchName string Switch name for the button that should activate the flipper when one-handed play is enabled.
AlternateSwitchName string Switch name for the button that should activate the flipper when the 'activate all flippers with red buttons' operator setting is active.
EOSSwitchName string Name of the End Of Stroke Switch. Field is absent if no EOS Switch.
MainCoilName string Name of the Coil that provides the initial stroke.
HoldCoilName string Name of the Coil that keeps the flipper up.
Tags string Comma-separated list of tags the software can optionally use.

Example:

"Flippers": [
{
"Name": "flipperUpR",
"SettingPrefix": "UpperRightFlipper",
"SwitchName": "buttonRight2",
"SecondarySwitchName": "buttonLeft2",
"AlternateSwitchName": "buttonRight0",
"MainCoilName": "auxRight0",
"HoldCoilName": "auxRight1"
},
{
"Name": "flipperUpL",
"SettingPrefix": "UpperLeftFlipper",
"SwitchName": "buttonLeft2",
"SecondarySwitchName": "buttonRight2",
"AlternateSwitchName": "buttonLeft0",
"MainCoilName": "auxLeft0",
"HoldCoilName": "auxLeft1"
},
{
"Name": "flipperMezzanine",
"SettingPrefix": "MezzanineFlipper",
"SwitchName": "buttonLeft2",
"SecondarySwitchName": "buttonRight2",
"AlternateSwitchName": "",
"MainCoilName": "MezFlipperMain",
"HoldCoilName": "MezFlipperHold"
}
],

Note - The upper flipper coils (auxRight0, auxRight1, auxLeft0, auxLeft1) are part of the base machine definition; they must not be defined in the Playfield Module Definition File.

Bumpers Section

This section describes each bumper. Playfield module definition files should only contain descriptions of bumpers that are part of the playfield module design. Bumpers are all devices for which the device's coil should be pulsed immediately following the activation of the device's switch. These typically include slingshots and pop bumpers.

The Bumper definitions include the following fields:

Field Type Description
Name string Name of the bumper
SwitchName string Name of the Switch that activates the bumper
CoilName string Name of the Coil to be pulsed when the bumper activates
SettingName string Name of strength setting for the bumper. The setting can be shared with other pop bumpers or independent.
SwitchPolarity bool Polarity of the switch. Use true for NO switches, false for NC. Using the correct polarity will ensure the associated coil activates as quickly as possible when the ball hits the bumper.
AllowShotgunning bool If true, the coil will fire on every switch event. If false, the coil won't fire a second time due to switch events happening within the next 64ms.
Tags string Comma-separated list of tags the software can optionally use.

Example:

"Bumpers": [
{
"Name": "popBumper",
"SwitchName": "popBumper",
"CoilName": "popBumper",
"SettingName": "PopBumperPulseTime",
"SwitchPolarity": true,
"AllowShotgunning": true
}
],

UpperDisplay Section

This section describes the mini-display on the playfield module, when applicable. For example, Lexy Lightspeed - Escape From Earth and Cannon Lagoon have a mini-display, but Heist does not.

The UpperDisplay section includes the following fields:

Field Type Description
Present bool true when the module has a mini-display, false otherwise
Width int Horizontal resolution of the mini-display, when applicable
Height int Vertical resolution of the mini-display, when applicable

Example 1:

"UpperDisplay": {
"Present": true,
"Width": 800,
"Height": 480
},

Example 2:

"UpperDisplay": {
"Present": false
},

TroughLaunchers Section

This section describes each TroughLauncher, which is a mechanism used to launch a ball from the P3's trough out to the playfield. The mechanisms usually just include a tube that mates with the P3's trough and one or two switches. Tubes are available from Multimorphic for each available trough launch position, and they can be ordered with or without switches. They can also be ordered with a ball-stopper, which keeps balls from rolling past that launch position in the trough. The leftmost tube installed on a playfield should contain the ball-stopper.

The TroughLauncher definitions include the following fields:

Field Type Description
Name string Name of the launcher (not used by any code)
VUKNumber int Trough position for the launcher. There are 8 physical positions from left to right (0-7). 4 is the center one. There is no available launcher on the right end of the playfield. See the note below for launchers >= 8.
HighSwitch string Name of the higher of two possible switches. Required for all TroughLaunchers. For tubes used only for launching (Bidirectional=false), this switch is usually installed after the make point on the ball delivery system so that a switch event means a ball successfully exited the tube. The make point is the point at which the ball can no longer fall back into the tube.
LowSwitch string Name of the lower of the two possible switches. Required for Bidirectional=true TroughLaunchers. Not used for Bidirectional=false TroughLaunchers. In Bidirectional configurations, the software uses the LowSwitch to determine when a ball is going up the tube and when a ball is coming down the tube.
Bidirectional bool true for bidirectional operation (requires both HighSwitch and LowSwitch definitions). false for unidirectional operation (requires HighSwitch only).
CustomCode bool true for complex launching mechanisms that require custom code to get the ball into play (eg. multi-stage launchers or launchers with diverters).
Destination string Identifies the destination of the ball launch. See the available values below.
EntrancePosition float[] Geographic coordinate of the hole entrance, in inches: [x, y, z]. For bidirectional TroughLaunchers only.
ExitPosition float[] Geographic coordinate where the ball enters the playfield, in inches: [x, y, z]. This could be right above the TroughLauncher (like in CL) or at an inlane (like in LL-EE).
Tags string Comma-separated list of tags the software can optionally use.

Example:

"TroughLaunchers": [
{
"Name": "LeftVUK",
"VUKNumber": 3,
"HighSwitch": "vukExit3",
"LowSwitch": "vukEntrance3",
"Bidirectional": true,
"CustomCode": false,
"Destination": "LeftInlane",
"EntrancePosition": [3.750,7.5,0],
"ExitPosition": [3.750,7.5,0]
},
{
"Name": "RightVUK",
"VUKNumber": 5,
"HighSwitch": "vukExit5",
"LowSwitch": null,
"Bidirectional": false,
"Destination": "RightInlane",
"EntrancePosition": [14.374,7.5,0],
"ExitPosition": [14.374,7.5,0]
}
],

The TroughLauncher Destination field is used by apps that don't know specific details about the playfield (like apps written to work with any playfield module) to be able to request launches to useful destinations. Options include:

Destination Description
"LeftInlane" Feeds the wireform going to the left inlane.
"RightInlane" Feeds the wireform going to the right inlane.
"LowerPlayfield" Ejected balls will find their way to the lower playfield, even if walls/scoops are raised.
"UpperPlayfield" Ejected balls would get stuck behind any walls/scoops that are raised.
"StagingArea" Ejected balls go into another position that isn't in-play on the playfield.

These options are defined in Multimorphic.P3.Mechs.LaunchDestination

Note - it is possible to define multiple TroughLaunchers for the same tube for cases where a launch tube feeds a diverter or something else that can alter the movement of the ball. To do this, add 8 to the VUKNumber for each additional definition. TroughLaunchers that share the same tube must have identical values for the HighSwitch, LowSwitch, and Bidirectional fields. Balls detected as coming down a bidirectional tube will always get detected as coming down the actual/physical tube number (0-7).

Example:

"TroughLaunchers": [
{
"Name": "RightVUK",
"VUKNumber": 6,
"HighSwitch": "vukExit6",
"LowSwitch": "vukEntrance6",
"Bidirectional": true,
"CustomCode": false,
"Destination": "StagingArea"
},
{
"Name": "RightVUKToLeftInlane",
"VUKNumber": 14,
"HighSwitch": "vukExit6",
"LowSwitch": "vukEntrance6",
"Bidirectional": true,
"CustomCode": true,
"Destination": "LeftInlane"
}
],

Switches Section

This section describes each switch on the playfield module. Switches are wired to Multimorphic switch boards (available from Multimorphic). The first board must be set to address 4. Additional switch boards can be added, with addresses > 4. Each address corresponds to 16 switches. Therefore, the switch connected to the first input on address 4 is assigned number (16 * 4) = 64.

The Switch definitions include the following fields:

Field Type Description
Name string Name of the switch. This is the name software will use to read the switch.
Type string "NC" for normally closed switches (switches that pull the switch board input to ground by default. "NO" for normally open switches.
Number string Value of 16*board address + board input number, converted to string.
Label string User-friendly string for displaying the switch name on graphics.
DebounceRequired bool false turns off debouncing, saving 1-2ms. Generally optos do not need debouncing, but that depends on the scenario. Default is true.
Tags string Comma-separated list of tags the software can optionally use.
Location float[] Geographic coordinate of the switch, in inches: [x, y, z].

Example:

"Switches": [
{
"Name": "leftRamp",
"Type": "NC",
"Number": "68",
"Label": "Left Ramp"
},
{
"Name": "innerLoopRight",
"Type": "NC",
"Number": "69",
"Label": "Inner Loop Right",
"DebounceRequired": false
},
{
"Name": "popBumber",
"Type": "NO",
"Number": "93",
"Label": "Pop Bumper"
}
],

Coils Section

This section describes each coil on the playfield module. Coils are wired to Multimorphic driver boards (available from Multimorphic). The first board must be set to address 6. Any number of additional driver boards can be added, with board addresses > 6. Each address corresponds to 16 coils (or other devices), configured as two banks of 8 (bank 0 and bank 1).

The Coil definitions include the following fields:

Field Type Description
Name string Name of the coil. This is the name software will use to drive the coil.
Number string This is a formatted string Ax-By-z, where x is the board address, y is the bank number, and z is the output number.
Label string User-friendly string for displaying the coil name on graphics.
PulseTime int Default pulse length in milliseconds. Software can override this.
Tags string Comma-separated list of tags the software can optionally use.

Example:

"Coils": [
{
"Name": "popBumper",
"Number": "A6-B0-2",
"Label": "Pop Bumper",
"PulseTime": 8
}
],

LEDs Section

This section describes each LED on the playfield module. LEDs are wired to Multimorphic PD-LED boards (available from Multimorphic). The first board must be set to address 9. Any number of additional PD-LED boards can be added, with board addresses > 9. Each address corresponds to 84 direct-wired LEDs (or 28 RGB LEDs) or up to 2048 RGB LEDs in one or more serial strings.

The LED definitions include the following fields:

Field Type Description
Name string For a single RBG LED driven by a PD-LED RGB output or an LED string segment consisting of a single RGB LED, this is the name software will use to drive the LED.

or

For an LED string segment consisting of more than one RGB LED, this is the baseName without the index suffix, the full name including the index suffix is what the software will use to drive each LED.
Polarity string "True" if the LED turns on by controlling the anode. "False" if the LED turns on by controlling the cathode.
Number string For a single RGB LED driven by a PD-LED RGB output:
This is a formatted string "Ax-Rr-Gg-Bb", where x is the board address, r is the output connected to an RGB's red input, g for the green output, and b for the blue output. The software only provisions RGB LEDs, but the hardware supports individual LEDs. If your module contains individual LEDs, you can control them in software by accessing only that color of the RBG LED defined here.

or

For an LED string segment consisting of a single RGB LED:
This is a formatted string "Ax:Sa", where x is the board address, and a is the LED string index. The name of the LED is taken as given without appending an index.

or

For an LED string segment consisting of more than one RGB LED:
This is a formatted string "Ax:Sa-Sb", where x is the board address, a is the starting LED string index, and b is the ending LED string index. This LED definition will be replaced by a set of LED definitions, baseName0,...,baseName{b-a}, with one definition for each RGB LED that composes this LED string segment. The application will never see the LED definition with just the baseName.

Note: if using an LED string, your Module Definition File must also include an LEDStrings section to describe how the strings themselves should be defined.
MaxBrightness double A value between 0 and 1. Limits the available power range for an LED. This value is multiplied against the desired LED color value before the resulting value is sent to hardware.
Label string User-friendly string for displaying the LED name on graphics.
Tags string Comma-separated list of tags the software can optionally use.
Location float[] Geographic coordinate of the LED, in inches: [x, y, z].
MapIntoSpecialLEDFeatures string Used for individually controlled features mapped to a PD-LED output, such as a motor control line. When "True", this item won't appear in the P3's LED Diagnostics.
DependentSwitch object Ensures the switch is the desired state at startup. If not, this item will be ignored by the configuration logic. This a JSON object of the form: {"SwitchName": string, "SwitchActive": bool}. For example {"SwitchName": "servoWS", "SwitchActive": false}

The LED definitions created from an LED string segment will all share the same location after reading the module definition file. The module driver must include code to assign the correct locations after the fact, otherwise the LED simulator will display these LEDs all on top of each other, and games will not be able to compute light show sweeps correctly.

Example:

"LEDs": [
{
"Name": "flasherShip",
"Polarity": "True",
"Number": "A9-R0-G1-B2",
"Label": "Flasher Ship"
},
{
"Name": "topTarget0",
"Polarity": "False",
"Number": "A9-R60-G61-B62",
"Label": "Top 0"
},
{
"Name": "CafeSign",
"Polarity": "True",
"Number": "A9:S100-S104",
"Label": "Cafe Sign",
"Location": [2,14,5]
},
{
"Name": "FoodL",
"Polarity": "True",
"Number": "A9:S105",
"Label": "Food Left",
"Location": [3.25,14,4]
}
],

LEDStrings Section

This section describes WS2812-compatible strings of LEDs, each driven by a single string output from a Multimorphic PD-LED boards (available from Multimorphic). The StartingIndex and EndingIndex are RGB indices. The first LED element will be at 3*StartingIndex and the last LED element will be at 3*EndingIndex+2.

The LEDString definitions include the following fields:

Field Type Description
Name string Name of the LEDString. Usually something generic like "Board 9 - String 0"
Number string This is a formatted string Ax-WS2812-a, where x is the board address and a is the string output (usually 0 to 2).
Polarity string "True" for LEDs that turn on with a high control signal. "False" for LEDs that turn on with a low control signal.
RGBOrder string Typically "GRB" for a WS2812 string
StartingIndex int The starting LED index for the first color of the first RGB LED in a string, as referenced in the PD-LED's LED indexing.
EndingIndex int The ending LED index for the last color of the last RGB LED in a string, as referenced in the PD-LED's LED indexing.
Label string User-friendly string for displaying the LEDString name on graphics.
Tags string Comma-separated list of tags the software can optionally use.

Example:

"LEDStrings": [
{
"Name": "Board 9 - String 0",
"Number": "A9-WS2812-0",
"RGBOrder": "GRB",
"StartingIndex": 100,
"EndingIndex": 199,
"Label": "Board 9 - String 0"
}
],

Servos Section

This section describes each servo on the playfield module that is wired to a Multimorphic PD-LED board (available from Multimorphic). Each PD-LED board can control the operation of up to 12 servos.

The servo definitions include the following fields:

Field Type Description
Name string Name of the servo motor. This is the name software will use to drive the motor.
Number string This is a formatted string Ax-y, where x is the address of the PD-LED board, and y is the index of the servo on the board (0-11, refer to the PD-LED board specifications).
Label string User-friendly string for displaying the motor name on graphics.
Tags string Comma-separated list of tags the software can optionally use.

Example:

"Servos": [
{
"Name": "rampDiverter",
"Number": "A9-0",
"Label": "Ramp Diverter"
}
],

Steppers Section

This section describes each stepper motor on the playfield module that is wired to a Multimorphic PD-LED board (available from Multimorphic). Each PD-LED board can control the operation of up to 2 stepper motors, connected through a separate stepper motor driver circuit.

The stepper motor definitions include the following fields:

Field Type Description
Name string Name of the stepper motor. This is the name software will use to drive the motor.
Number string This is a formatted string Ax-y, where x is the address of the PD-LED board, and y is the index of the stepper motor on the board (0 or 1, refer to the PD-LED board specifications).
Label string User-friendly string for displaying the motor name on graphics.
Tags string Comma-separated list of tags the software can optionally use.

Example:

"Steppers": [
{
"Name": "movingToy",
"Number": "A9-0",
"Label": "Moving Toy"
}
],

BallPaths Section

This section describes definitions of BallPaths, which allow a game application to make use of playfield-specific shots and targets even if the application has no specific knowledge about which playfield is installed in the P3 at run-time. This section is therefore REQUIRED in all module drivers for all shots that aren't simply entrances into TroughLaunchers that aren't handled by a module driver. Said another way, if a shot does not go into a TroughLauncher or if a shot goes into a TroughLauncher and the module driver handles that entrance and posts other events, the shot needs to be defined here.

The events defined in BallPaths must be implemented in the associated module driver code. The module driver is what determines that a shot starts or completes, and then it posts the associated Started and Completed events defined in the BallPath definitions.

The BallPath definitions include the following fields:

Field Type       Description
Name string Name of the BallPath. This is the name software will use to reference the BallPath.
Tags string[] Array of tags the software can optionally use.
ExitType string String name of the associated Multimorphic.NetProcMachine.Config.BallPathExitType enum. See below for the available values.
EntranceName string String name of the entrance into the shot (can be anything)
ExitName string String name of the exit of the shot (can be anything)
StartedEvent string Event name that's posted when the shot is started (ie. a ball hits the first switch in a loop)
CompletedEvent string Event name that's posted when the shot is completed (ie. a ball completes a loop)
EntrancePosition float[] Geographic coordinate of the shot entrance, in inches: [x, y, z]
ExitPosition float[] Geographic coordinate of the shot exit, in inches: [x, y, z]
EntranceLEDs string[][] Array of arrays of LED segments. The first dimension is typically for parallel arrays, like the inside and outside strings of LEDs on a Cosmic Cart Racing ramp. The second dimension is the sequence of LEDs, starting closest to the shot entrance. An LED segment can either be an LED name denoting an individual LED, or a formatted string basenameX-Y denoting an LED string segment, where basename is the LED name without an index, X is the starting index and Y is the ending index, inclusive. The SDK will replace basenameX-Y by splicing in its place the sequence of LED names basenameX,...,basenameY. The application will never see the basenameX-Y notation. If no LEDs are associated with the shot, use [[""]].
ExitLEDs string[][] Array of arrays of LED segments. The first dimension is typically for parallel arrays, like the inside and outside strings of LEDs on a Cosmic Cart Racing ramp. The second dimension is the sequence of LEDs, starting closest to the shot exit. An LED segment can either be an LED name denoting an individual LED, or a formatted string basenameX-Y denoting an LED string segment, where basename is the LED name without an index, X is the starting index and Y is the ending index, inclusive. The SDK will replace basenameX-Y by splicing in its place the sequence of LED names basenameX,...,basenameY. The application will never see the basenameX-Y notation. If no LEDs are associated with the shot, use [[""]].

Example:

"BallPaths": [
{
"Name": "LeftLoop",
"Tags": ["Loop","Passthrough","Default"],
"ExitType": "PlayfieldLocation",
"EntranceName": "LeftLoop",
"ExitName": "Pops",
"StartedEvent": "Evt_LeftLoopStarted",
"CompletedEvent": "Evt_LeftLoopHit",
"EntrancePosition": [2,0,0],
"ExitPosition": [10,15,0],
"EntranceLEDs": [["LeftLoopInner0-2"],["LeftLoopOuter0-2"]],
"ExitLEDs": [[""]]
}
],

In the example, the EntranceLEDs will be expanded into:

"EntranceLEDs": [["LeftLoopInner0","LeftLoopInner1","LeftLoopInner2"],["LeftLoopOuter0","LeftLoopOuter1","LeftLoopOuter2"]],

The ExitType describes what happens to the ball when the BallPath is completed. The options are:

ExitType Description
Undefined Reserved for use by the module driver, typically for error handling. This is not a user-makeable shot. Module agnostic games should ignore this BallPath.
Other Choose this when none of the other options apply
PlayfieldLocation Ball remains in play somewhere on the playfield
Hole Ball falls into the trough and is no longer in play
Lock Ball enters a physical lock and is no longer in play
TemporaryLock Ball may take a while to exit, but remains in play, for example a pop area.
Target Ball activates a Switch and remains in play

Suggested Tags to choose from:

Tag Description
Default This dynamic BallPath is active by default when the application starts.
Hole The ball enters a hole when completing this BallPath.
Inaccessible This BallPath is used to reposition a mech so that the ball can no longer enter the entrance. The Started and Completed events will never be fired.
Lock The ball enters a physical lock when completing this BallPath.
Loop This BallPath is an orbit.
Passthrough The ball remains in play and is free to move after completing the BallPath, without intervention from the application.
Ramp This BallPath is a ramp.
Scoop The ball enters a scoop when completing this BallPath.
Spinner This BallPath may complete multiple times for a single shot. The application might choose to implement a cool down period to ignore the subsequent events if it wants to count the shot only once.
Static This BallPath does not change and is always available (should be the only one with this entrance name).
Target This BallPath is a Target.

Some conventions to keep in mind when designing your BallPaths:

  • Name is PascalCase as <EntranceName>To<ExitName> when EntranceName != ExitName.
  • Name is PascalCase as <EntranceName> when ExitName == EntranceName (typically only true for Hole and Targets).
  • EntranceName and ExitName are also PascalCase and they are not necessarily Switch names.
  • An EntranceName (or ExitName) defines a consistent set of switches/criteria (i.e., two paths cannot have the same EntranceName if the switches/state are not identical).
  • StartedEvent is Evt_ShotStarted_<EntranceName>, since the module driver probably does not know exactly which path has started, dynamic BallPaths sharing the same EntranceName also share the same StartedEvent value.
  • CompletedEvent is Evt_ShotMade_<BallPathName>

Example Module Definition Files

The development kit includes a number of existing module drivers so that developers can create new apps that work with those modules. Each has a module definition file that can serve as an example.

Developing The DLL

So that game apps can interact with the features on your module, you'll likely need to develop a module driver DLL. An example module driver DLL project is included in the development kit as a Visual Studio project called SampleModuleDriver. The code generally includes handling for custom launch destinations, ball paths, event-based control of specific playfield module features, etc.

Main Components of a Module Driver DLL

A module Driver DLL must contain:

  • A ModuleController (subclass of PlayfieldModuleController )
  • One or more devices (subclasses of PlayfieldDeviceController ) - This contains the logic for one or more devices on the playfield. You could implement all of your devices in a single device file or use a separate device file for each.
  • A diagnostics mode (subclass of PlayfieldModuleDiagnosticsMode ) - This contains the logic that should execute when the Playfield Module option is selected in the P3 Diagnostics application. It includes parameters that define an asset bundle and prefab that should be added to the Diagnostics Unity hierarchy when the code is loaded. This is how Diagnostics knows how to show a graphical representation of the playfield module features; you build the Unity objects into the prefab. There's also a parameter for the name of the class that should be instantiated onto the object so that code can control those graphical elements, perhaps by responding to ModeToGUI events posted by your ModuleDriverDiagnosticsMode in response to various button presses.

Custom Launch Code

If a playfield module has any complex launching mechs, such as a multi-stage launcher or a launcher with a diverter, the playfield module definition file should include the "CustomCode" property on the associated TroughLauncher. Then, when a game app requests a launch out of that TroughLauncher, the platform launching code will post the ModeToMode event "Evt_CustomLaunchPrep" with a TroughLauncherDefinition param. The playfield module driver should subscribe to that event and use the TroughLauncherDefinition to see which TroughLauncher is being used for the launch. The actual launch is then paused (except for a timeout timer) until the module driver posts a response. See more details below:

ModeToMode events posted to module driver:

Event Name Parameter Type Description
Evt_CustomLaunchPrep TroughLauncherDefinition Posted when beginning a custom launch, telling the module driver to do whatever it needs to do before the TroughLauncher should attempt to kick up a ball. The module driver should do what it needs to do and then post a response (see below responses) to signal it's ready for completion or to delay the launch logic from timing out.
Evt_CustomLaunchFollowUp TroughLauncherDefinition If the module driver requested a "LaunchBallAndPostCustomFollowUp" from the TroughLauncher in its response to the Evt_CustomLaunchPrep event, the TroughLauncher will post this event after it kicks the ball up, telling the module driver to handle the ball and do any cleanup it needs to do before verifying the launch. The module driver should do what it needs to do and then post a response (see below responses) to confirm a launch success or failure.

Response ModeToMode events posted to module driver:

Event Name Parameter Type Description
Evt_CustomLaunchPrepComplete Multimorphic.P3.Mechs.CustomLaunchResponse enum When responding to an Evt_CustomLaunchPrep event, the module driver should indicate when the TroughLauncher should either LaunchBall or LaunchBallAndPostCustomFollowup (in the case there's more work to do after the ball is launched but before the full launch should be confirmed.
Evt_CustomLaunchStageComplete Multimorphic.P3.Mechs.CustomLaunchResponse enum This is used after a followup stage is completed after a ball is launched to either confirm the launch was a success or failure.
Evt_CustomLaunchResetRetryTimer double How much time to delay before timing out (TroughLaunchers will default to timing out a custom launch request after 2.0s)

Module Driver Diagnostics

To help you make your module driver's diagnostic prefab and ensure it shows up properly, the P3 SDK includes a Unity project called SampleModuleDriverDiagnostics. It is a subset of the P3's full Diagnostics just for simulating your Playfield Module's Diagnostics routines. It includes a very simple example module driver prefab called Assets/SampleModuleDriver/SampleModuleDriver_Diags.prefab. To change this for your Module Driver, drag it into the heirarchy, modify it as desired (including renaming it), and then drag it back into a Project folder. Then, to export your asset bundle file, select the prefab in the Project window (not in the Hierarchy), and at the bottom of the inspector window, select the AssetBundle dropdown, and add a new module driver asset bundle name. Most Multimorphic module drivers call it <module_identifier>-diags-assets. Then to build it, click Assets -> Build AssetBundles. It should then appear in Assets/AssetBundles, and you can now copy it into your module driver folder in ~/.multimorphic/P3/ModuleDrivers/<module_identifier>/<module_driver_version>/. The example is simply a counter. The text element is defined in the prefab, and the code that sends counter updates is in the module driver code.

Building the Module Driver Package

Follow these steps to build an installable package of your module driver for your P3. In Unity, select from the top menu Multimorphic->"Package Module For Distribution". Fill in the fields in the dialog that appears and click "Continue". An internet connection is required.

When the process completes, you should have a new .p3p file within your project's Packages directory. The dialog also offers the option to write a copy of the .p3p file to a USB drive during the build.

The .p3p file can then be installed on your P3 via a USB drive.

  • Note: The current dev kit does not include the ability to deploy to a P3 programmatically.

These are the fields presented in the packager dialog:

Field Description
Module Id The module identifier
Version Module driver version (recommended format: a.b.c.d)
Files to Include The path to a folder. All files within the folder will be included in the package. This folder should contain the module driver DLL, the module definition file, the diagnostics asset bundle and a document describing the module driver API to software developers.