Tutorial step 14: Add your first game mode¶
By this point in the tutorial you should have a “playable” game, though it’s pretty boring because there’s no scoring, no modes, and the display just shows PLAYER X BALL X the whole time.
So in this
step the real fun will begin as we configure our first game mode! So
far all of the configuration you’ve been doing has been machine-wide
configuration which was stored in the /config
folder in your game’s
machine folder.
All of the configuration options you added to the config.yaml
applied machine-wide.
In this step, we’re going to add a /modes
folder to your machine
folder. Then we’ll add a subfolder for each game mode, and in each
we’ll create a YAML config file that controls what happens in that
specific mode.
What’s cool about MPF’s modes system is that all of the configuration you do for a mode is only active when that mode is active. In fact from here on out, almost everything you configure will be at the mode-level rather than the machine-wide level. As we go deeper into the tutorial and the How To guides, you’ll start to get a feel for what types of things should be in the machine-wide configuration versus the types of things that should be in mode-specific configurations. Pretty much all the hardware (coils, switches, lights, leds, ball devices, platform, DMD, etc.) are configured as machine-wide settings, and then game logic-type things (scoring, shots, sound effects, animations, light shows, etc.) are configured as mode-specific settings.
MPF can have as many modes running at once as you want. In fact you’ll probably use this to your advantage, breaking up your game into lots of little modes to make the programming easier. (Many of these modes will not be “in your face” modes that the player is aware of. Things like skill shot, combo timers, super jet counters, etc., will all be configured as modes even though the player wouldn’t think of them as modes.)
1. Read the documentation about modes¶
The first step to setting up a game mode is to understand how game modes work in MPF. So read that documentation now to get an overview, and then come back here for the step-by-step walk-through of doing your first mode.
2. Set up the folders & files for your “base” mode¶
The first mode we’re going to create is a mode called “base.” (Don’t call it “game” because MPF has a built in mode called “game” that you don’t want to overwrite.) This “base” mode will be running at all times while a game is in play and can be thought of as the “default” game mode. We’ll set up default shots, scoring, configure the display to show the score, etc. Everything in the base game mode will be available if no other higher-priority modes are running. To create the base game mode:
- Create a folder called
modes
in your machine’s folder. - Create a subfolder your
modes
folder calledbase
. (You will ultimately create one subfolder for each mode you have, and the name of the folder controls the name of the mode.) - Inside your
base
folder, create a folder calledconfig
. (This folder will hold your mode-specific config files.) - Inside your
config
folder, create a file calledbase.yaml
. (This is the default config file for your base mode. We use the naming scheme<mode_name>.yaml
instead ofconfig.yaml
for these to make it easier to keep track of which files are which if you open a bunch of them at once in your editor.)
At this point your machine’s folder & file structure should look like this:

3. Add your base game mode’s settings to its config file¶
The settings that control a mode are configured the mode’s own configuration file. We do this because it allows modes to be completely self-contained. In other words, as long as you have a mode’s folder and all its content, then you have everything you need for that mode.
So let’s configure some settings for the base mode in the base mode’s
config file. To do this, open your new mode’s base.yaml
in your code editor. Add
the config_version, then create a top-level configuration section
called mode:
. On the next line, indent four spaces and add the entry
start_events: ball_starting
. On the following line, also indent four
spaces and type priority: 100
. Your base.yaml
file should now look
like this:
#config_version=5
mode:
start_events: ball_starting
priority: 100
There are lots more settings besides start_events
and priority
which you can set for a mode. See the mode: for details.
The two settings we added here
should be pretty obvious. The start_events: ball_starting
means that
this mode will automatically start when the MPF event
ball_starting is posted. (In other words, this mode will start
whenever a ball starts.) You can also enter a list of stop_events to
control how the mode ends, though if you don’t enter one here then the
mode will automatically stop when the ball ends, so you don’t have to
specify a stop event now.
The priority: 100
means that everything
this mode does will have a base priority of 100. We’ll create future
modes at higher priorities so they can take over the display, control
lights, filter and block scoring, etc. (You read the documentation about modes,
right?)
Also, when you create your own modes, keep them between 100 and 1,000,000. MPF has some built-in modes above and below those values that should stay at the top and bottom of the priority stack.
4. Add your mode to your machine-wide config file¶
Now that you have a mode set up, you need to go back to your machine- wide configuration file to add this new mode to the list of modes that your game will use. At first you might think this is a bit confusing. After all, you just created a folder and a config file for your new mode, so why do you have to specify that mode in another location too?
The reason is we don’t want to automatically include a mode in a game just because that mode has a folder in the modes folder. (After all, what if you’re testing something out, or if you have multiple versions of a mode you’re playing with? It would be dangerous if MPF just automatically loaded every mode it found.)
So instead we built MPF so
that you have to add all the modes you want to be available in a game
to a list in the machine-wide config file. To do this, go back to your
machine-wide config.yaml
file (in <your_machine>/config/config.yaml
)
and add a top-level section called modes:
. (Like all the sections in
your config file, you can put this section anywhere you want in your
file. Maybe up towards the top so it’s easy to find later?) Then on
the next line, type two spaces, then a dash, then another space, then
type base
. So now that section of your config.yaml
should look
like this:
modes:
- base
Note that it’s very important that you put dashes in front of each mode in this list? Why? Because with dashes, MPF will be able to combine settings together in this list from different config files.
For modes that important, because MPF has several built-in modes it uses for its own things. (For example, “attract” and “game” are both modes, and we’ll be creating future ones that you might want to use too for tilt, volume control, game statistics, high score entry, credits, etc.)
5. Run your game to verify your new mode works¶
Be sure to save the changes to base.yaml
and config.yaml
, and then
run your game again. For this test, you do not need to use verbose
logging since mode information is reported in the basic level of
logging. Once MPFis running, start a game and you should see something
like on the console and/or the log file:
INFO : Mode.attract : Mode Starting. Priority: 10
INFO : SwitchController : <<<<< switch: s_start, State:1 >>>>>
INFO : SwitchController : <<<<< switch: s_start, State:0 >>>>>
INFO : Mode.game : Mode Starting. Priority: 20
INFO : Mode.game : Player added successfully. Total players: 1
INFO : Mode.base : Mode Starting. Priority: 100
INFO : SwitchController : <<<<< switch: s_trough_1, State:0 >>>>>
INFO : SwitchController : <<<<< switch: s_shooter_lane, State:1 >>>>>
INFO : SwitchController : <<<<< switch: s_shooter_lane, State:0 >>>>>
6. Make your base mode do something useful¶
We already mentioned that there are lots of different things you could add to your base mode. For now, let’s configure the display so that it shows the player’s score, as well as which player is up and what ball it is, like this:

