CaveX14 (GLSL Version)

For a computer science paper a few months back, we had to program in teams of two, a game on a small embedded board. It had two buttons, a 4-way hat and a 5x7 dot matrix display. It only knew how to talk in C. It also had to be multiplayer over an IR port.
My and a friend came up with CaveX14, where you are in a cave and are looking for the exit. (the exit was a flashing dot, you were in the center). As part of it, I came up with an algorithm for generating nice small-scale caves. using my own not-quite-cellular automata rules developed through trial, error, and only a little bit of science.

Now I haven’t finished a game in BGE for a long time. Probably since last BGMC, so I decided to bash out CaveX14 in BGE. In two versions. This one is the GLSL version. Made to look slightly more impressive than the embedded board one ever could!

So, weighing in at a total of 10 hours work over two days, 1mb of blendfile, we have CaveX15. A game with an infinite number of levels, and no real point.







Currently I’ve got the level size set to a 15x15 grid. If you want a challenge, set the size up to, say, 50 or so.
Have fun, and don’t get stuck in this game for too long…

Current Version:
CaveX14b.blend (1000 KB)

You could generate a whole city using the same system…

And you should :wink:

Wow, this looks absolutely amazing, and runs well to, nice job :D!

A few questions…

What does the FXplane do exactly?

How long did it take you to write the map.py?

And how hard would it be to convert this to first person perspective(just out of curiosity)?

FX plane adds that blue glow-mist-stuff. You probably don’t notice it, but the game was bland without it.

map.py? About 4 hours. I already knew the algorithm though. The map generation itself was maybe an hour. The other three were spent converting a cell based map into picking walls.

Into First person? Not long (3-4 hours). I was thinking of giving this a shot actually, but think there are some other changes I’d like to make first. (I was thinking doors and keys).
Maybe when I have a day or two free time.

First of all, I like the game, it reminds me of a game I had on my old sega mastersystem, which would boot up if you turned it on without a cartridge inserted.

It could also be a good base for expanding, like adding a timer, or roaming enemies or something.

Secondly:
If you’re going to write an algorithm like that again, I suggest approaching it as a binary arrangement.

So instead of having just the 4(5) tile types (we can include an empty tile as number 5) you create a full set of 16.
You can create them by just duplicating and rotating your original elements.

Like so:


Each tile should have as its center point, the bottom left hand corner. This is the origin tile, where the tile will be placed.

Now check that tile in your graph/array. If it is full the first corner is True. Else it is False. Return this as 0/1.
Next check the North tile, then the north East tile, then the East tile. For each one get a 1 or a zero. Stitch those returns together as a string, for example: 0100 You can see that one in the tiles above. If you’ve named the 16 tiles like that you only need to addObject the right tile at the right position.

To make things easier you can check using a search array rather than nested “if” statements.


own = cont.owner
scene = own.scene
   
tile_size = 2.0 #blender units

x_max = 15
y_max = 15   
   
array = [[[0] for y in range(y_max)] for x in range(x_max)]
  
### do some generation on your array first    
        
array = cellular_automata(array)

### then display the output

search_array = [[0,0],[0,1],[1,1],[1,0]]

for x in range(-1,x_max-1):
    for y in range(-1,y_max-1):
        
        tile_string = ""
        
        for neighbor in search_array:
            neighbor_x = x + neighbor[0]
            neighbor_y = y + neighbor[1]
                        
            ### a little cheat to deal with edge tiles
            ### you could write a function to wrap edges instead
            neighbor_x = max(0,min(x_max,neighbor_x))
            neighbor_x = max(0,min(x_max,neighbor_x))
            
            check_tile = array[neighbor_x][neighbor_y]
            
            tile_string += str(check_tile)
        
        tile = scene.addObject(tile_string,own,0)
        tile.worldPosition = [x* tile_size,y* tile_size,0.0]         

Then that’s all you need for placing your tileset.

Here’s an example blend with the cellular automata from roguebasin:
cave_tileset.blend (519 KB)

Actually I really like your cave generation algorithm, it doesn’t create lots of open spaces like cellular automata usually does. The end result is much more maze like.

That is fantastic smoking_mirror. I wish i’d thought of/known that while writing it. It woukd have made things far easier. I think I’ll change it over at some stage, if for no other reason than to make me ahppier with the code. While I was writing it I knrw there must be a better way.

I guess you dug into the code and already know what the algorithm is?
If you don’t:
It simply removes dividing walls. If there are two parallel areas unconnected for 3 blocks, it opes up an opening in the middle block

This means it leaves the natural ‘detail’ of the random noise alone, leaving the map interesting but also of a reasonable size.