15 KiB
Arcade Escape
An arcade-powered escape room framework built with Godot.
Arcade Escape brings seven classic arcade recreations together with room-design tools, configurable cabinet controls, scenario-driven hardware outputs, and a browser operator dashboard. Designers define the room and its scenarios; Raspberry Pi cabinets run the games; staff prepare and monitor sessions from a computer or tablet.
The Arcade Escape controller is separate from Odin and does not require its code or services.
Included games
The games include attract/title screens, sound, and game-specific visual treatments. They are playable recreations under active development; arcade accuracy and individual mechanics continue to be refined.
Start here
- Play or configure controls: Launcher and cabinet controls
- Deploy the room and operator: Controller deployment guide
- Connect real Pi outputs: GPIO setup and LED test
How it fits together
Godot development computer
Escape Room editor + game/cabinet/scenario resources
| |
| game export | exported catalog.json
v v
Raspberry Pi cabinets ------> Room controller on Mac mini / PC
games + saved controls Python + persistent SQLite state
| ^
v |
Local GPIO bridge Browser operator on Mac / PC / iPad
|
Physical outputs
| Component | Purpose | Runs on |
|---|---|---|
| Godot project and Escape Room editor | Build games, place cabinets, and author scenarios | Development computer |
| Arcade Launcher | Select games and configure physical controls | Desktop or Pi cabinet |
| Managed cabinet client | Load assigned games and report session events | Each Pi cabinet |
| Room controller | Validate assignments, track cabinet state, and queue commands | Mac mini, PC, or suitable server |
| Browser operator | View the room, prepare scenarios, and start/reset cabinets | Staff computer or iPad |
| GPIO bridge | Drive configured local Pi outputs | Each Pi that controls hardware |
1. Run the project locally
- Clone this repository and import project.godot into Godot.
- Use the project's configured Godot 4.7 version and Compatibility renderer. Allow the initial asset import to finish.
- Run the project with F5, or open ArcadeLauncher.tscn and use F6.
- Complete Control Setup if prompted, then select a game and press Start.
Godot's matching export templates are needed to create builds. Python 3 is needed for the room controller and GPIO bridge, but not for standalone desktop gameplay.
The launcher is the configured main scene. The project also has saved editor run arguments for a test scenario/cabinet; review Project Settings → Editor → Run → Main Run Args before testing another assignment.
Controls
- Joystick: navigate the launcher and move in games.
- Start: select an entry or begin play.
- Select: return to the launcher in standalone mode.
- F1: reopen Control Setup from the launcher.
- Escape: quit the application entirely.
Configure each machine independently. USB encoders can report different button numbers on Windows and Raspberry Pi OS. The setup wizard saves local mappings, including separate Robotron firing controls; a trackball should report as a mouse.
Mappings live in user://arcade_controls.cfg and survive replacing the game export. See the control guide for keyboard defaults, multiple-controller behavior, and reconnect handling.
2. Author a room and its scenarios
The Escape Room editor plugin is enabled in this project. Open its main-screen tab in Godot; if it is missing, check Project Settings → Plugins.
The existing resources provide a starting point:
| Resource | What to configure |
|---|---|
| Project database | Register cabinets, games, and scenarios |
| Room layout | Boundary, walls, cabinet placements, and room devices |
| Cabinet profiles | Unique cabinet IDs, available controls, and hardware configurations |
| Game definitions | Game scenes, control requirements, and exposed events |
| Scenarios | Cabinet/game assignments and event-to-hardware mappings |
A typical authoring workflow:
- Create or duplicate a cabinet profile and give it a unique
cabinet_id. - Describe its actual controls in
capabilities, and configure its hardware actions with the correct controller ID and BCM pins. - Register the cabinet in the project database and place it in the room layout.
- Create a scenario with one assignment per participating cabinet. Choose a compatible game and the
standardvariant. - Map game events to the cabinet's hardware action IDs. For example,
game_won→coin_release. - Register and save the scenario. Use the editor's simulation tools before deploying real outputs.
Designer-facing physical dimensions and positioning use feet; internal room geometry remains in meters.
Capabilities and input mappings are separate. Capabilities determine which games a cabinet can support; Control Setup determines which physical inputs activate their actions. The sample cabinet profiles describe limited controls, so update them to match your hardware before expecting every game to be available.
Export the operator catalog
From the project root, with your Godot executable available as godot:
godot --headless --path . --script tools/room_controller/export_catalog.gd
This generates catalog.json from the saved designer resources. The controller uses it for room positions, scenarios, and game compatibility. Regenerate it after authoring changes, restart the controller after copying it, and redeploy the game export when its packaged resources change.
3. Export and run a Pi cabinet
- Install matching Godot export templates on the development computer.
- Use the Linux export preset, configured for ARM64, for a 64-bit Raspberry Pi OS installation. The Windows Desktop preset is available for PC testing.
- Copy the executable and any accompanying export files to the Pi.
- Make the Linux executable runnable, then launch it normally to configure the controls:
chmod +x ArcadeEscape.arm64
./ArcadeEscape.arm64
Use your actual exported filename if different. The Pi runs the exported game; it does not need the Godot editor. The project has been tested on a Pi 4; verify the target hardware, display resolution, and controls for each installation.
For gameplay-only testing, no controller service or GPIO bridge is required. Real GPIO remains opt-in through --gpio=real.
4. Start the room controller and browser operator
Copy these three files together to the controller machine:
The controller uses Python's standard library; it has no pip dependencies. Generate distinct random tokens of at least 16 characters for the operator and each cabinet. Replace the placeholders below with those values.
macOS / Linux, from that controller folder:
export ARCADE_OPERATOR_TOKEN='your-generated-operator-token'
export ARCADE_CABINET_TOKENS='{"cabinet_01":"your-generated-cabinet-one-token","cabinet_02":"your-generated-cabinet-two-token"}'
python3 server.py --bind 0.0.0.0 --database arcade_room.sqlite3
Windows PowerShell, from the repository root:
$env:ARCADE_OPERATOR_TOKEN = 'your-generated-operator-token'
$env:ARCADE_CABINET_TOKENS = '{"cabinet_01":"your-generated-cabinet-one-token","cabinet_02":"your-generated-cabinet-two-token"}'
py -3 tools/room_controller/server.py --bind 0.0.0.0 --database arcade_room.sqlite3
Keep the database at a stable location and back it up. Allow TCP 8766 through the controller machine's firewall for the room LAN. Keep real tokens and deployment databases out of source control.
Open http://CONTROLLER_IP:8766/ on the staff computer or iPad and enter the operator token. The iPad needs only a browser. Use a trusted isolated LAN; the default HTTP connection is not encrypted. See the deployment guide for network and credential details.
5. Connect cabinets to the controller
On each cabinet, create arcade_network.cfg in the application's Godot user-data directory:
[network]
url="http://CONTROLLER_IP:8766"
cabinet_id="cabinet_01"
cabinet_token="your-generated-cabinet-one-token"
Use that cabinet's own ID and token. CFG strings use double quotes.
| Machine | Typical configuration directory |
|---|---|
| Raspberry Pi / Linux | ~/.local/share/godot/app_userdata/ArcadeEscape/ |
| Windows | %APPDATA%/Godot/app_userdata/ArcadeEscape/ |
This file goes in the user-data directory, not beside the executable. ARCADE_ROOM_URL and ARCADE_CABINET_TOKEN environment variables override their file values; --cabinet=... overrides the cabinet ID.
Start the managed client:
./ArcadeEscape.arm64 -- --managed-cabinet --cabinet=cabinet_01
This bypasses the game list and waits for the operator. It uses the controls previously saved through the launcher. Deploy the current export: the fleet controller requires protocol 2 (arcade-cabinet-2).
Enable physical GPIO outputs
Follow the GPIO guide to install Pi dependencies and verify the wiring with an LED first. GPIO action pins use BCM numbering, not physical header positions.
For the Cabinet 01 GPIO17 example, run the helper and game in separate terminals:
# Terminal 1: local GPIO helper
GPIOZERO_PIN_FACTORY=lgpio python3 pi_gpio_bridge.py --controller cabinet_01_gpio --pins 17
# Terminal 2: managed game with real outputs enabled
./ArcadeEscape.arm64 -- --managed-cabinet --cabinet=cabinet_01 --gpio=real
Copy the bridge script from tools/pi_gpio/ to the Pi. Match its controller ID and allowed pins to that cabinet's hardware resources.
| Port | Service | Address used |
|---|---|---|
| 8766 | Room controller and browser operator | Controller machine's LAN address |
| 8765 | GPIO bridge | 127.0.0.1 on the cabinet Pi |
Keep the room URL on 8766 even when the GPIO bridge reports 8765. An accepted GPIO command confirms the software call; without sensor feedback it does not confirm physical coin delivery.
6. Run a room session
- Confirm each required cabinet is ONLINE in the browser operator.
- Select a scenario and choose Prepare assigned cabinets.
- Wait for each cabinet to acknowledge READY, then start it remotely or with its physical Start button.
- Monitor game state, event history, and hardware command acknowledgements.
- Use Reset cabinet… to end its session before changing assignments.
Scenario preparation validates the complete assignment list before dispatch, including connectivity and game compatibility. Cabinets acknowledge independently. Manual game assignments intentionally run without inherited scenario rewards.
The sample proof_of_concept connects a Pac-Man win on Cabinet 01 to its coin_release action. The two_cabinet_test demonstrates separate cabinet assignments and event mappings.
The older -- --operator Godot mode remains available for Cabinet 01 quick controls. Use the browser interface for multiple cabinets and the room map.
Troubleshooting
| Symptom | Check |
|---|---|
| Controls differ between Windows and Pi | Run Control Setup on the Pi; do not copy Windows mappings blindly. |
| Room connection token is not configured | Check the user-data CFG location, double quotes, role-specific token, and environment overrides. |
| Unauthorized | The service is reachable; check the token and cabinet ID against the controller configuration. |
| Cabinet stays offline | Check the controller IP, port 8766, firewall, running client, and export protocol version. |
| A game is missing from the compatible list | Update the cabinet's capabilities, regenerate the catalog, and redeploy the cabinet resources. |
| GPIO command fails or LED stays off | Check real mode, local helper, controller ID, pin allowlist, and the wiring test in the GPIO guide. |
| Delivery is unconfirmed | Software acknowledgement is available, but physical feedback is not; inspect the output. |
Repository layout
addons/escape_room/ Godot editor plugin
core/ Game contracts, resources, runtime, controls, networking
editor/ Room-authoring workspace and simulation tools
data/ Saved games, cabinets, rooms, scenarios, and mappings
games/ Seven games, art/audio, launcher, and control setup
operator/ Godot operator scenes
main/ Room runtime entry scene
tools/room_controller/ Python controller, browser dashboard, catalog exporter
tools/pi_gpio/ Local Raspberry Pi GPIO bridge
tests/ Godot and Python verification scripts
Development checks
Run commands from the repository root, replacing godot with your executable as needed:
python3 -m unittest discover -s tests/room_network -v
python3 -m unittest discover -s tests/gpio -v
godot --headless --path . --script tests/room_network/check_capabilities.gd
godot --headless --path . --script tests/launcher/check_launcher.gd
godot --headless --path . --script tests/launcher/check_controls.gd
python3 tests/room_network/check_integration.py /path/to/godot
On Windows, py -3 can replace python3. The network integration test launches two headless Godot clients and temporary services on ports 8765/8766, forces test-only wins, and checks a fake GPIO output. Stop any real services using those ports before running it. These tests do not replace physical Pi, wiring, or iPad checks.
Current scope
The project supports standalone arcade play, room authoring and simulation, multiple managed cabinets, scenario assignments, a browser room map, and real GPIO outputs. External sensor inputs, detailed live puzzle-step diagrams, coordinated finale variants, and room timers/hints remain future work. Device locations on the map currently provide layout context rather than live physical sensor state.