Skip to main content

SubTerrex - 0.1.2

Explore deep subterranean caves using only your trusty ropes and flares.

Paul Paterson

A cave exploration game where you explore caves by descending into them on ropes.

The caves are procedurally generated and completely dark to begin with. To explore you will need to place flares strategically to light your way. This early playable version includes the core gameplay.

Requires pymunk, scipy

You left click on the rock areas to fire a rope. Make sure you shoot it relatively close to your character and fire it into the body of the rock and not the edge.

Once you are on the rope you can then move up and down, left and right using WASD keys. You then descend into the cave firing additional ropes in the same way. Left click deploys a new rope and right click does the same but picks up the rope you already deployed.

You can let go of the rope using Q and if you are swinging near a second rope you can use E to switch between ropes. The key assignments are also shown in the HELP screen.

To add light you click on the flares at the top right.



This is a bug fix release for v0.1.1.

There was a bug on the start screen where the rope physics could go crazy and potentially crash the game.

Also included in this is the bug fix for v0.1. Version 0.1 had a horrible bug that would cause the spawning of lots of processes, eventually bringing your machine down. This is resolved in version 0.1.1.

The later bug did not affect Linux.


Home Page


SubTerrex 0.2 — 30 Jun, 2012

SubTerrex 0.1 — 20 Jun, 2012

SubTerrex 0.1.2 — 23 Jun, 2012

SubTerrex 0.1.1 — 23 Jun, 2012

SubTerrex 0.3 — 22 Jul, 2012

