A runner game on the MMA fighter Benoit Saint Denis
Level 1 - You're getting chased by Jon Jones, one of Benoit Saint Denis nemesis. You have to dodge the differents obstacles by jumping or sliding. There is also cages that falls from the ceiling
Level 2 - Same as level 1 but instead of sliding you can double jump. The speed is also increasing over time (from 420 to 900)
Level 3 - Geometry Dash like level, there is geometric obstacles and you have to dodge them or destroy them with your laser
- Gamepad support (Xbox, PlayStation) but only in gameplay (not in the menus)
- Discord Rich Presence
- You can change your keybindings in the options
- A CI/CD pipeline is present to build & release the game, you just have to change the version in
pyproject.toml
Download the latest release from GitHub Releases and extract MMA.zip
git clone https://github.com/spacevx/bsd-runner.git
cd bsd-runner
pip install -r requirements.txt
python main.pyRequirements: Python 3.11+
pygame-ce, Pillow, pytablericons, pypresence
# Run the game
python main.py
# Type checking
mypy .
# Build Windows executable
pyinstaller build.specNote: All those flags were used during our dev period to facilitate the work, they are not meant to be used by the player
--disableChaser- Run the game without the chaser enemy--unlockAllLevels- Unlock all levels
Usage: python main.py --disableChaser --unlockAllLevels (you can combine them)
To add a new flag, go to flags.py, add a new bool variable (prefixed with b), then add a parser.add_argument("--yourFlag", action="store_true") and assign it from parsed. Then you can use flags.bYourFlag anywhere in the code
- You can change your controls (only for keyboard players)
- You can also toggle the sound on/off
Levels 1 & 2: Do the combo JUMP, JUMP + SLIDE (hold both together), SLIDE and it will activate a random visual effect, the two existing ones are inverted colors and mirrored screen
Level 3: If you press SPACE more than 5 times in less than 10 seconds, the geometric obstacles will transform into Jeffrey Epstein
The game has a Discord Rich Presence, it changes depending on what you're doing in the game
| Menu | Playing | Game Over |
|---|---|---|
![]() |
![]() |
![]() |
mma/
main.py
game.py # Manages the differents screens
settings.py # Constants & differents vars
levels.py # Level config, you can config each level here
config.py # JSON config (settings, keybindings, progress)
discord.py # Discord Rich Presence
entities/
player.py # Our Player
chaser.py # The chaser, (only available in level 1)
animation.py # Class used to animated frames
tilemap.py # Ground/ceiling tilemap (ground is not really useful, only the ceiling one is really used for the cages)
obstacle/ # Obstacles logic, there is BaseObstacle and all Obstacle are child of BaseObstacle
input/ # Input manager, keybindings, joystick
screens/
menu.py # Start Menu
level_select.py # Level selector, to choose a level to play
options.py # Options
game/
screen.py # Render logic
hud.py # All the hud in game (score, life, keys)
collision.py # Collision logic
spawner.py # Logic for spawning obstacles (when, where, can we)?
ui/ # UI Lib, all our components are reusable
assets/ # All our assets
tools/ # Useful tools
The game can be played directly in the browser via GitHub Pages using pygbag. A new web build is deployed automatically on each release.
Differences with the desktop version:
- All levels are unlocked by default
- Discord Rich Presence is disabled
- Settings are not persisted between sessions
- Icons are simplified (no pytablericons in WASM)
To build locally: pygbag . then open http://localhost:8000
- mypy.yml: Type checking on every push/PR (just like a tsconfig.json)
- release.yml: Auto builds Windows executable and creates a release when the version in
pyproject.tomlchanges - pages.yml: Deploys the WASM web build to GitHub Pages on each release
- camelCase for variables,
bprefix for booleans (bGameOver,bDoubleJump) - Typed code, please run mpy . before pushing code to main
- All UI strings are located in
strings.py - The player is referenced as the
local playerso localPlayer = Player _prefix for private methods (_toggleFullscreen,_createBackButtonfor example)


