Tuesday, March 08, 2005

Last night I did no work on the game at all. Infact I mostly sat in bed watching old Xfiles episodes I'd found in one of the cupboards. American and Canadian adverts are the worse adverts in the world. Really, they really suck. It makes you worry who they think the target audience is.

Anyway today I was thinking about world creation which is kind of around the corner. Basically content generation and all that good stuff. I've never worked with bitmaps or done any non-directX graphical stuff in C# but assumed it wouldn't be to hard. I was right! It's the easiest thing ever.

Drag a few bits and pieces over to the form and then add a little code.




Currently I'm going for the simplest world generation algorimth I could think of. The world is divided into a grid. At the start it's all sea. You begin by "seeding" the world. This means that a number of "seeds" are put at random grid positions. All a seed does is turn the grid point from blue for sea to brown for earth.


for(i <- 0 to maxSeedNo) { map[random, random].gridColour <- earthColour; }


Of course, the above psuedo code isn't anything like my code but I'm sure you get the idea. (For a start the random numbers should be some how bounded by the number of grid points in your map).

This is all I've done so far but it's only taken a few seconds. I didn't even have to look anything up I could just fiddle with VS.net GUI! Of course I choose the most garishly bright colours I could to dazzle the senses and woo the mind.

The next stage is to grow the seeds. The way I'm currently thinking of doing this is to iterate through the map. All seeded areas throw out another seed around their border. If it lands upon an already seeded grid point then nothing happens (I was thinking of it making that grid point grow higher but I want simple first). If it lands on the sea well then thats another seeded area and it turns to earth.

So what would that look like?
Well it would look like this:




Not too bad for a first go!

The main problems - maps are quiet found and pretty round.

Possibly solution during Growth iterations throw a few seeds into the sea.

The Code

Well let's have a look a some of the main algorimths in C# this time :D


private void Seed(Bitmap b, int seedNum)
{
for(int i = 0; i < seedNum; i++)
{
b.SetPixel(random.Next(100),
random.Next(100),
System.Drawing.Color.Brown);
}
}


So that's throws seedNum amount of seeds on to our map. In C# that argument to the random function is the maximum number it must under. So putting in 100 rather than 99 is fine.

The only other interesting function is grow. And as you might imagine this is called a growth number of times.


private void Grow(Bitmap b)
{
for(int i = 0; i < b.Width; i++)
for(int j = 0; j < b.Height; j++)
{
if(b.GetPixel(i,j).Name == "ffa52929")
{
try
{

int x = GetRandomOffset(i);
if(x > 99) x = 99;
if(x < 0) x = 0;

int y = GetRandomOffset(j);
if(y > 99) y = 99;
if(y < 0) y = 0;

b.SetPixel(x,
y,
Color.Brown);
}
catch(Exception e)
{
Console.WriteLine("Something odd" +
" has happened!");
}
}
}
}


Quiet a straight forward function the only two things of note are: b.GetPixel(i,j).Name == "ffa52929" which means "under the particular pixel encoding we are using is this colour brown?". The other thing is getting the border offset GetRandomOffset(i) - in which direction is the next seed going to be laid down?

I put this in a seperate function because random only returns non-negative numbers! I needed to change that and didn't want to do it in the middle of the code and mess things up.


public int GetRandomOffset(int i)
{
int r = random.Next(0,3);

switch(r)
{
case 0:
return i;
case 1:
return i - 1;
case 2:
return i + 1;
}
return i;
}


And they're all the main functions everything else is just prettiness to go around it. One last note is that if you set the growth to 1 and keep pressing the grow button then you can see the world forming before your eyes.

The only useability problem at the moment is that it blocks while its working. If it was coded using a timer or something then we could put up a progress bar maybe in the future. That's the most basic land generation function ever though, enjoy.

Easy to Port

To generalise this code and make it easier to port over to my main game code I'd probably use an interface. The functions will then use the interfaces methods and therefore be very spiffy and wouldn't need to be changed again. Basically it would probably be:


namespace MyGame.WorldGeneration
{

public enum LandTypes {Earth, Sea};

interface GeneratableTerrain
{
void SetState(LandTypes landtype);
}

}


That would probably do the trick quiet nicely, though I wish I could think of a better name from my interface there.

No comments: