# 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 | | Game | Cabinet controls | | --- | --- | --- | | ![Pac-Man](games/launcher/icons/ico_pacman.png) | **Pac-Man** | Four-way joystick + Start | | ![Galaga](games/launcher/icons/ico_galaga.png) | **Galaga** | Horizontal movement + Fire + Start | | ![Tempest](games/launcher/icons/ico_tempest.png) | **Tempest** | Joystick, spinner, or trackball + Fire + Superzapper + Start | | ![Missile Command](games/launcher/icons/ico_missilecommand.png) | **Missile Command** | Trackball + three battery buttons + Start | | ![Frogger](games/launcher/icons/ico_frogger.png) | **Frogger** | Four-way joystick + Start | | ![Space Invaders](games/launcher/icons/ico_spaceinvaders.png) | **Space Invaders** | Horizontal movement + Fire + Start | | ![Robotron](games/launcher/icons/ico_robotron.png) | **Robotron 2084** | Two eight-way joysticks, or one joystick + four directional fire buttons, plus Start | 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 - **Start the services with one command:** [Windows and Pi launch scripts](tools/launch/README.md) - **Play or configure controls:** [Launcher and cabinet controls](games/launcher/README.md) - **Deploy the room and operator:** [Controller deployment guide](tools/room_controller/README.md) - **Connect real Pi outputs:** [GPIO setup and LED test](tools/pi_gpio/README.md) ## How it fits together ```text 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 1. Clone this repository and import **project.godot** into Godot. 2. Use the project's configured **Godot 4.7** version and **Compatibility** renderer. Allow the initial asset import to finish. 3. Run the project with **F5**, or open [ArcadeLauncher.tscn](games/launcher/ArcadeLauncher.tscn) and use **F6**. 4. 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](games/launcher/README.md) 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](data/project_database.tres) | Register cabinets, games, and scenarios | | [Room layout](data/rooms/arcade_room.tres) | Boundary, walls, cabinet placements, and room devices | | [Cabinet profiles](data/cabinets/) | Unique cabinet IDs, available controls, and hardware configurations | | [Game definitions](data/games/) | Game scenes, control requirements, and exposed events | | [Scenarios](data/scenarios/) | Cabinet/game assignments and event-to-hardware mappings | A typical authoring workflow: 1. Create or duplicate a cabinet profile and give it a unique `cabinet_id`. 2. Describe its actual controls in `capabilities`, and configure its hardware actions with the correct controller ID and BCM pins. 3. Register the cabinet in the project database and place it in the room layout. 4. Create a scenario with one assignment per participating cabinet. Choose a compatible game and the `standard` variant. 5. Map game events to the cabinet's hardware action IDs. For example, `game_won` → `coin_release`. 6. 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`: ```sh godot --headless --path . --script tools/room_controller/export_catalog.gd ``` This generates [catalog.json](tools/room_controller/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 1. Install matching Godot export templates on the development computer. 2. 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. 3. Copy the executable and any accompanying export files to the Pi. 4. Make the Linux executable runnable, then launch it normally to configure the controls: ```sh 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: - [server.py](tools/room_controller/server.py) - [operator.html](tools/room_controller/operator.html) - [catalog.json](tools/room_controller/catalog.json) 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: ```sh 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: ```powershell $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](tools/room_controller/README.md) 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: ```ini [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: ```sh ./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](tools/pi_gpio/README.md) 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: ```sh # Terminal 1: local GPIO helper GPIOZERO_PIN_FACTORY=lgpio python3 pi_gpio_bridge.py --controller cabinet_01_gpio --pins 17 ``` ```sh # 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/](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 1. Confirm each required cabinet is **ONLINE** in the browser operator. 2. Select a scenario and choose **Prepare assigned cabinets**. 3. Wait for each cabinet to acknowledge **READY**, then start it remotely or with its physical Start button. 4. Monitor game state, event history, and hardware command acknowledgements. 5. 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](data/scenarios/proof_of_concept.tres) connects a Pac-Man win on Cabinet 01 to its `coin_release` action. The [two_cabinet_test](data/scenarios/two_cabinet_test.tres) 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 ```text 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: ```sh 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.