Map Generator

A map generator based on Amit Patel’s Polygonal Map Generation blog post. There are 4 different versions ; 2D / 3D WPF , 2D / 3D XNA ( main project ).

Using Voronoi diagrams to create the main structure and Lloyd’s algorithm for relaxation.  There is a Catmull-Clark subdivision implementation in 3D XNA version to smooth the polygons and a linear interpolation implementation in 2D WPF to smooth the coastline.

 

Blog posts about this project;

Part 1 – Introduction

Part 2 – Creating the Island

Part 2.5 – Smoothing the Coastline

Part 3 – Elevation

Part 4 – Rivers

Part 5 – Moisture

 

GALLERY

[usercontrol: /blog/user controls/gallery.ascx ImageUrl=/blog/gallery/mapgenerator;RepeatColumns=5]

Yet Another A* Implementation

So I’ve been working on a dungeon generator for a while now. Tried a few different approaches already like bsp tree and stuff but I’ still haven’t decide which one to use. The current one I’m using though is a little interesting , it’s a corridor first approach , using A* path finding algorithm to create corridors between random start and end points.

I remember implementing A* in a project , it was like 2 or 3 years ago I guess. It was a decent implementation and worked as it should but this time , I wanted something better and something elegant so I start looking for A* articles before jumping into code and found an A* article by Eric Lipper himself!

It was quite surprising as I follow Eric Lippert’s Fabulous Adventures in Coding closely for a long time now and haven’t seen this one before. For those who don’t know Eric Lippert , he’s a principal developer on the Microsoft Visual C# compiler team and a very good & active blogger.

After reading his Path Finding Using A* in C# 3.0 series ( 4 parts ) , I knew I had to implement it. It works perfectly , looks so elegant and extremely easy to manage ( like switching heuristic function etc) .

I won’t go into the A* details here , I’ll only talk about my implementation of Eric Lippert’s sample. I said “my implementation” as I had to change some stuff in order to make a stand-alone example/solution without any big dependencies ( like a grid structure to work on etc ) so if you want the original.

 

First of all , let’s take a look at some helper classes Eric Lippert used. There are 2 classes the used and first one is Path<T> ;

public class Path<T> : IEnumerable<T>
{
    public T LastStep { get; private set; }
    public Path<T> PreviousSteps { get; private set; }
    public double TotalCost { get; private set; }

    private Path(T lastStep, Path<T> previousSteps, double totalCost)
    {
        LastStep = lastStep;
        PreviousSteps = previousSteps;
        TotalCost = totalCost;
    }

    public Path(T start) : this(start, null, 0) { }

    public Path<T> AddStep(T step, double stepCost)
    {
        return new Path<T>(step, this, TotalCost + stepCost);
    }