SubTerrex 0.3.1 — 2 Sep, 2012 account Comments

  • Ryan Fletcher 2012-07-01 14:37:02

    really good work mate, absolutely fantastic start :).

    Paul Paterson 2012-07-03 02:55:50

    Thanks - glad you liked it!

  • sipiatti 2012-07-10 08:01:17

    Fantastic and unbelievable you made it with pygame. Absolutely unique and well made

    Paul Paterson 2012-07-13 04:06:32


  • renesd 2012-07-23 17:26:00

    I really like the rope :)

    Paul Paterson 2012-07-24 00:04:04

    Thanks - it was a bit fiddly to get working but it turned out to behave quite realistically. Pymunk is pretty powerful!

  • Edward 2012-09-10 02:16:34

    really really nice game. Hope for more your games!

    Paul Paterson 2012-09-30 20:57:36

    Thanks - you can check out more at

  • Angello Maggio 2012-09-20 00:15:44

    This is really great! Very impressive, I really like the rope as well

    Paul Paterson 2012-09-30 20:57:59


  • martibttbtt 2012-09-27 00:48:46

    good job!:D

    Paul Paterson 2012-09-30 20:58:11


  • Oscar Carballal 2012-10-07 13:20:55

    THE greatest job with pygame I've seen so far, and I shall take a look to the code for a clone of Another World that I plan to do. I only have one objection, you developed it strictly for x86_64, making it impossible to run on x86 unless some stuff is modified :/

    Paul Paterson 2012-10-09 23:58:44

    Many thanks. Another World is one of my favourite games - I'll look forward to seeing that!

    I think that the 64-bit issue might be related to the pymunk installation on your system as I can't find anywhere in the game distribution that I am distributing the 64-bit binaries ... although I am developing on 64-bit so it could be something accidentally slipped in!

  • aNxello 2012-10-10 20:24:06

    So I've played the game and I love the concept. If you want some feedback I'd say that at least for me the physics were a little too sensitive, he would gain speed really fast, altho that made it a little bit harder by making you have to be precise which was still fun. Also maybe it's me but I had some problem with the rope, it seemed unresponsive at times. Is it only possible to cast the rope on certain places or it doesn't matter? Cause sometimes it would work and my guy would fall and sometimes die of course. But in general it's an amazing game I loved it!

    Paul Paterson 2012-10-11 03:39:45

    Thanks for the feedback - it is always great to get real play experience.

    I'll let you into a secret that the player walking sensitivity is really a bug! The walking is all driven by the physics engine but there is some kind of problem in how I'm implementing it. It is supposed to be a circular shape rolling on a surface with friction but sometimes the frictional drag will get really huge and the player slows to a crawl. To alleviate this I reduced the friction (and some damping I think) to as small as I could, which prevents the crawl but makes it twitchy at times.

    For the unresponsive rope do you mean you cannot fire (deploy) it or that it is deployed but doesn't move?

    Behind the scenes the physics model of the cave is a square grid. You can only attach the rope to rocks on the grid. Visually I overlay a fractal outline on the grid, which makes a nice cave shape. However, the fractal part of the rock is not in the physics model so you cannot attach the rope to that, you have to attach it to the body of the rock. Normally this is pretty close to the outline so you don't notice it. The trick is to fire a little deeper into the rock walls if you are having problems deploying the rope. This is really a bug, I should extrapolate into the "physical rock" in these circumstances but this isn't done in version 0.3.1.

    The other deployment problem can be that you are firing too far away. The rope has a limited length and I don't think there is any visual or audible cue that you are aiming too far. I should add this really.

    If you are finding the rope doesn't move or doesn't move properly then this also sounds like a bug. In previous versions I've seen that if the rope is partially(*) embedded inside the rock wall it can be constrained so much that it cannot move. This should never happen in 0.3.1 as, when firing the rope, the game does a calculation to locate the first bit of rock encountered by the rope such that it would always be completely outside of the wall. It's possible that this can fail and leave the rope partially embedded - although I've not seen that myself.

    (*) the rope is made up of a number of segments and it used to be possible to have the first few inside one of the rock "squares"

    Angello Maggio 2012-10-12 18:54:16

    Hi, this is me aNxello, I took your advice to click deeper and it totally works now, it definitely makes the game more pleasant to play! But I did have to click very deep into the rock (I mean not that deep but I good amount into the rock) and there's no problem with that, the game works perfectly. The thing about the rope not being long enough I assumed it, but maybe in the future you might want to add an animation for the rope trying to reach but not reaching (this wouldn't take ropes out of the count though.) And if you're interested in changing the fact that you have to click deep into the rock maybe you want to increase the radius of closeness that the rope has to be to the object in order to be attached? (I don't really know how the rope works, haven't looked into the code, but maybe that isn't possible) But the rope works great now that I know that little detail about clicking deeper. Also it is very interesting to know how the movement works, I was going to look into these libraries and that gives me a good idea of how the movement would work. Keep it up and I'm looking forward to future versions! (cool music too, I like it!)

    Paul Paterson 2012-10-14 17:37:57

    Thanks - I'm working on some of these suggestions to improve the way it works.

    If you are interested you can get a better idea of what is going on by turning off the fractal edges,

    > python -t cave-fractals={}

    You can then see the raw cave and see exactly how the rope attachment mechanism is working!

    Angello Maggio 2012-10-17 18:42:06

    that's very very cool! I see how it works now, very interesting. Oh, also I forgot to say that some of the levels generated (I think it generates the caves using the name given right?) don't have a path to win. For example cave "anxello2" is only 3 blocks deep and then there's nowhere to go.

    Paul Paterson 2012-10-18 02:28:47

    Yes, the name you give the cave is hashed and then used as a seed for the random number generator. This means that it always generates the same cave when you use the same name.

    Sometimes it does generate an insolvable cave. The algorithm is supposed to ensure connectivity by creating tunnels between chambers. However, I've seen that sometimes it generates a diagonal tunnel that is impassable and I've not managed to narrow down the circumstances. Since you gave me the name at least it gives me a repeatable case. Thanks!

  • Malcolm Boyd 2012-10-31 02:39:30

    This video inspired me to get back into my game development. Thank you!

  • Alvaro 2012-11-26 07:34:55

    Wow! Looks amazing.

  • DavidNovikov 2012-12-16 21:47:15

    Wow, im interested in how you did make the light effects O_o

    Paul Paterson 2012-12-18 06:56:35

    The lighting is generated from an underlying grid. The whole cave is a grid of square cells. Each cell is either occupied or not and an algorithm generates the cave structure. When you place a light in the cave, the game does a line-of-sight calculation from the light to the other squares with the light decaying as it moves away from the source. This give the light intensity and colour for each square in the grid.

    Then I take a black opaque surface (rgba 0,0,0,0) and overlay the lighting on top so that it becomes transparent with the right colour (using a blit with BLEND_RGBA_ADD) for each square. This works but is very "blocky" and unrealistic as a lighting overlay. You can see a simple example below (green image). So then I use numpy to do a gaussian blur on the overlay image, which smooths the light field out and makes it much more realistic.

    Now the next problem is that the gaussian blur needs to be quite broad (30px I think) for it to look good and that is quite an expensive calculation. You can see the second example below what happens if you don't use enough of a blur. The blurring is helping but it is still not right. Look at the red light and you can still see that it is made up of squares. I think that might be 5-10px of blur.

    I think 30px of blurring takes more than a second if I remember right and so the calculation is done on a separate thread (actually it is an out-of-process call using multiprocessing) to avoid a pause in the game. The calculation eventually returns the new lighting and it is added to the screen. You see this in the game when you drop a light it "flares" up and the "flickers" into life. This feels like it might be trying to model how a flare works but actually is just the delay in the calculation!

    If you look very closely then you will spot something else. Blurring the entire screen takes more than a couple of seconds and I found that this feels wrong. The light needs to appear quicker than that or it doesn't feel like it is related to the flare anymore. So there are in fact two calculations - a quick blur updating the light field around the new light you added. This takes <0.5 second. Then a full update, including blurring of the whole screen comes in a second or so later. Often you cannot see this but occasionally you can. You will see the new light has a hard edge where the light seems to stop. A second or so later it blurs out properly.

    You can see a few more images of how the overall algorithm developed over time here:

    The code is in,

    - game/ - calculateLight method for calculating the overall light field
    - game/ - doWork function for doing the blurring

    Once upon a time the code was reasonably easy to understand but as I had to keep optimising it and making it run in separate process it started to get quite intricate!

    DavidNovikov 2012-12-19 19:34:29

    A very complete answer, thank you very much!

    I'm making a game and, to make the lights, my idea was to add an white circular surface around and the object and, by detecting the collision points and the angle between the collision point of the "light" and the light source, it will create an black surface to simulate the shadow (the colour of the floor is black).

    Inspired in this game:

    But, i think that your method will work better. The problem is, as you said, the processing time. My game pretends to be an MMO and if its not fast enough, it will create lag. Not an real lag, its not caused by the connection, the problem will be the synchronization of the lights. An "fake lag".

    CreateProcessA 2013-03-26 00:41:01

    How about bilinear interpolation between the centres of the grid? This will give you a "gouraud" effect (you will still see some seams), but then you'll only need to filter with a smaller Gaussian afterwards (3-5 px). Also note that Gaussians are separable (filter in one direction, then the other).

    Paul Paterson 2013-03-31 18:34:26

    Nice idea - I think that will work. The Gaussian performance pretty good for a few pixels width. I'm playing with the idea of switching this to OpenGL right now. I think the graphics card can optimize this stuff much better than I can!

  • Jason 2012-12-16 21:51:51

    Awesome game! Here are some suggestions:

    1) When I'm on the rope, pressing UP (W) or DOWN (S) moves only one unit; I expected to slide up or down the rope.
    2) Walking and jumping is sensitive to the point of being funny. Maybe tone down the sensitivity a bit?

    Paul Paterson 2012-12-18 06:24:33

    Thanks - good idea about the up and down sliding. I'll give that a try.

    For the unresponsive walking - see my response to aNxello below. This is a physics bug that I wasn't able to solve yet. Somehow the friction between the player and the surface is inconsistent and it results in the weird behaviour you are seeing. It is funny - sometimes it feels like you are skating on ice and sometimes you are walking through treacle!

  • Eliot Leo Carney-Seim 2013-01-22 03:27:25

    Were there any additional libraries that you used to make this? It's very cool and I can't seem to get the same image quality like the kind you have in your game. I really hope I can make thing of your quality in the future!

    Paul Paterson 2013-01-24 00:44:29

    Well for the graphics I am using scipy to do a Gaussian blur on the lighting to smooth things out. See the answers below to David for some more details. The physics is all using pymunk but that doesn't affect the image quality, it is just used for modeling the rope and player and how they both interact with the walls of the cave.

    Other than those it is pygame.

    Which aspect of the image quality are you referring to? The only trick is using BLEND_RGB_ADD for the lighting effects. The underlying sprites are all just pygame surfaces. The cave and the trees are procedurally generated. You can play with the tree stuff if you go into the sandbox folder and run the "" file.

  • ;) 2013-01-22 11:53:33

    The sound of the rope firing sounds familiar...

    Paul Paterson 2013-01-24 00:27:36

    Yes, it seems that it is the same sound used by Minecraft. I used a sample from the and didn't realise it was the same one until there were some comments on the YouTube video!

  • Steven 2013-05-24 01:50:26

    I haven't yet installed this, but you might want to explicitly state that the MLK version of the NumPy package is required.

  • Abhimanyu Aryan 2016-03-05 03:48:48

    This was so cool. Wow

  • Abhimanyu Aryan 2016-03-05 03:49:28

    were do I download this for Mac?

  • Zain Khan 2020-05-11 00:44:26.207420

    I can convert this game to a .exe (Windows), .apk (Android) and .dmg (MacOS)