To do this, go back to your base mode’s config file (<your_machine>/modes/base/config/base.yaml
)
and add a section called slide_player:
. Then add the following subsections so
your complete base.yaml
looks like this:
#config_version=5
mode:
start_events: ball_starting
priority: 100
slide_player:
mode_base_started:
widgets:
- type: text
text: (score)
number_grouping: true
min_digits: 2
font_size: 100
- type: text
text: PLAYER (number)
y: 10
x: 10
font_size: 50
anchor_x: left
anchor_y: bottom
- type: text
text: BALL (ball)
y: 10
x: right-10
anchor_x: right
anchor_y: bottom
font_size: 50
We briefly touched on the slide_player:
functionality earlier in
this tutorial and how you can configure it to show certain slides when
various MPF events happen.
Every time a mode starts in MPF, an event called mode_(name)_started
is posted. So in this case, we set our slide
player entry to play when it sees the event mode_base_started
which
means it will play that slide as soon as the base mode starts. (And
since you configured your base mode to start based on the
ball_starting event, this means this slide will be created and
shown whenever a new ball is started.)
You may be wondering why we don’t set that slide to play on the ball_starting event? The key to remember with game modes is that all the settings in your mode-specific config file are only active when the mode itself is active. In the case of our base mode, the ball_starting event is what actually causes the mode to start. When ball_starting is posted, the base mode starts and loads its configuration. At that point that ball_starting event has already happened, so if you set a slide to play within that mode then it will never play because it doesn’t start watching for that event until after it happened. (Hopefully that makes sense?)
Anyway, if you look at the slide_player:
settings, you’ll see
that the slide that is shown when the event mode_base_started
is posted
contains three text widgets. One that shows the score, one that shows the
player and one that shows the current ball number. Note that the text:
entries
for those have have some words in parentheses.
Words in parenthesis signs are variables that are replaced in real time when they’re updated. In this case these are “player variables” because they are values that belong to the current player. More on using dynamic text (that is, text that automatically updated itself as underlying values change), is here.
Also note that there are some additional positioning settings, like x:
, y:
,
anchor_x:
, and anchor_y:
. You can read about these in our How to position widgets on slides guide.
Finally, note that the text widget showing the score has settings for number_grouping:
and min_digits:
.
You can read about what those do in the documentation for the text display widget.
7. Remove the old slide_player: ball_started entry¶
Now that you have this cool score display from your new base mode, you
can go into your machine-wide config.yaml
and remove the slide_player:
entry for ball_started:. So now the slide_player: in your machine-wide
config.yaml
should just look like this:
slide_player:
init_done: welcome_slide
mode_attract_started: attract_started
What if it didn’t work?¶
- Make sure you actually start a game. Remember that this new base mode is only active when a ball starts from a game that’s in progress, so you won’t see the mode until a game starts. (If you’re not able to start a game, check the troubleshooting tips in the previous step.)
- If you get some kind of crash or error, specifically any errors that mention anything about “config” or “path,” double-check that you put all the files in the proper locations back in Step 2. (A common mistake is to put base.yaml in the /modes/base folder rather than the /modes/base/config folder.)
Check out the complete config.yaml file so far¶
If you want to see a complete config.yaml
file up to this point, it’s in the mpf-examples/tutorial_step_14
folder with the name config.yaml
.
Note that this is a different folder than the previous steps. Since we now have subfolders in the machine folder, steps
14+ now each have their own folder in the mpf-examples
folder. So switch out of the mpf-examples/tutorial
folder and to the mpf-examples/tutorial_step_14
folder, then run mpf both
. (You don’t need the -c
option
since we’re back to using config.yaml
instead of a custom config file name.)
C:\mpf-examples\tutorial_step_14>mpf both