    public IEnumerator<T> GetEnumerator()
    {
        for (Path<T> p = this; p != null; p = p.PreviousSteps)
            yield return p.LastStep;
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

This path class , using generic type , is the actual path or corridor we are trying to create. It has 3 properties , LastStep ( or tail ) is the last point of the path ( ending ) , PreviousSteps is yet another Path containing all previous points and the TotalCost which calculates total movement cost from start to finish. Think of this Path class as  one simple node packaged with the other nodes before himself ( we’ll use it this was later on in the actual A* implementation )

Second one is a Priority Queue. Priority queue is a structure very similar to queue , just one obvious difference , items hold in queue are ordered by their priorities. Remember in A* we always have a pool of possible next points and select the “best” one from that pool in each step? This queue is that pool and the priorities we’ll set are the values ( cost + heuristic ) of those points.

And this is the PriorityQueue implementation ; ( I directly copy&pasted from Eric Lippert’s blog , even the comments are his very own comments. )

class PriorityQueue<TP, TV>
{
    private SortedDictionary<TP, Queue<TV>> list = new SortedDictionary<TP, Queue<TV>>();

    public void Enqueue(TP priority, TV value)
    {
        Queue<TV> q;
        if (!list.TryGetValue(priority, out q))
        {
            q = new Queue<TV>();
            list.Add(priority, q);
        }
        q.Enqueue(value);
    }

    public TV Dequeue()
    {
        // will throw if there isn’t any first element!
        var pair = list.First();
        var v = pair.Value.Dequeue();
        if (pair.Value.Count == 0) // nothing left of the top priority.
            list.Remove(pair.Key);
        return v;
    }

    public bool IsEmpty
    {
        get { return !list.Any(); }
    }
}

And we need one last helper class before we move into the actual A* , a grid for our calculations. Obviously you don’t need a grid for A* , it can be any sort of structure with randomly connected nodes but of course grid is the simplest. This is my implementation to make it a stand alone project.

public class Block : IHasNeighbours<Block>
{
    public static float BigBlockSize = 1;
    public Vector3 Point { get; set; }

    public Block(Vector3 point)
    {
        Point = point;
    }

    public IEnumerable<Block> Neighbours
    {
        get
        {
            return new Block[]
                       {
                           new Block(new Vector3(Point.X + BigBlockSize, Point.Z)),
                           new Block(new Vector3(Point.X BigBlockSize, Point.Z)),
                           new Block(new Vector3(Point.X, Point.Z + BigBlockSize)),
                           new Block(new Vector3(Point.X, Point.Z BigBlockSize)),
                       };
        }
    }
}

If you can get over the incredibly uncreative name , there are few things to explain here.

First of all , what is BigBlockSize? It’s pretty much the base cost of moving from one node to another. Check this out ,

 

yesitsasudokuimage

Notice you may have grid with much smaller squares but if you set BlockSize as anything bigger than 1 , your path will follow every n’th square to calculate the path. I needed this as I’m using this to create corridors , remember?

Then we got a Vector3 Point , I just created a small Vector3 class to wrap X and Z coordinates ( I’m working on XNA these days and Y is UP in DirectX ) of the points.

Oh we also got a simple interface , IHasNeighbours , it’s a very simple interface that contains Neighbors and Point.

public interface IHasNeighbours<N>
{
    IEnumerable<N> Neighbours { get; }
    Vector3 Point { get; }
}

And last but not least , we have a Neighbors property that returns 4 other Blocks around current one. Obviously returning 4 new objects for every node is overkill but I decided to do it this way as your project will have your own grid structure anyway so you won’t need this part.

 

OK I guess we’re done with helper classes so now the real deal , actual implementation of A* !

I highly suggest you to read at least the first part of the Eric Lippert’s A* series , he explains it very well. Here is the method ;

public static Path<T> FindPath<T>(
    T start,
    T destination,
    Func<T, T, double> distance,
    Func<T, T, double> estimate)
    where T : IHasNeighbours<T>
{
    var closed = new Dictionary<int, T>();
    var queue = new PriorityQueue<double, Path<T>>();
    queue.Enqueue(0, new Path<T>(start));
    while (!queue.IsEmpty)
    {
        var path = queue.Dequeue();

        if (closed.ContainsKey(path.LastStep.Point.GetHashCode()))
            continue;

        if (path.LastStep.Point.X == destination.Point.X && path.LastStep.Point.Z == destination.Point.Z)
            return path;

        closed.Add(path.LastStep.Point.GetHashCode(), path.LastStep);
        foreach (T n in path.LastStep.Neighbours)
        {
            double d = distance(path.LastStep, n);
            var newPath = path.AddStep(n, d);
            queue.Enqueue(newPath.TotalCost + estimate(n, destination), newPath);
        }
    }
    return null;
}

This is a method that takes start and end points , a distance function , an estimate function and returns a path.

We have a dictionary “closed” for visited blocks ( Eric Lippert used Hashset in original implementation but I prefer Dictionary for node based systems as I’ll eventually need to find stuff by key. It’s just a personal preference , you’re perfectly fine with Hashset in this example too of course. ) and a priority queue.

And this is pretty much how it goes , we start by adding start point to the queue and then start a while loop.

In this loop ,

    we dequeue and get the “best” block in the pool

    if that block is already in the closed dictionary , we move on to the next best block

    if that block is the destination point , we return the path ( result )

and if both statements above are false , we move on to adding this new block to the path ;

    we add this new block to the closed dictionary

    and add all it’s neighbors to the queue to process later

And that’s all. Now it’ll eventually reach the destination node and return the path back. Be careful with one thing though , if you change the BlockSize value , your destination coordinates must be on this new Grid using new BlockSize. In other words , destination X & Z must be divisible  by BlockSize or it won’t be able to get to the destination point. Of course you can also add a check for that , like if current node is closer than any other nodes etc but that’s all up to you.

 

Oh and one last thing , distance and estimate functions. As I said before I used Manhattan distance for those, it’s pretty much like the simplest estimate function ever. If you will use A* to actually calculate paths for game characters or something , you’ll probably need something more complex with tie breakers etc etc.

public static double Distance(Block start, Block end)
{
    return Math.Abs(start.Point.X end.Point.X) + Math.Abs(start.Point.Z end.Point.Z);
}

public static double Heuristic(Block start, Block end)
{
    return Math.Abs(start.Point.X end.Point.X) + Math.Abs(start.Point.Z end.Point.Z);
}

That pretty much sums it up. I highly suggest reading Eric Lippert’s A* posts and his blog in general too ( his blog is just simply awesome and probably the best C# blog out there ). But if you really want to go deep in the path finding theory and how things works , then you MUST read Amit Patel’s incredible work on the topic . As far as I know it’s the best source you can find to learn how path finding works. Theory , examples , explanations , everything is there!

 

Oh and in case you’re curious about my corridors , here they are!

DungeonTest (14)

I also connect multiple corridors to create a network as you can see , it’s all based upon the codes above.

 

You can find the sample below , it doesn’t include the visuals ( in picture above ) of course. It’s just a simple console application that calculates the path , but you can see all those code in work.

Hope you like it or at least find it useful! Goodbye until the next post!

 

Visual Studio 2010 Solution

Simple Map Generator Part 5 ( Moisture)

Hey hey!

So we’ve created rivers in last part right? Now that we have elevation and river , now we can calculate moisture which we’ll use for biomes later. I guess this will be a short post , since calculating moisture is pretty much same as calculating elevations. Pretty similar iterations , almost same.

The main idea here is to set river moisture a static value and then iterate through all corners and decrease this value as the corner gets further away from the river. Then we’ll also set center ( polygon ) moisture as the average of it’s corners’ moisture , easy peasy.

 

OK so I’ll start with our first method , CalculateCornerMoisture() }

 private void CalculateCornerMoisture()
{
var queue = new Queue<Corner>();

foreach (var q in App.AppMap.Corners.Values)
{
if ((q.Water || q.River > 0) && !q.Ocean)
{
q.Moisture = q.River > 0 ? Math.Min(3.0, (0.2 * q.River)) : 1.0;
queue.Enqueue(q);
}
else
{
q.Moisture = 0.0;
}
}

while (queue.Count > 0)
{
var q = queue.Dequeue();

foreach (var r in q.Adjacents)
{
var newMoisture = q.Moisture * 0.9;
if (newMoisture > r.Moisture)
{
r.Moisture = newMoisture;
queue.Enqueue(r);
}
}
}

foreach (var q in App.AppMap.Corners.Values)
{
if (q.Ocean || q.Coast)
{
q.Moisture = 1.0;
}
}
}

As you can see we got 3 simple loops here. I won’t go into the detail as they are pretty much self explanatory.

First we iterate through all corners , set rivers moisture to 0.2 * river size ( maximum 3.0 ) and then add those river corners to the queue.

Then we start processing stuff in the queue , for each corner in the queue , we find it’s adjacent and set moisture to the 0.9 of original value. So with each step , moisture is decreased by 0.1 of the closest river moisture.

Then at last we set ocean and coast moisture to a standard value , 1.0.

I’m using a little different method in my personal project , merging 1st and 3rd loop together.

foreach (Corner q in App.AppMap.Corners.Values.Where(q => (q.Water || q.River > 0) && !q.Ocean))
{
q.Moisture = q.Water
? 1
: ( q.River > 0
? Math.Max(3.0, (0.2 * q.River))
: 0.1 );
queue.Enqueue(q);
}

It does pretty much the same thing , just in one loop and I don’t think setting ocean moistures before effects much or anything at all.

 

Anyway , once we set corner moisture…. actually we’re almost done.

Amit prefers to redistribute moistures as well ( remember we did the same thing for elevation before ) I personally prefer not to do this but here it is ;

private void RedistributeMoisture()
{
var locations = App.AppMap.Corners.Values.OrderBy(x => x.Moisture).ToArray();

for (int i = 0; i < locations.Count(); i++)
{
locations[i].Moisture = (float) i/(locations.Count() 1);
}
}

I added this to the sample solution below but it creates a very low moisture / desert-ish island for me at the moment , so it’ll be commented out. But remember all this stuff is just about some static variables. I know it’s a very bad practice but you’ll see magic numbers around , like 3.0 being the maximum river moisture , in that method above. All you have to do play with such numbers until you got an island you like.

 

One last thing before we finish , setting center ( polygon ) moistures. As I said before we’ll just take the average of corners and use it as center moisture , so it’s simple as this ,

foreach (Center c in App.AppMap.Centers.Values)
{
c.Moisture = c.Corners.Sum(x => x.Moisture) / c.Corners.Count();
}

 

Aaand we’re done! Now when you run it , it should look something like this ,

WindowClipping (7)

 

Not bad eh? Well actually we’re pretty much done now , at least code-wise. There is only biome selection left and that’s not really a technical issue , also it’s in the sample solution since the Part 2 , as we needed to visualize it somehow. Still I may post about it in the future , or maybe some other stuff like the methods I used etc.

 

I really hope you liked it or at least found useful. I’m still working on this occasionally so I’ll probably post about it in the future again , maybe even about the XNA version of it.

 

You can find the sample solution file below , please don’t hesitate to contact me for any questions!

 

 

Visual Studio 2010 Solution

Simple Map Generator Part 4 ( Rivers )

So now that we’ve calculated elevations and somewhat created the Y axis on our map , we can now create some rivers! Rivers will turn or boring looking island into a much better , interesting environment. We’ll also use rivers and watersheds to calculate moisture and biome later on so we definitely need them.

 We’ll use a simple method to generate them , we’ll get a few random points on the map and then create the river down to the ocean or a lake using the elevation datas. The number of rivers and the starting points will all be random for now.

 

First of all , we’ll iterate through all corners and create a “Downslope” property for them. Downslope will be the adjacent corner with the lowest elevation or in other words , the way which water will run.

Then we’ll do pretty much same for the calculation of watersheds. Iterate through all corners and set the Watershed of the Downslope corner as the current corners Watershed until it reaches water.

Then we’ll actually create the rivers , take a random corner between statically set elevations ( like 0.3 and 0.9 , since we don’t want rivers starting at the beach or at the top of the mountain ) , follow downslopes till water and calculate river width depending on the watersheds we calculated earlier.

 

Huh I don’t even know why did I bother to explain it like this , it should be much more easy to explain with code!

 

So here we go , our first method , CalculateDownslopes!

private void CalculateDownslopes()
{
    foreach (Corner corner in App.AppMap.Corners.Values)
    {
        var buf = corner;
     
        foreach (var adj in corner.Adjacents)
        {
            if (adj.Elevation <= buf.Elevation)
            {
                buf = adj;
            }
        }

        corner.Downslope = buf;
    }
}

Just iterate through corners and set the adjacent with lowest elevation as Downslope. I don’t know if there are anything else to say really , so I’ll just move on to the next method , CalculateWatersheds ,

private void CalculateWatersheds()
{
   
    foreach (var q in App.AppMap.Corners.Values)
    {
        q.Watershed = q;
       
        if (!q.Ocean && !q.Coast)
        {
            q.Watershed = q.Downslope;
        }
    }
   
    for (int i = 0; i < 100; i++)
    {
        var changed = false;

        foreach (var q in App.AppMap.Corners.Values)
        {
            if (!q.Ocean && !q.Coast && !q.Watershed.Coast)
            {
                var r = q.Downslope.Watershed;
               
                if (!r.Ocean)
                    q.Watershed = r;
               
                changed = true;
            }
        }

        if (!changed)
            break;
    }

    foreach (var q in App.AppMap.Corners.Values)
    {
        var r = q.Watershed;
        r.WatershedSize = 1 + r.WatershedSize;
    }

}

This looks a bit more complex , but it’s just 3 simple iterations really.

First we set the downslope of each corner also as watershed. This will be the first step towards water.

Second iteration is a bit weird and I’m not really sure about the implementation,  yet I’ll just keep it as it is in the original code written by Amit. What it does , is to follow downslopes until it reaches coast or any water source. When it’s done for all corners , it’ll create a structure like a tree , for watersheds.

What I wasn’t sure about is if we really need to iterate through all corners many times like that instead of a depth first like iteration. That “for” iterator from 0 to 100 will break very early so we don’t go all the way up 100 of course but even 5 iterations means Corner count * 5 steps after all. Anyway , as I said I’ll just stick with the original code here.

And in the 3rd iteration , we’ll just increase the watershed size. Remember more than one corners may have same corner as watershed so this will increase the watershed size of that central corner.

 

And last but not least , the CalculateRiver method ,

private void CreateRivers()
{
    var rnd = new Random();

    for (int i = 0; i < MapX / 2; i++)
    {
        Corner q = App.AppMap.Corners.Values.ElementAt(rnd.Next(0, App.AppMap.Corners.Values.Count 1));
       
        if (q.Ocean || q.Elevation < 0.3 || q.Elevation > 0.9) continue;
       
        while (!q.Coast)
        {
            if (q == q.Downslope)
            {
                break;
            }

            Edge edge = q.Protrudes.FirstOrDefault(ed => ed.VoronoiStart == q.Downslope || ed.VoronoiEnd == q.Downslope);
            edge.River = edge.River + 1;
            q.River = q.River + 1;
            q.Downslope.River = q.Downslope.River + 1;
            q = q.Downslope;
        }
    }
}

We first start with getting a Random but I highly suggest using a centralized Random generator instead of creating a new one , so you can feed any number to that centralized Random as seed and recreate any island you want just by a number.

Then we’ll grab some random point , for some reason Amit preferred to do this in a “for” iterator , I’m not a fan of that personally. Too random for my liking I guess.

Then when we get these corners , we’ll use them as starting points for rivers and follow downslopes until we reach water. And with each step , we’ll increase the River value of the edges and corners. This will give us a nice effect , rivers joining together and getting bigger.

 

Hmm guess that’s all. after all these 3 methods , you’ll have something like this ,

WindowClipping (6)

 

Much better , isn’t it?

Next , calculating moistures I believe. I’ll try to write that as soon as possible too.

You can find the sample solution file below , hope you like it!.

 

Visual Studio 2010 Solution

Simple Map Generator Part 3 ( Elevation )

Hey again!

If you read the previous part ( Part 2.5 ) you probably already know I decided to just convert Amit’s code from now on and keep my personal additions at minimum. Hopefully I’ll also be able to post more frequently , just because of this too.

But again let me remind you this , since we’re working on a totally different framework and somewhat different structure , it won’t be exact same as Amit’s original code. There are still some differences  like order of calculations or WPF related extra code here and there but the algorithms and stuff will be almost same.

Also if you remember Part 2.5 was totally optional , even not recommended so we’ll keep working on Part 2 now.

 

This is what we had at the end of Part 2 and now , in this post, we’ll talk about and implement elevation calculation.

 

It seems like Amit decided to do this in two little parts , first calculating the corner elevations then redistributing the elevation and scaling all numbers down to 0 – 1.0 range.

 

To do this , we’ll first find the corners at the edge of the map and set their elevation to zero and every other corners elevation to a very high value ( double.MaxValue ). this will create a huge , long block and then we’ll carve our island from it.

 var queue = new Queue<Corner>();

 foreach (var q in App.AppMap.Corners.Values)
{
 if (q.Border)
{
q.Elevation = 0.0;
queue.Enqueue(q);
}
 else
{
q.Elevation = double.MaxValue;
}
}

 

This part is pretty self explanatory I guess. If it’s a border , we set elevation to 0 and Enqueue that corner to use later. If not , just set elevation to double.MaxValue.

You may have noticed that since we’re using Queue , we’ll calculate elevations as if we’re flood filling a space. Now that we have some corners to start with , we’ll take one , process it , add it’s adjacent to queue , and dequeue the current one.

I guess it’ll be easier to explain with code ,

 while (queue.Count > 0)
{
 var corner = queue.Dequeue();

 foreach (var adj in corner.Adjacents)
{
 double newElevation = 0.01 + corner.Elevation;
 
 if (!corner.Water && !adj.Water)
{
newElevation += 1;
}
 
 if (newElevation < adj.Elevation)
{
adj.Elevation = newElevation;
queue.Enqueue(adj);
}
}
}

So we take corners one by one , find it’s adjacent , if that adjacent is not water , we increase the current corners elevation by a tiny bit and set it as the adjacent corner’s elevation.

This , like a flood fill , go find every corner on the map and set it’s elevation based on the lowest corner around it. Oh and if we change the elevation of a corner , we add that corner to queue again because it’ll also effect it’s adjacent and we must repeat this process for them too.

 

This method should get you something like this now ,

WindowClipping (4)

Notice the elevation at the left side bar , it’s above 10.96. But we want elevation numbers between 0 and 1.0 , also a little bit more control over the general elevation distribution on our island. So we’ll use this numbers as a base value and redistribute elevations from scratch.

double scaleFactor = 1.1;
var locations = App.AppMap.Corners.Values.Where(x => !x.Ocean).OrderBy(x => x.Elevation).ToArray();

for (int i = 0; i < locations.Count(); i++)
{
double y = (double)i / (locations.Count() 1);

var x = 1.05 Math.Sqrt(scaleFactor * (1 y));
if (x > 1.0)
x = 1.0
locations[i].Elevation = x;
}

 

OK this part is a little bit more complex so I’ll go slowly.

First of all let me explain the Amit’s plan here a bit. It seems he wanted to distribute elevations in a way that elevation frequency will be directly related to the elevation itself. In example , only the 0.1 of the corners will have 0.9 elevation and 0.2 of them will have 0.8 elevation and so on. Admittedly I’m not a fan of this , but here we go,

We’ll start off by setting a scaleFactor. Scale Factor is pretty much maximum elevation on the island. We’ll use it for calculations but later clamp the elevation between 0 – 1.0 anyway.  This will create a bit more mountain tops at max elevation on our map , so it won’t look like just one sharp spearhead.

Then we select the corners we want to recalculate. Obviously oceans will have 0 elevation but since lakes at the top of mountains should be calculated properly , we’ll select them too. So we’ll get every non-ocean corner and order them by their elevations.

To explain the distribution calculation , I’ll just quote Amit’s own comment from the code ,

Let y(x) be the total area that we want at elevation <= x. We want the higher elevations to occur less than lower  ones, and set the area to be y(x) = 1 – (1-x)^2.

y = I / ( locations.length – 1 );

Now we have to solve for x, given the known y.

y = 1 – (1-x)^2
y = 1 – (1 – 2x + x^2)
y = 2x – x^2
x^2 – 2x + y = 0

From this we can use the quadratic equation to get:

x = Math.sqrt(SCALE_FACTOR) – Math.sqrt(SCALE_FACTOR*(1-y));

 

I guess this is better than trying to explain it with my broken math/english eh?

The 1.05 you can see in the code is just the square root of 1.1 , I doubt we need it but anyway. Rest should be pretty much same as he explained. I honestly not sure if it worths the trouble tho , because square root is a costly calculation and simply dividing all corner elevations to the biggest one pretty much gets you a similar map anyway.

 

And after this 2nd method , you’ll end up with something like this ;

WindowClipping (5)

 

The gray part in the middle are areas with elevation above 0.8 and pinkish areas you can see right about beaches are areas with elevation below 0.3 I believe. All style files are in that solution anyway so you can already play with numbers to color them as you please.

 

You can find the sample solution file below , please don’t hesitate to ask anything you like. Next post , I believe , will be about calculation the moisture!

 

Visual Studio 2010 Solution

Simple Map Generator Part 2.5 ( Smoothing )

I’m aware this series are coming along pretty slow , apologies for that. One of the main reasons for that , is I’m working on a few different version of this project at the same time. You see this series are based on WPF but actually I switched to XNA some time ago , and it is the main branch for me at the moment. But since WPF and XNA is so different , I just can’t switch to XNA for blogging like that.

That’s pretty much why I decided to make this WPF version , the exact same as Amit’s original work. I will not go into my own implementations of various stuff like elevation distribution , I’ll just convert Amit’s code. I’m doing things my own way in XNA anyway ( and probably I’ll talk about that in future too ).

But before that , there is one last personal thing I want to talk about in this WPF series , so I’ll call this Part 2.5. It’s totally optional and actually I even suggest not use this one in your project but still something cool and good to know.

Remember the island we got at the end of last post? It was looking pretty decent right? Well but in my XNA work , I came to a point where I had to do something about those strong and sharp coast line.

 

WindowClipping (56)

 

So I decided to try smoothing that coast line and see how it looks. After reading a bit about spline smoothing techniques , I decided to use Catmull-Rom interpolation!

 

Catmull-Rom Interpolation

OK so let’s talk a bit about Catmull-Rom , what it is and how to implement it.

It’s an interpolation technique that requires 2 main points ( the ones you want to smooth ) and 2 other for calculating the curve. And of course something like a ratio of the new 3rd point ( between those main 2 ). Bah it’s hard to describe really so check this out;

spline1

So the idea is , creating a new point between P1 and P2 which will make the line smoother. But what if I don’t want to add new points to my map? That would create lots of new problem , just for a simple smoothing test , right? So what about this ,

 

int

 

Well excuse my photoshop skills and let me explain this. Instead of creating a new point which will cause lots of new troubles like creating and processing 2 new edges , safely deleting the old one etc , I’ll just replace the existing points in a way they’ll look smoother.

 

So let’s say black lines are the original coast line and forming a zig-zag which we don’t want. If we put i-2 ,  i-1 ,  i+1 and i+2 in catmull-rom , we’ll end up with a point between i-1 and i+1 right? You can see that blue line would be the smooth line , our interpolation function will create and i* will be the point it will return. So we’ll just replace the I with i* , and do this for all coast corners on the map!

 

I think it’ll be best if we do this in IslandService and CreateIsland method. But first of all , we must order coast corners in a line so we can just iterate through them as I explained above.

 var ordered = new List<Corner>();
 var first = App.AppMap.Corners.Values.First(x => x.Coast && x.Touches.Any(z=>z.Ocean));
 var start = first;
ordered.Add(first);
 var next = first.Adjacents.First(x => x.Coast);

 while (next != start)
{
     var nexte = next.Protrudes.FirstOrDefault(x => x.Coast && (x.VoronoiStart != ordered.Last() && x.VoronoiEnd != ordered.Last()));
    ordered.Add(next);
    next = nexte.VoronoiStart == next ? nexte.VoronoiEnd : nexte.VoronoiStart;
}

I’m not really sure if this is the best way to order them but well it’ll do for now. In the end we’ll have a list of corners ordered as a line. And then comes the iteration for interpolation ;

 for (int a = 0; a < 2; a++)
{
     for (int i = 2; i < ordered.Count 2; i++)
    {
        ordered[i].Point = PointOnCurve(ordered[i 2].Point, ordered[i 1].Point, ordered[i + 1].Point,
                                     ordered[i + 2].Point, 0.5f);
    }
}

So we iterate through each point and relocate it depending on the positions of 4 other points around it.

Oh and you can see the interpolation ratio there , 0.5f. That means , I want the point in the middle of curve between point i-1 and i+1. If I passed 0.9f , the result would be very close to i+1 and obviously if I passed 0.1f , it would be very close to i-1.

And of course the “PointOnCurve” function. I’ll admit I’ve just stolen this from a math forum , although I understand how does the calculation process works , I don’t have a full grasp on the code. You can easily find lots of resources on interpolation calculation and it’s fun really , so I suggest you read it about interpolation from more professional mathematicians. Anyway , here is the implementation I use;

 public Point PointOnCurve(Point p0, Point p1, Point p2, Point p3, float t)
{
     Point ret = new Point();
     
     float t2 = t * t;
     float t3 = t2 * t;

    ret.X = 0.5f * ((2.0f * p1.X) +
    (p0.X + p2.X) * t +
    (2.0f * p0.X 5.0f * p1.X + 4 * p2.X p3.X) * t2 +
    (p0.X + 3.0f * p1.X 3.0f * p2.X + p3.X) * t3);

    ret.Y = 0.5f * ((2.0f * p1.Y) +
    (p0.Y + p2.Y) * t +
    (2.0f * p0.Y 5.0f * p1.Y + 4 * p2.Y p3.Y) * t2 +
    (p0.Y + 3.0f * p1.Y 3.0f * p2.Y + p3.Y) * t3);

    return ret;
}

 

We’re pretty much done eh? So this is what it should look like now ;

 

WindowClipping

 

Much smoother then before right? I’ll admit I personally do not like this new smooth look. I prefer previous hex-like look , no contest. But I believe it was still a nice attempt and it was great to learn about Catmull-Rom so I decided to blog it.

Also I guess it looks a bit better when you remove the edges ,

WindowClipping (2)

 

Anyway , hope you liked it or at least find it somewhat useful. You can find the sample below!

 

Visual Studio 2010 Solution

Game Backgrounds in XNA 2D – Part 3

I’ll try to keep this short & clear so ( hopefully ) I’ll have to time actually code tonight.

In first post we talked about Fixed and Tiled Backgrounds

In second post we talked about Big Huge Backgrounds

In this post we’ll talk about Flowing Backgrounds. I believe it sounds silly but couldn’t find any other ( better ) name for it. What we’re going to do is create a layer which will constantly move even if the player doesn’t , like clouds in the background.

They’ll move even if the player doesn’t and they move faster ( relative to the player and camera ) if the player moves in opposite direction etc etc.

We’ll create and move a tiled background for this post but you can also use exact same logic for moving other background types like Big Huge ones.

 

Flowing Background

 

OK now as I said we’ll use a tiled background for this one so our FlowingBackground class will be pretty close to TiledBackground class we created earlier. Let’s have a look at how Tiled Backgrounds work again ,

image

Remember this picture from Fixed & Tiled Background post? It’s all same ,

publicclassFlowingBackground : IBackground
{
    privatereadonlyTexture2D _texture;
    readonlyint _horizontalTileCount;
    readonlyint _verticalTileCount;
    Vector2 _startCoord;
    privatefloat _speed;
    publicRectangle _previousCameraRectangle;

    public FlowingBackground(Texture2D texture, float speed, int environmentWidth, int environmentHeight)
    {
        _texture = texture;
        _horizontalTileCount = (int)(Math.Round((double)environmentWidth / _texture.Width) +1);
        _verticalTileCount = (int)(Math.Round((double)environmentHeight / _texture.Height) +1);

        _startCoord =newVector2(0, 0);
        _speed = speed;
    }
}

Again we have a texture , horizontal tile count , vertical tile count , start coordination  and as an addition we also have a speed and Camera position data from previous update.

 

Nothing fancy in constructor as you can see , we just set the variables we need and calculate vertical and horizontal tile counts.

 

Oh and by the way , I forgot to say it before , we will move our background in X dimension. Of course you can also implement something more complex with a bit of extra code but for the sake of simplicity , we’ll move it in X dimension with a constant speed set in constructor.

publicvoid Update(GameTime gameTime, TheGame game)
{
    var dif = game.CameraService.CameraRectangle.X _previousCameraRectangle.X;
    _previousCameraRectangle = game.CameraService.CameraRectangle;
   
    _startCoord.X = _startCoord.X + (this._speed) dif;
    if ((_startCoord.X >= _texture.Width) || (_startCoord.X >= _texture.Width))
        _startCoord.X =0;

    _startCoord.Y = ((game.CameraService.CameraRectangle.Y / _texture.Height) * _texture.Height) game.CameraService.CameraRectangle.Y;
}

As you can see our Update method will be a bit different than Tiled Background Update method.

At first we get the Camera.X difference between previous and current Camera Position. Remember in this example , our camera is following player character so the difference in Camera.X is almost same as the difference in Player.Position.X ( just not in map edges ). This is a nice effect but you can also remove this of course.

Then we update the start coordination for our tiles and since we’re only changing X , we have to check if the start coordination is in the range we want. ( talked about it a bit in Tiled Background part )

publicvoid Draw(SpriteBatch spriteBatch)
{
    for (int i =0; i < _verticalTileCount; i++)
    {
        for (int j =1; j < _horizontalTileCount; j++)
        {
            spriteBatch.Draw(_texture,
                newRectangle(
                    (int)_startCoord.X + (j * _texture.Width),
                    (int)_startCoord.Y + (i * _texture.Height),
                    _texture.Width, _texture.Height),
                    Color.White);
        }
    }
}

Draw method is exactly same as Tiled Background as you can see , nothing fancy here , just iterating through X & Y and drawing a 2D matrix , tile by tile.

 

And now it should look something like this ;

CodeMonekyGetUpGetCoffee (5)

 

Well it looks same as Tiled Background as an image but trust me , it moves!

 

There are a few more background types I want to talk about in the future like , progress indicator or parallax ( I’m not even sure that is what people call parallax really , but it’s such a cool name  )background.

 

Hope you find it useful !

 

Visual Studio 2010 Solution

Game Backgrounds in XNA 2D – Part 2

OK so we talked about layered background structure in 2D games in the first post and implemented 2 simple types; Fixed Background and Tiled Background. Although I keep saying them simple , those two are probably the most used types too. Especially Tiled Background is standard for top down or isometric view games.

In this post , we’ll talk about and implement two another types , Big Huge Background ( I honesty have no idea what to call it ) and Flowing Background ( I know I’m terrible at naming stuff ). ( Edit : I just decided to do Flowing Background in another post )

Big Huge Background

Let’s start with this one. Now you know sometimes they have a big environment in the background , like a city , and you slowly move on that background. That is exactly what we’ll going to do now. It’s pretty simple actually , only thing is ,  you have to be careful about X and Y Coordination of Camera. Have a look at this ;

bhb

As you can see , what are we supposed to do is , get a particular section of background image ( starting from Camera.X / Camera.Y and ending at Camera.X + 500 / Camera.Y +  500 ) and draw it on screen ( starting from 0 / 0 and ending at 500 / 500 )

 

Let’s have a look at the code ;

 publicclassBigHugeBackground : IBackground
{
     privateTexture2D _texture;
     privateRectangle _screenRectangle;
     privateRectangle _cameraRectangle;

    public BigHugeBackground(Texture2D texture)
    {
        _texture = texture;
    }

    publicvoid Update(Rectangle screenRectangle, Rectangle cameraPosition)
    {
        _screenRectangle = screenRectangle;
        _cameraRectangle = cameraPosition;
    }

    publicvoid Draw(SpriteBatch spriteBatch)
    {
        spriteBatch.Draw(_texture, _screenRectangle, _cameraRectangle, Color.White);
    }
}

Again we have a texture for background ( Texture2D class also holds Width and Height data of that image ) , _screenRectangle which holds the data for camera Width and height and _cameraRectangle which hold the data for Camera.X and Camera.Y.

Actually if you’re going for something simple like one view full screen , then you can get _screenRectangle data from _cameraRectangle too. But if you ever want to resize your camera view , say use top half of the screen for the game and bottom half for hud , then you’ll need both of them.

Nothing fancy in constructor and Update methods really. And as I said earlier , draw method just takes a section of image ( _cameraRectangle ) and draws it on whole game screen ( _screenRectangle ).

So now it should look something like this ;

CodeMonekyGetUpGetCoffee (4)

Please don’t mind the terrible background , it just makes it easy to debug movement and position related stuff.

 

I was planning to write about Flowing Background too but I think it would be better to keep posts shorter from now on. So I’ll talk about Flowing Background in another post.

 

You can find a sample Visual Studio Solution below , it contains both BigHugeBackground and FlowingBackground ( and the other 2 from previous post ).

 

Hope you like it!

 

Visual Studio 2010 Solution

Game Backgrounds in XNA 2D ( Fixed & Tiled )

 

It was like 2-3 weeks ago when I got bored and decided to check out some gaming forums. Gaming forums are always fun after all. After a few hours of skimming / reading / talking ; I remembered about XNA, the gaming framework of Microsoft using C# , and decided to give it a shot.

So I’m playing with XNA for that last 2 weeks and it has been incredibly fun! It’s extremely easy if you’re somewhat decent at C# and you can create experimental stuff extremely quick. Also there are big huge professional games using XNA out there , like Terraria , Bloodline Champions and Bastion. I’m not really experienced in game programming and don’t know much about other game development frameworks either but XNA really looks like the perfect choice for indie game developers to me now.

I’ve been making small experimental stuff all those 2 weeks and I’ll slowly blog about them , stargin with background management and creation in 2D games.

But please note that , I’m not experienced in XNA or game development , not one bit. So my samples here might bad practices or wrong or something. Beware.

So , about background in 2D games. First thing I wanted to try was a simple platformer , actually I think I started it after checking out one of the Xna Platformer samples. And after recreating what is already in that sample , I decided to improve it a bit myself and the first thing came to my mind was the backgroun since background is the heart and soul of a platformer. It takes like %90 of the screen and you stare it almost all game long. Also it’s the most important part of creating the mood and showing off your art style etc etc.

In this post , we’ll create the two simplest background types , static and tiled background.

What I call static background is just putting an image into background and no matter where does the player character moves , it doesn’t change one bit. It just stays there , pretty much like “Fixed Background” in Cascading Style Sheets.

On the other hand , tiled background is craeted by repeating same tile texture until it fills the whole screen , like grass or water in good old 2D games. It’s a bit repetitive of course but with good symmetrical textures , it looks pretty good and much more usable then one huge background image.

OK here we go , first of all I’ll create some services to take care of background elements. This might not be the best practice in XNA but I just like to work with my custom services to do stuff. I guess “Components” is the XNA way of doing the same thing but I prefer my good old simple service classes for now. I’ll read & learn about component later.

PlayerService = new PlayerService(this);
EnvironmentService = new EnvironmentService(this);
CameraService = new CameraService(this, EnvironmentService, PlayerService);

These are the first 3 services I like to use in every project. Obviously Player service creates and takes care of player , EnvironmentService handles background stuff and the level , CameraService takes care of camera position , where camera looks ( for 3D ) and stuff like that.

Constructor of the EnvironmentService is also simple and not much there for now;

 

 

public EnvironmentService(TheGame game) : base(game)
{
    _background = new Background(game, MapWidth, MapHeight);
}

 

tangle.Height))
Now the real content is all in Background object.

public class Background
{
    public List<IBackground> BackgroundLayers { get; set; }

    public Background(TheGame game, int mapWidth, int mapHeight)
    {
        BackgroundLayers = new List<IBackground>();

        BackgroundLayers.Add(new FixedBackground(_game.Content.Load<Texture2D>("space")));
        BackgroundLayers.Add(new TiledBackground(_game.Content.Load<Texture2D>("astroid"), _game.GraphicsDevice.Viewport.Width, _game.GraphicsDevice.Viewport.Height));

    }

    public void Update(GameTime gameTime)
    {
        foreach (IBackground bg in BackgroundLayers)
        {
            bg.Update(_game.CameraService.CameraRectangle);
        }
    }

    public void Draw(SpriteBatch spriteBatch, Rectangle screenRectangle, Rectangle nextPosition)
    {
        foreach (IBackground bg in BackgroundLayers)
        {
            bg.Draw(spriteBatch);
        }
    }
}

OK , what do we got here. We have a background layers list , we add our 2 background layers to that list in constructor method , update them in generic Update Method and Draw them on screen in generic Draw Method , nothing fancy.

As you can guess , Game Update method calls , EnvironmentService Update method which calls Background Update method. And same thing for Draw method too.

Oh and I got an interface for Backgrounds so I can keep them all in one list ;

   

public interface IBackground
{
    void Update(Rectangle screenRectangle);
    void Draw(SpriteBatch spriteBatch);
}

Now , let’s have a look at Fixed Background ;

   

public class FixedBackground : IBackground
{
    private Texture2D _texture;
    private Rectangle _screenRectangle;

    public FixedBackground(Texture2D texture)
    {
        _texture = texture;
    }

    #region Implementation of IBackground

    public void Update(Rectangle screenRectangle)
    {
        _screenRectangle = screenRectangle;
    }

    public void Draw(SpriteBatch spriteBatch)
    {
        spriteBatch.Draw(_texture, new Rectangle(0,0,_screenRectangle.Width,_screenRectangle.Height), Color.White);
    }

#endregion
}

That’s all and hardly anything there really. We just set texture in constructor method , update screen data in Update method and draw a simple rectangle in Draw method. One thing you may ask tho , do we really need to update screen data , it’s not like screen will change in the middle of game after all. But then , what if we want to change our camera position and Viewport? You may remove it too of course but I prefer having it there , just feels like it’s working properly checking out where to draw stuff every time.

In the draw method , we’re using generic spriteBatch.Draw method to draw an image using the texture set in contructor , starting from the top left of the screen (0,0) and ending at bottom right corner. ( Color.White is the standart input for no tinting , not really important for now ) Easy Peasy.

Now it should look something like this ;

Yea I’m using that ship , from one of those Xna samples , as player and a random space image from internet.

Now even tho our “space” is 4000×960 , no matter where player goes , background will stay the same.

And now let’s have a look at Tiled Background and add an astroid field to our game. But before the code , let’s see what do we really need.

This is simply how tiled backgrounds work. We create screenWidth / tileWidth + 1 amount of tiles ( because one tile will be used to fill empty space created by scrolling ) and start drawing them one by one , starting from a point close to top left ( which always changes according to player movement ). And if we assume our tile width is 100px , starting point X must be somewhere between 0 and -100. If it’s below -100 then there is no need to draw that tile , player can’t see it anyway and if it’s above 0 , then we’ll have empty space at the left of that tile , right?

Now let’s have a look at code ;

public class TiledBackground : IBackground
{
    private readonly Texture2D _texture;
    readonly int _horizontalTileCount;
    readonly int _verticalTileCount;
    public Vector2 _startCoord;

    public TiledBackground(Texture2D texture, int environmentWidth, int environmentHeight)
    {
        _texture = texture;
        _horizontalTileCount = (int) (Math.Round((double)environmentWidth / _texture.Width) + 1);
        _verticalTileCount = (int) (Math.Round((double)environmentHeight / _texture.Height) + 1);

        _startCoord = new Vector2(0, 0);
    }

    public void Update(Rectangle _cameraRectangle)
    {
        _startCoord.X = ((_cameraRectangle.X / _texture.Width) * _texture.Width) - _cameraRectangle.X;
        _startCoord.Y = ((_cameraRectangle.Y / _texture.Height) * _texture.Height) - _cameraRectangle.Y;
    }

    public void Draw(SpriteBatch spriteBatch)
    {
        for (int i = 0; i < _horizontalTileCount; i++)
        {
            for (int j = 0; j < _verticalTileCount; j++)
            {
                spriteBatch.Draw(_texture,
                new Rectangle(
                (int)_startCoord.X + (i * _texture.Width),
                (int)_startCoord.Y + (j * _texture.Height),
                _texture.Width, _texture.Height),
                Color.White);
            }
        }
    }
}

It’s pretty close to that simpler Fixed Background actually. We have a texture , a starting point and tile counts for each dimension. We set them all in constructor and then update starting coordination in the update method. I didn’t update tile count ( which depends on screen size ) here as an example. As I said in Fixed Background , it’s optional. Now if we change screen size during game , this background won’t be able to resize according to new screen.

Anyway , as I said, in update method we update starting coordination. Note that _cameraRectangle is the place where camera is looking at that given moment. We have a 4000×960 environment and our game screen is just 766×500 , so yes starting points of the camera rectangle changes as player moves.

(_cameraRectangle.X / _texture.Width) will give you the required tile count from absolute 0,0 to the top left of camera.

((_cameraRectangle.X / _texture.Width) * __texture.Width) will give you the X position of our first tile.

(((_cameraRectangle.X / _texture.Width) * __texture.Width) – _cameraRectangle.X) will give you the X position of our first tile relative to camera ( or relative to the (0,0) you have on your screen ) , or in other words it’s where we should draw the tile.

Draw method is pretty straight forward , it just draws a 2D matrix on screen.

And now it should look something like this;

Yes I know it looks horrible but it’s all because of the terrible textures I’m using , nothing related to the code. Hopefully I’ll have time and patience to find better textures for future blog posts. Who would want to try out such a bad looking sample right? It’s not really encouraging…

What’s next? Hmm I guess something like Flowing Background or I guess people call it Parallaxing Background eh? Anyway hope you like this one!

Visual Studio 2010 Solution

Oh and in case you’re curious about the solution name ; Code Monkey


Simple Map Generator Part 2

Wow , it has been 31 days since that last post? Damn I’m lazy. Ok so in this second part of the series , we’ll create our island and visualize it in 2D with some basic colors.

Remember we had our voronoi diagram and our polygons in previous post? Now we’ll need a logic to decide which polygons will be ocean/water and which part will be land. There are some generic algorithms like perlin noise for these stuff , but I decided to use a sine wave function which I saw in Amit’s example and actually it looks kinda better than perlin noise to me.

It’s a simple function which takes a point ( between 0 and 1 since we’ll use sine wave ) and returns a boolean to set IsLand property of the polygon.

It goes something like this ,

private bool IsLandShape(Point point)
{
    double ISLAND_FACTOR = 1.07;
    int bumps = islandRandom.Next(1, 6);
    double startAngle = islandRandom.NextDouble() * 2 * Math.PI;
    double dipAngle = islandRandom.NextDouble() * 2 * Math.PI;
    double dipWidth = islandRandom.Next(2, 7) / 10;

    double angle = Math.Atan2(point.Y, point.X);
    double length = 0.5 * (Math.Max(Math.Abs(point.X), Math.Abs(point.Y)) + GetPointLength(point));

    double r1 = 0.5 + 0.40 * Math.Sin(startAngle + bumps * angle + Math.Cos((bumps + 3) * angle));
    double r2 = 0.7 - 0.20 * Math.Sin(startAngle + bumps * angle - Math.Sin((bumps + 2) * angle));
    if (Math.Abs(angle - dipAngle) < dipWidth
    || Math.Abs(angle - dipAngle + 2 * Math.PI) < dipWidth
    || Math.Abs(angle - dipAngle - 2 * Math.PI) < dipWidth)
    {
        r1 = r2 = 0.2;
    }
    return (length < r1 || (length > r1 * ISLAND_FACTOR && length < r2));
}

I have to admit I just (shamelessly) converted Amit’s AS3 code to C# for this function and don’t totally understand what’s going on. I’m not really good at math and I didn’t want to waste time on this one. For all I know , it returns a “noisy” boolean series. Yes I’m a terrible person and coder , let’s move on.

Now we’ll just iterate through corners and set water/land values according to results of the function above. Not much to see here ;

foreach (var c in App.AppMap.Corners.Values)
{
     c.Water = !InLand(c.Point); // calculate land&water corners
}

Now that we have set corners’ land/water values , we’ll iterate through polygons ( centers ) and decide if a polygon is water or land according to states of it’s own corners. Also we’ll do some other stuff like fixing edges for polygons at the edge of the map and ordering corners as we’ll need them in order for creating visuals ( WPF Polygons ).

First ;

 

 

foreach (var ct in App.AppMap.Centers.Values)
{
    ct.FixBorders(); //Fix edges at map edge, set "border" and "ocean" values
    ct.OrderCorners(); //Order corners clockwise as we'll need it for polygons and 3d stuff

    //if it touches any water-corner , it's water
    ct.Water = (ct.Corners.Any(x => x.Water)) ? true : false;
}

 

As you can see I decided to set a polygon as water ( or sea , whatever ) if it has even one corner set as water. Of course you can use the exact opposite here ( land if it has one corner set as land ) or something more complex.

Then we’ll floodfill the oceans starting from map edges. Oh I set polygons at map edge as “Ocean” in FixBorders method but that method is pretty ugly and should be rewritten, so I’m not going to talk about it here. You can just go set a polygon as Ocean if it has a corner at map boundaries ( like X = 0 or Y = 0 etc )

 

var Oceans = new Queue<Center>();
    //start with oceans at the borders
foreach (Center c in App.AppMap.Centers.Values.Where(c => c.Ocean))
{
    Oceans.Enqueue(c);
}

//floodfill oceans
while (Oceans.Count > 0)
{
    Center c = Oceans.Dequeue();

    foreach (Center n in c.Neighbours.Where(x => !x.Ocean))
    {
        if (n.Corners.Any(x => x.Water))
        {
            n.Ocean = true;
            if (!Oceans.Contains(n))
            Oceans.Enqueue(n);
        }
        else
        {
            n.Coast = true;
        }
    }
}

I guess it’s pretty clear what’s going on here. We just ahve a queue for Oceans and we floodfill starting from the polygons at the edge of the map. Then we set every polygon , which has at least one corner set as water , as ocean. A nice little touch here, if a polygon we reached by this floodfill , doesn’t have any corners set as water ( all land ) this means that’s the coast! So we set it as coast and later we’ll visualize it as beach.

One last thing , we have to set polygon “biome”. We’ll use biome for template selection at the front end. You know ocean will be blue and land will be brown and stuff like that.

 

 

foreach (Center c in App.AppMap.Centers.Values)
{
    c.SetBiome();
}

Just wanted to clarify what it is.

Hmm we now have our island , created oceans and lands even beaches. Should be enough for this post but of course we need to visualize this all now right?

Since we already set biome for all polygons , we just need to set a visual style for that biome and use a template selector to choose polygon styles according to polygon biomes.

It’s kinda hard to write and explain Xaml stuff but I’ll try ; we’ll use this style for oceans

   

<DataTemplate x:Key="Ocean">
<Polygon Points="{Binding Converter={StaticResource MapPointToPointConverter}}"
Fill="#363661" />
</DataTemplate>

It creates a Polygon , do change corner points according to polygon center and fill the polygon with that probably blue-ish color. You can find all styles ( and even more, old test styles, which I forgot to delete ) in MapResource.xaml in the solution.

And since we’re using a Listbox as item container, we need to give our listbox a function to help him decide how to choose styles for each polygon.

It’s much longer but I’ll just paste a part of it as sample ;

 

public class MapDataTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        if (item != null && item is Center)
        {
            var center = item as Center;
            var window = Application.Current.MainWindow;

            return window.FindResource(center.Biome) as DataTemplate; 
        }
    }
}

It’s pretty straight-forward I guess. If the item is a Center ( polygon ) we just get the MainWindow ( which holds all styles , actually I doubt we need to do that but anyway ) and find the style ( FindResource ) according to that Center’s Biome. Listbox will handle the rest , easy peasy.

Now this is how it should look;

In the next episode? Hmm probably some elevation work maybe even rivers!

Hope you enjoy it!

Visual Studio 2010 Solution