# Marble Madness

A puzzle-like game where you are a marble.  Basic, but hopefully fun, and an example of
[pygame](https://pyga.me/).

The game was originally inspired by [Trackballs](https://trackballs.github.io/), a Linux game in
turn inspired by [an Atari Game](https://en.wikipedia.org/wiki/Marble_Madness), which happened to
also be called 'Marble Madness'.  I was almost certainly unaware of this, and came up with the name
independently.



## Setup and Running

Requires [Python](https://www.python.org/) (at least 3.11).

After Python, requires the [pygame](https://pyga.me/) and
[PyOpenGL](https://pyopengl.sourceforge.net/) packages.  [NumPy](https://numpy.org/) is optional,
but will greatly improve performance.  You can install all these like so:
```sh
python3 -m pip install --upgrade numpy pygame-ce PyOpenGL
```

To run the game, run ["main.py"](main.py):
```sh
python3 -OO main.py
```
(Note that that is `-OO`, not `-O0`.)

The main controls are the arrow keys (or WASD) to move.  There is also RETURN to select, P to pause,
CTRL-R to restart, CTRL-D to die, CTRL-F to toggle the framerate, CTRL-S to take a screenshot, and
ESCAPE to abort a run.  (There are more controls in debug mode; read the source.)



## Story

Let's face it.  You're a marble.  How did you get like this?  For reasons unknown, you have been
transformed to this state by the good King Gargrenought, who has recently decided to be evil.

Fortunately, the spell the King used backfired after hitting you, so he is now a marble as well—just
bigger.  Your goal is to seek revenge for this nefarious deed. However, you must battle your way
through the King's palace for the final showdown . . .



## Performance and Troubleshooting

The game is fairly complicated and not well tested, so bugs are possible, if not likely.  Older
configurations (the basic renderer, systems lacking NumPy, etc.) are not well-tested.  If the game
crashes, please send me the traceback and I'll fix it.  Especially for graphics-related bugs, it
would be helpful to know what GPU your computer has.

After the first run, the game writes "config.ini" into the main directory.  Editing this file is the
main way for the user to try to fix things themselves if it's not working.

The game starts with the advanced renderer enabled by default.  It requires only OpenGL 3.2, which
is near ubiquitous by now, but in the event of an older system or a problem with running it, you can
select the old renderer (set `render_advanced` to `false` in the INI file).  This requires only
OpenGL 2.1, and also has a much lighter load and less to go wrong.

The graphics are basic by today's standards.  Nevertheless, certain graphics adapters (e.g. old or
low-power integrated GPUs) struggle.  You can improve performance by adjusting the graphics options
(see the options in the menu, or you can directly edit the INI file).  Try a lower MSAA count,
shadowmap size, PCF level, and even screen resolution.  The game itself is fairly well-optimized,
and there's not much to be done to improve it.  A better computer is better, obviously.  However,
for reasonably modern systems the bottleneck is very strongly on the CPU side (Python is slowww).



## Level Format

Levels are stored in plaintext files.  Each file starts with a line which will be interpreted as the
title, and then a line with a floating-point number giving the time in seconds to complete the
level.

Then follows the level data.  Each character in the line can define something according to the
following:

Walls
'!' = laser wall
'%' = hedge wall
'#' = metal wall

Floor
' '                     = normal (grayish) tile
'r'/'o'/'y'/'g'/'b'/'p' = red/orange/yellow/green/blue/purple tile
'↑'                     = up arrow
'1'/'2'/'3'             = help text 1, 2, 3

"People"
'@' = self
'G' = Gargrenought
'h' = Gargrenought's Henchman

Objects on Normal Tiles
'L' = Life Up
'$' = Jewel / Gem
'*' = star
'T' = +60 seconds



## Contributions and Development

I consider the game a somewhat finished experiment.  It can obviously be improved, but this would
amount to serious game development.  I'm not really here for that, so I don't foresee doing further
large-scale development on this.

Bearing that in mind, if you'd like to contribute, it would probably best to propose changes first
before expending time writing them.  Smaller contributions and contributions that improve the code
quality are more welcome.  Follow the implied coding standard.

Additional recommended development tools are [PyInstaller](https://pyinstaller.org/en/stable/)
(making builds) and [SnakeViz](https://jiffyclub.github.io/snakeviz/) (see below):
```sh
python3 -m pip install --upgrade pyinstaller snakeviz
```

For profiling, you can use the builtin `cProfile` module:
```sh
python   -m cProfile -o marble_madness.prof   -OO   main.py
```
After the game exits, this will produce a profile dump "marble_madness.prof", which you can then
analyze (e.g. with the nice SnakeViz tool):
```sh
snakeviz marble_madness.prof
```

For builds, use pyinstaller.  The script automates this.



## License

Licensed under the MIT license.
