Search Results

Friday, June 24, 2011

Random Level Design Implemented in BGE - Part 1

Hey. So here is a fairly large tutorial into random level design in the BGE, along with my Random Level Generator (RLG) python module. You can download it at the bottom of this post.

As you may or may not remember, I covered random level design as was utilized in the popular, good free indie game Spelunky, which has random levels implemented in the game.

Now, I'd like to split this into pieces to keep the two people reading this blog clamoring for more (LOL), but not overly so. The source code is available at the bottom of this page. Now, then - let's examine the level design theory really quickly.

So first, the idea is that we have a list that we store our level data in. We will look through these values, and use them to form our randomly-generated level. Inside of that list are several other lists - this will form the positions used to spawn our level piece data. Here's an example:

room = []
for y in range(ysize):
     room.append([])
     for x in range(xsize):
          room[y].append(0)

This will initialize an empty list, and then fill it up with other lists - inside of those lists are 0 values, according to the xsize and ysize variables. If you've tried other game engines or game development libraries, then you might be aware of what I'm doing here - each array inside our list represents a Y-axis value, and each index represents our X-axis value.

[
[0, 0, 0],
[0, 0, 1],
[0, 0, 0]
]

For example, in the list above, the value of 1 is at position 2, 1. By looping through our room list and then looping through those lists, we can see where we need to create our objects.

So, then. Now that we have our empty list, we can place random list data. Now, I originally thought that the best way to implement this would have been to loop through each cell in our room list like when I first initialized the room list, and by chance spawn 1's in those indices. However, this method isn't good because this method would basically bias room creation toward the beginning of the list. For example, if we only want to create 10 rooms in a room list with 20 possible indices, most of the rooms would be toward the beginning of the room list.

So, a better alternative would be to choose a random Y-axis list and a random X-axis index in the room list to set it to be occupied.


randomy = floor(random() * ysize)

randomx = floor(random() * xsize)
room[randomy][randomx] = 1 
As we can see, we choose a random X and Y position and set that position index to be 1. That's not too difficult, now is it? If we create a random room now, it will look something like this:
 
[[0, 0, 1, 0],
[1, 0, 1, 0], 
[0, 1, 1, 0],
[0, 0, 1, 0]]
  
How do we limit the creation of the rooms to a certain number? Well, a while loop inserted before we create the room indices will work well:

currentnum = 0
while (currentnum < maxsize):
     # Create room
     currentnum += 1

As you can see, every time we create a new room index, we increment a new variable, the currentnum variable. Should that variable exceed a maximum size (of our own determination earlier in the script), it breaks the loop, keeping the number of rooms created in the array under the maximum amount (actually, it creates that amount).

Beyond that, the next thing would most likely be obvious: How do we make an array of rooms that are connected? Well, that will be discussed in Part 2. 

You can download the source code, along with the RLG module in the BGE here. As always, have fun!

5 comments:

  1. Hi, thanks for the random level generating demo. It works really well.

    I have a couple of questions, though. Why did you save the Python files externally? are there any benefits for doing this? I just deleted the external Python files and saved them internally, and so far I'm running the demo without any errors or problems.

    Also, when are you going to do part 2? I'm really looking forward to it!

    ReplyDelete
  2. Well, Blender's text editor isn't very good for writing longer, more complex scripts. For example, by saving the script files externally, I can use Notepad++ to write them, and Notepad++ includes syntax highlighting and code folding, making it easier to write scripts.

    Also, by having the scripts be external like with the other modules I've written (X-Emitter, Sprites, BGHelper, etc), you can easily include them in your projects. All you have to do is place them where Blender expects them to be - on Windows, a default place is in the Blender folder itself. Then, you can simply import them in all of the projects that use the modules. It's pretty easy.

    Finally, by having the files be external, they are compiled, making them execute faster than normal, internal scripts, though speed isn't really an issue here.

    ReplyDelete
  3. Ah, I see now. For non-programmers like me it is more convenient to store everything inside one package, but I understand why it would be better for programmers such as yourself to store them externally.

    Also, I did not know that scripts execute faster when stored externally. Thanks for the tip!

    ReplyDelete
  4. Somebody is a Persona fan... ;)

    ReplyDelete
  5. thanks a lot solarlune for these tutorials,without them i would have been stuck in a muck long ago. now when is part 2 comin' up ?

    ReplyDelete