|  | 
 
 Introduction Hi all. First I would like to thank Krylar for helping me get started by hosting this great site and his tutorials were instrumental in getting me running with Blitz. My code for this tutorial is originally based on his tile code. The tileset included is written by Adam Bolt. It is an excellent fantasy tileset. It is usually distributed with Angband. I have created most of the terrain tiles myself, so in other words, don't blame the crappy terrain on him! I am relatively new to Blitz and this is my first tutorial, actually, it is also my first ever Blitz program, so go easy on me ;) I began working with random world generation because I have always wanted to remake one of my favorite games, Master of Magic. This is a turn based fantasy strategy game, built on the Civilization franchise. It is about 10 years old now, but one of the key features that still has me playing today is that the world is always randomly generated. So my first order of business was to complete this. I began searching extensively for any kind of help in any programming language on the web and basically came up empty. So here is what I came up with. I am happy with the results. A few notes. This does run at 1024X768. You can use the mouse or arrow keys to move. You can also go to a map location by left clicking on the minimap. Click here to download the code: Click Here The Code I have included three modules. One is Krylar's Key Constants, one is the main game loop and the last one is the game engine itself, which we will be looking at here. I am only going to discuss the world generation itself, if you have questions on the rest of the code, please feel free to email. It is somewhat commented (not my strong point!) First I call the InitializeMap function: 
 Pretty much self explanatory. The PlaceResources puts items like coal, iron, gold, etc. The PlaceNodes puts magic nodes on the map. The PlaceSpecials put monster lairs, dungeons, etc. The MapGen function is where the map actually gets created. Let's break it down. First: 
 This clears out any old data, nothing special. Next: Initialize Array 
 This initializes the whole map to 0, which is water. The important thing here is that it assigns an altitude and a water level. These are randomly assigned numbers between 0-.98. We will see how these are used in just a moment. Next: Seed Map 
 This randomly seeds the map with high points. You can play with the value of SeedVar. The higher the number, the more mountainous the terrain will be. Increasing the 4 in the For...Loop will cause more high points, which will create more islands or continents. The first two Repeat...Until just insure that we are not on the edge of the map. After randomly assigning the highpoint to one square, we also assign it to 4 adjacent squares to give us a larger seed for the continent. With only one value here, it would tend to get normalized out in the next step. Next: Normalize Terrain 
 Here we are normalizing the terrain. We run 5 passes over the entire map, getting the average value of both altitude and water level for all 8 of the surrounding squares and assigning it to the current square. This is done because all of these values are randomly assigned, and this will flatten the high points and cause "clumping" of like terrain. The number of passes can be changed to make the map higher or lower. Next: Assign Terrain 
 This long bit of code assigns all of the terrain types. The terrain types are actually constants, just integers behind the names. The terrain is assigned based on altitude and water level. If the altitude is low and the water content is low, it is a desert. If it is the same altitude with a higher water content, it is Grasslands. For hills and mountains, we do not worry about water content, just height. I haven't added rivers, but you could use high points with high water levels to assign the source of a river and use an algorithm to pull it down to the sea. I will be adding this later. Anything that doesn't fall into these categories also gets assigned to Grasslands. When all of this was complete, the map looked nice and was fairly realistic, but I wasn't happy with the look. This is when I decided to add a ShoreLine function. This made the map look TREMENDOUSLY better, much more professional. Just for fun, comment the ShoreLine function call out and look at the difference. This function was a pain to write, as I am sure you can see from all of the gigantic If...Then statements. I posted on the forums here and no one was able to give me a better suggestion for checking, if someone comes up with a better way, please let me know. I feel the end result was worth it, though. You will still find the odd anomaly here or there on the shoreline, but it is mostly correct. Here is the function broken down. 
 This first section loops through the map and sets bounds for the current tile so that only the adjacent tiles are checked. 
 Here we are actually checking the adjacent tiles. I have created a Hold$ that is 9 characters in length that is a binary representation of the surrounding tiles. It works like this: 1 2 3 Each number is the position in the string, with 9 being the tile itself. A "1" is used to represent any tile that is not water and a "0" is used to represent water. For example, "111000000" would be 3 land squares directly above the tile, the rest surrounded by water like so: 1 1 1 So this tile would get a downward facing shoreline. Conclusion Well, I think that's about it. This is a great foundation for either a real time or turn based strategy game. I welcome comments and suggestions.Why0Why 
 For a printable copy of this article, please click HERE. 
 This site is CopyrightŠ 2000-2004, BlitzCoder. All rights reserved.   |