Glaring Path Animation

So we created a glare effect on standard border in previous post but that insipid, boring border with rounded corners looked terrible. In this post, we’ll try to improve the shape, keeping the same old glaring effect we created.

We can’t change the shape of a border in WPF but we can use some other elements instead of border to achieve the same effect, like Path.

What we will do is to create different layers of Path’s and place the content above it ( instead of inside, like we do with Border ). Then maybe add some triggers ( or VisualStates ) for MouseOver, Selected etc states.

 

Let’s start with a simple path first;

    <Path Name=“Border”
       Data=“M0,5 5,0 350,0 360,10 360,200 340,220 10,220 0,210 Z”
       Opacity=“1”
       Stroke=“#317185”
       StrokeThickness=“2” />

As you can see from this simple declaration; Path is pretty much Border with a custom shape ( for this kind of usage ). Only non-trivial thing is the Data attribute and syntax for data input. I will not go into detail for that but you can read a lot more about XAML Geometry and syntax here. But to give you a tldr; version, it’s like an array of points; 0,5 –>5,0 –>350,0 etc.

And this is what it should look like;

 

WindowClipping (2)

 

Not bad, not bad at all…

And another trick before the real thing; using Path as Opacity Mask. Considering our rectangular image won’t fit in this irregular shaped frame.

    <Border Width=“355” Height=“215”>
        <Image HorizontalAlignment=“Center”
               VerticalAlignment=“Center”
               SnapsToDevicePixels=“True”
               Source=”{Binding Screenshot}
               Stretch=“UniformToFill”/>
        <Border.OpacityMask>
            <VisualBrush>
                <VisualBrush.Visual>
                    <Path Data=“M2,5 5,2 350,2 358,10 358,200 340,218 10,218 2,210 Z” Fill=“White” />
                </VisualBrush.Visual>
            </VisualBrush>
        </Border.OpacityMask>
    </Border>

Putting image into a border is a good old trick to properly centralize stretch image ( UniformToFill ) which I use frequently. And then we use a Path as Visual Brush to create an Opacity Mask for that border.

Now let’s start our picture frame. I’ll use a grid as container for all path’s, images, triggers and other stuff. You can also use any other panel for this, like Canvas. Grid is just easy-mode.

    <Grid Width=“360” Height=“220”>
        <Border Width=“355” Height=“215”>
            <Image HorizontalAlignment=“Center”
                   VerticalAlignment=“Center”
                   SnapsToDevicePixels=“True”
                   Source=”{Binding Screenshot}
                   Stretch=“UniformToFill” />
            <Border.OpacityMask>
                <VisualBrush>
                    <VisualBrush.Visual>
                        <Path Data=“M2,5 5,2 350,2 358,10 358,200 340,218 10,218 2,210 Z” Fill=“White” />
                    </VisualBrush.Visual>
                </VisualBrush>
            </Border.OpacityMask>
        </Border>

        <Path Name=“MainBorder”
               Data=”{StaticResource path}
               Opacity=“1”
               Stroke=“#317185”
               StrokeThickness=“2” />

        <Path Name=“Background”
               Data=”{StaticResource path}
               Opacity=“0.1”
               StrokeThickness=“1”>
            <Path.Fill>
                <RadialGradientBrush Center=“0.5,0.5”>
                    <GradientStop Offset=“0” Color=“Transparent” />
                    <GradientStop Offset=“1” Color=“#148cd1” />
                </RadialGradientBrush>
            </Path.Fill>
        </Path>

        <Path Name=“BackgroundUpper”
               Data=“M0,150 0,5 5,0 220,0 180,30 50,30 30,50 30,120 Z”
               Opacity=“0.9”
               Stroke=“#148cd1”
               StrokeThickness=“1”>
            <Path.Fill>
                <LinearGradientBrush StartPoint=“0.5,0” EndPoint=“0.5,1”>
                    <GradientStop Offset=“0” Color=“#357194” />
                    <GradientStop Offset=“1” Color=“#045482” />
                </LinearGradientBrush>
            </Path.Fill>
        </Path>
        <Path Name=“BackgroundLower”
               Data=“M360,60 340,90 340,170 310,200 160,200 130,220 340,220 360,200”
               Opacity=“0.8”
               Stroke=“#148cd1”
               StrokeThickness=“1”>
            <Path.Fill>
                <LinearGradientBrush StartPoint=“0.5,0” EndPoint=“0.5,1”>
                    <GradientStop Offset=“0” Color=“#357194” />
                    <GradientStop Offset=“1” Color=“#045482” />
                </LinearGradientBrush>
            </Path.Fill>
        </Path>

        <Path Name=“Border”
               Data=”{StaticResource path}
               StrokeThickness=“5”>
            <Path.Stroke>
                <LinearGradientBrush Opacity=“0.8” StartPoint=“0,0” EndPoint=“1,1”>
                    <GradientStop x:Name=“gs1” Offset=“-0.5” Color=“Transparent” />
                    <GradientStop x:Name=“gs2” Offset=“-0.4” Color=“Transparent” />
                    <GradientStop x:Name=“gs3” Offset=“0” Color=“#31C7F5” />
                    <GradientStop x:Name=“gs4” Offset=“0.4” Color=“Transparent” />
                    <GradientStop x:Name=“gs5” Offset=“1.5” Color=“Transparent” />
                </LinearGradientBrush>
            </Path.Stroke>
        </Path>

        <Grid.Triggers>
            <EventTrigger RoutedEvent=“Grid.Loaded”>
                <BeginStoryboard Name=“Glance”>
                    <Storyboard RepeatBehavior=“Forever”>
                        <DoubleAnimation Duration=“0:0:5”
                                           From=“-0.1”
                                           Storyboard.TargetName=“gs2”
                                           Storyboard.TargetProperty=“Offset”
                                           To=“5.0” />
                        <DoubleAnimation Duration=“0:0:5”
                                           From=“0”
                                           Storyboard.TargetName=“gs3”
                                           Storyboard.TargetProperty=“Offset”
                                           To=“5.1” />
                        <DoubleAnimation Duration=“0:0:5”
                                           From=“0.1”
                                           Storyboard.TargetName=“gs4”
                                           Storyboard.TargetProperty=“Offset”
                                           To=“5.2” />
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Grid.Triggers>
    </Grid>

OK this is a lot of stuff, so before explaining what’s going on here, I’ll show you the result;

 

WindowClipping (3)

 

It might look a bit complex for a simple starter sample but it’s rather easy really.

 

Now let’s go back and have a look at stuff inside our container grid. First of all, we have our image at the bottom of everything ( wrapped by a border but it’s not really important at this point ). The wrapper border also uses a path as Opacity Mask to crop the sharp corners of our rectangular image to fit.

 

After that, there is “MainBorder”, the non-animated static thin line you see around our image. Nothing fancy here. It uses a StaticResource path, to show it’s not only possible but also much better option than writing Path data again and again.

 

Then there is the “Background” layer. I guess it’s a wrong name for it though as it’s above the image, not behind. It’ creates a blue haze around the image, using a RadialGradientBrush. You may remove it as well, but I think it helps to mesh the colorful image with our blue sci-fi frame.

 

Above that, there is “BackgroundUpper” and “BackgroundLower” . I don’t even know why I keep them calling “Background” even though they are on top of everything but whatever. Those are that plate-like parts at the top-left and bottom-right of the image. Kinda helps the mood I guess. They both use LinearGradientBrush as SolidColorBrush felt & looked boring.

 

Then there is “Border”, pretty much the path version of the border we created in previous post. This time it doesn’t have the static line though ( we use MainBorder for that ). This one is mainly transparent and there is just a thick glare which looks like it’s moving on MainBorder as they stacked perfectly. Kind of hard to describe but you’ll know what I mean as soon as you see it.

 

I believe the Grid Triggers are exactly same as the Border Triggers we created in previous post. They just change the Offset of LinearGradientBrush that we use in “Border”. The animation is on a 5 second loop, first 1 second is the glare effect moving through the border and next 4 seconds is just a padding between animations.

 

Aaand that’s it. I guess just “MainBorder” and “Border” would be enough but I wanted to show some extra stuff you can do. Playing around with XAML is always fun but overdoing it hurts it more than helps.

Ah and one more thing, this won’t work in Silverlight as it is. Silverlight doesn’t have VisualBrush ( which we used for Image OpacityMask ) and some other stuff. I bet there are equivalent stuff or a work around but that’s beyond me.

 

I hope you liked it, see you next time!

Glaring Border Animation

I’ll start with a little UI trick for this series, glaring techy borders! ( I’m not even sure if “glaring” is the right word for it but anyway )

 

So I’ve been trying to get a light blue high-tech UI style for Towel as it fits the sci-fi ( or Starcraft 2 ) theme very well. You know like the high tech consoles from all mighty and glorious battleships. It was going rather well until I came across this little problem; when you put an unrelated image into a high-tech looking UI, it doesn’t blend well.

 

first

 

Notice how boring and insipid it looks. Obviously I needed some kind of border / frame for a proper transition but decided boring static borders wouldn’t cut it.

I also wanted something with animation, as I really believe that animations are what makes UI feel dead or alive. So I decided to try glaring lines which is very common among techy looking UI designs. I guess almost all sci-fi UI ever created has a variation of this.

 

second

 

It’s a very nice, subtle, non-distractive animation that fits so well with this kind of UI. And this is what the whole window looks like;

Towel (15)

 

So, how to do it? It’s rather easy really. All you have to do is to create a Border with LinearGradientBrush as BorderBrush.

<Border Margin=“20,0,20,0”
       BorderThickness=“2”
       CornerRadius=“5”>
    <Border.BorderBrush>
        <LinearGradientBrush Opacity=“0.5” StartPoint=“0,0” EndPoint=“1,1”>
            <GradientStop x:Name=“GradientStop1” Offset=“0.0” Color=“#FF057394” />
            <GradientStop x:Name=“GradientStop2” Offset=“-0.1” Color=“#FF057394” />
            <GradientStop x:Name=“GradientStop3” Offset=“0” Color=“#FF77DFFF” />
            <GradientStop x:Name=“GradientStop4” Offset=“0.1” Color=“#FF057394” />
            <GradientStop x:Name=“GradientStop5” Offset=“1.0” Color=“#FF057394” />
        </LinearGradientBrush>
    </Border.BorderBrush>
    <Border.Triggers>
        <EventTrigger RoutedEvent=“Border.Loaded”>
            <BeginStoryboard>
                <Storyboard RepeatBehavior=“Forever”>
                    <DoubleAnimation Duration=“0:0:5”
                                    From=“-0.1”
                                    Storyboard.TargetName=“GradientStop2”
                                    Storyboard.TargetProperty=“Offset”
                                    To=“1” />
                    <DoubleAnimation Duration=“0:0:5”
                                    From=“0”
                                    Storyboard.TargetName=“GradientStop3”
                                    Storyboard.TargetProperty=“Offset”
                                    To=“1.1” />
                    <DoubleAnimation Duration=“0:0:5”
                                    From=“0.1”
                                    Storyboard.TargetName=“GradientStop4”
                                    Storyboard.TargetProperty=“Offset”
                                    To=“1.2” />
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Border.Triggers>
    <Image Source=”{Binding Screenshot}/>
</Border>

As you can see all we need is a LinearGradientBrush and an EventTrigger that runs the animation.

Well I’m not really experienced in GradientBrushes really but I believe we need 5 stops for this kind of thing glare. It might also possible with 3 stops I guess (but then it won’t be slim/thin glare I’m afraid ) , got to experiment on stuff like that a little.

Animation starts running when the control is loaded and repeats forever. All it does is to move 3 middle stops bit by bit until it reaches the right end.

Hmm I guess that’s all? Yea pretty much

 

Get Microsoft Silverlight

 

Oh I hope this works properly. If it works I’ll try to add live SL samples like this every time from now on.

OK it looks somewhat decent but straight lines and curved corners are still boring right? I’ll talk about how to fix that in the next post, hope you like this one!

Towel, E-sports Aggregator

A towel, it says, is about the most massively useful thing an interstellar hitchhiker can have.

 

It has been a while since my last post eh? I have been working non-stop but unfortunately was too lazy to blog about stuff I’m working on. But well, now that I have a little more free time, guess it’s time to talk a little about WPF and my latest e-sports fan application attempt; Towel.

I believe it was 2010 summer, I first started my little humble Starcraft 2 fan application ScCalendar. At first, it was supposed to be just  a little desktop calendar with notification system ( based on TeamLiquid events calendar. ), to help people to keep up with all Starcraft 2 events going on. Later on I added lots of other stuff, like stream player, irc client, rss reader etc and it grow pretty fast.

ScCalendar have been downloaded more than 6500 times from our Codeplex page and even though it’s discontinued for almost a year ( for various reasons, I won’t go into that for now ), still has around 50-100 daily users.

 

Streams Window of ScCalendar

Main Menu and Notifications

Program Manager (20) Program Manager (7)

 

It looks kind of pretty but unfortunately code behind was a total mess. As I said the initial plan was just to have a calendar and notification system so there wasn’t a proper backbone or infrastructure to support a bigger application. And I did a terrible job with refactoring ( I simply didn’t do it ) and just kept adding new stuff. In the end, it turned into a huge bloated application that I couldn’t manage and support it properly anymore.

 

ScCalendar 2 & ScCalendar 3

After ScCalendar turned into a total mess, I decided to write a new one from scratch. A new version better, faster, prettier, manageable and  with a proper infrastructure to support all possible features I might want to add in the future.

To be honest, I don’t even remember ScCalendar2. I probably created the project, tried some stuff, experimented a bit ( MEF ? ) and then gave up.

Second attempt, ScCalendar 3 was much better though. I worked on it for a decent while, created a MEF based infrastructure and a decent module system. Even did most of the calendar and stream modules but then I noticed the structure was much more complicated than it should be. There were extra layers and useless abstractions  that I’ll probably never ever need etc. I learned my lesson though, making it HUGE makes it less manageable, not more.

 

StarcraftWindow (7)

Initial UI & Style of ScCalendar 3. I decided to try out Metro UI but no one ( except me )  liked this white theme so I had to redo the style and layout;

StarcraftWindow (9)StarcraftWindow (10)

All these screenshots are from early development stages, so don’t mind the bad UI/UX.

 

and the Towel

After the first 2 failures, I started Towel. I simply didn’t wanted to name it ScC4 and “Towel” was one of the first things came to my mind. I’ve always been terrible at naming stuff so I learned not to waste time on naming ( as it’ll be terrible no matter how much I try ) and stick with the first thing comes to my mind.

Fortunately ScCalendar3 code was actually pretty good, it was just too complicated. So all I had to do is to start a new project, copy  the ScC3 code and deleted some abstractions and layers.

 

Towel (11)Towel (12)Towel (13)Towel (14)

UI is servable yet still far from finished at this stage

 

I won’t go into too much detail here, but there are lots of stuff in Towel I want to blog about. Like modularity, completely skin able UI and animations. I’m also pretty new to most of those stuff myself, so it’ll be more like sharing what I learned than teaching. I hope someone out there ( it’s so lonely in the WPF world ) will find it useful.

Towel, at the moment, has calendar and stream widgets. They are both almost done, just doing little tweaks ( mostly UI ) and bug fixing now. Also started to work on Stream Player yesterday, it’ll be an external, stand alone player application so people will be able to use it separately as well. And only after that I’ll release the Towel 0.1b. Hopefully I won’t get bored and trash everything once again until then!

 

So now that I’m back to WPF and have lots of stuff to talk about, I’ll try to post more frequently. See you soon!

Coordinate Calculations in Hexagonal World 2

OK so I talked about hexagonal coordinate system in my previous post but actually there are more than just one way to do it. The one I used in my previous post ( let’s call it standard ) is probably the most straight forward and simplest way to do it. It’s also pretty much my favorite because of that but still there is one other way I would like to talk about, radial hexagonal coordination structure.

I really don’t know if this system has an official name but I’ll refer to it as radial structure from now on. Unlike the system we used before ( which uses a standard coordinate system with 2 axis) , radial coordinate system uses 3 axis for 2 dimensional mapping.

Sounds weird right? OK this picture will probably help a lot ;

 

hex

 

So let’s talk about this radial coordinate structure a bit ;

As you can see , this system uses 3 axis ( I’ll refer to those axis as r ( red ) , g ( green ) and b ( blue )) and the origin is in the middle instead of a corner ( the structure we used previously used top right as (0,0)).

You may also have noticed that in this system, we have rings around our starting hex. First ring has 6 hexes and the sum of absolute r,g,b values of those hexes is equals to 2
Second ring has 16 hexes and sum of absolute r,b,b values of those hexes is equals to 4

I guess you can see the pattern there.

Oh also for every hex, sum of r,g,b values is equals to zero. So in a way, r,g,b values shows how many step you need to take in various directions to reach (0,0,0).

Now check this out to see how each axis behave;

axis

As you can see red increases as we move from northwest to south east , green increases as we move from northeast to south west and blue increases as we move from south to north. You can also check out the axis arrows in that first picture.

Now if we put all those 3 on top of each other, we’ll have a 3 axis structure.

 

OK but how does this help? This structure is actually just a standard square grid with a matrix transformation , so the calculations are easier and somewhat more elegant. Instead of checking every sections like we did in previous post, we’ll just use some magical equations to find hex coordinates.

 

I guess it sounds confusing and actually I’m making it way more confusing than it should be , so I’ll just move on to the code part.

Again we’ll need 2 main functions ;

1) Hex coordinate to pixel coordinate

2) Pixel coordinate to hex coordinate

 

And luckily some nice fellow at this Stackoverflow question worked out all the equations so all we need to do is implement them properly.

 

 

 

x = sqrt(3) * s * ( b/2 + r)

y = 3/2 * s * b

 

r = (sqrt(3)/3 * x – y/3 ) / s

g = -(sqrt(3)/3 * x + y/3 ) / s

b = 2/3 * y / s

 

 

r,g,b are the hex coordinate axis

x,y are pixel coordinate axis

s is the edge length of a hexagon

 

Hex Coordinate to Pixel Coordinate

 

//radial structure
MapCoordination =newVector2
    (
    (float) (1.73 * Radius * (position.Z/2+ position.X)),
    (float) 3/2 * Radius * position.Z
    );

 

Position is r, g, b coordinate so it’s Vector3. ( x = r , y = g, z = b )

Not much to say here really,  I didn’t even bother to calculate equations myself and it’s extremely easy when you got the equations right? 2nd function isn’t hard either ;

 

Pixel Coordinate to Hex Coordinate

 

return new Vector3(
    (float)Math.Round((1.73f/3.0f* position.X – position.Z /3) / Radius),
    (float)Math.Round((1.73f/3.0f* position.X + position.Z /3) / Radius),
     (float)Math.Round(0.66* (position.Z /Radius)));

 

Position here is the Vector2 which we want to get Hex coordinates for. And the Vector3 we create is the r, g, b coordinates. Again not much to explain here, you just provide the coordinates and equations spit out the result, magic I say, magic !

 

So which one is better?

Well I can’t really say I have vast experience in hexagon calculations but at this moment , I can’t see a breaking difference between two so it’s just personal preferences for me.

Obviously this radial structure calculations are easier and will probably be faster but the difference is so small that I highly doubt you’ll feel anything unless you’re making thousands of calculations every second.

On the other hand, standard / rectangular structure coordinates are way easier to understand and use. Consider this for example ;

 

HexWorld3D (10)

I’m pretty sure anyone can create this map in standard / rectangular coordinate system in a few minutes but it’ll be much harder in radial coordinate system that you’ll probably need a map editor. I love how I can predict the result and coordinates in standard system to be honest.

Anyway guess we’re pretty much done right? Am I missing something? It’s early in the morning ( and I have to leave soon ) so I suspect there’ll be lots of grammar mistakes and stuff. I hope it’s still somewhat understandable…

Oh well, I’ll be more careful next time!

Coordinate Calculations in Hexagonal World

Hey again!

This time I’ll talk about something different, coordinates in hexagon based maps!

First of all let me tell you this , hexagons are much more cooler than square tiles can ever be, period. And I won’t even go into stuff like diagonal movement problem on square tiles and stuff like that. It’s just that square tiles used way too much while it feels like hexagons are under used and under appreciated.

But hexagons comes with a price, small but still there it is. It just a bit harder to calculate coordinates on a hexagon based maps. You know how easy it is to calculate pixel/tile coordinates on square based maps? You just divide/multiply everything by square edge size? Well it’s just a bit more complex on hexagonal maps as you can guess but still all it takes is a few helper functions and then you’re set.

 

Hexagons – Billions of bees cannot be wrong

You probably already know that there are 2 different type of hexagonal structure ; vertically aligned and horizontally aligned.

 

hexes

 

Well technically it’s just like rotating 90 degrees right? But it’s actually much more than that. Not only that rotation changes math behind all together, it even effect how many different sprites you need to texture etc etc. So when you choose on of these styles , you probably won’t have an easy time to switch to another so be careful.

 

I personally prefer horizontally aligned hexagons ( top ). It totally personal for me but horizontally aligned hexagons feels better for grand strategy games like Civilization while vertically aligned hexagons feel better for small size tactical strategy games. But as I said it’s totally personal. Also I heard some artists saying that horizontally aligned requires less sprite variations but don’t quote my on that.

 

Anyway as I said I prefer horizontally aligned hexagons so all my math and samples will be using that.  Still I’m sure you can work math out for vertically aligned one easily.

 

coords

 

And one more thing before we start the calculations, obviously we’ll need some constants for hexagons like edge length. Have a look at this ;

hexagon

We’ll calculate all those variables from just one thing , radius. And actually I guess that picture is a little misleading, where it says radius is actually just an edge, radius is the distance from center to any corner but considering the angles between edges of a hexagon, radius is equal to edge. Hope it is clear.

As I said we’ll calculate all those from radius so let’s have a look at that ;

public HexValues(float radius)
{
    Radius = radius;
    Height =2* Radius;
    RowHeight =1.5f* Radius;
    HalfWidth = (float)Math.Sqrt((Radius * Radius) ((Radius /2) * (Radius /2)));
    Width =2*this.HalfWidth;
    ExtraHeight = Height RowHeight;
}

We’ll do this once at the beginning and use those variable then so we will be able to change hex sizes easily whenever we want to.

Then we need 2 main functions.

 

1) Calculating pixel coordinates from hex coordinates ( We’ll use hex coordinates mainly since it’s way easier. If we assume Width is 64 for example , (1,0) will become (64,0) )

 

2) Calculating hex coordinates from pixel coordinates ( We’ll need this for a few different things , for example converting mouse coordinates to hex coordinates so we can detect which hexagon player selected etc. )

 

Calculating pixel coordinates from hex coordinates

First one is much easier so let’s start with that ; pseudo code for that should be something like this ;

PixelX = (HexX * Width) + ( ( HexY AND 1 ) * ( Width / 2 ) )
PixelY = HexY * RowHeight;

Or in C# ;

MapCoordination =newVector2
    (
    (position.X * _values.Width) + (((int)position.Y&1) * _values.Width /2),
    position.Y* _values.RowHeight
    );

Let me explain that a bit ; if you go back and check the hex coordinates image again , you’ll notice the horizontal placement is just increasing by Width every hex but it starts with an offset every other row. So;

PixelX = (HexX * Width)

will draw hexagons one by one as they are in first row ( top row is 0 ) and then

+ ( ( HexY AND 1 ) * ( Width / 2 ) )

will add (Width / 2) offset to every other row. ( 1st, 3rd, 5th etc)

Y coordinate is much simpler, if you check it out carefully you’ll actually see Y increases by Row Height , every row. So it’s just HexY * RowHeight. Easy peasy.

With this function we’ll be able to say “Put a hex to (5,6)” and it’ll calculate the actually pixel coordinates and we won’t need to bother with those calculations again.

 

Calculating hex coordinates from pixel coordinates

Now this is harder, much harder. Now have a look at this and notice that our hexagonal map actually can be divided into two type of rectangles/squares.

 

rows

 

And as you can see those rectangles are “Width” pixel wide and “RowHeight” pixel long. So actually it’s pretty easy to calculate which square you’re in ;

int GridX = (int)px / (int)(type.HexValues.Width);
int GridY = (int)py / (int)type.HexValues.RowHeight;

var GridModX = (int)px % (int)type.HexValues.Width;
var GridModY = (int)py % (int)type.HexValues.RowHeight;

gridX and gridY will tell us which tile we’re in and then gridModX and gridModY will tell us the position in that tile.

Now if you check that image again, you’ll see both A and B tiles contains areas belong 3 different hexagons. (2,1) tile for example is type B and contains areas which belongs to green ( top ), blue ( left ), orange ( right ) hexagons. and (2,2) is type A which contains areas belong to blue ( top left ) , orange ( top right ) and green ( bottom )

Now that we already know which tile we’re in and the exact coordinate in that tile , we’ll just find which hexagons contains the point in that tile.

I’m sure you understand the concept so I won’t bother to explain all lines one by one. Here is the first block ;

 

if (gridTypeA)
{
    // middle
    resultY = gridY;
    resultX = gridX;
    // left
    if (gridModY < (type.HexValues.ExtraHeight gridModX * m))
    {
        resultY = gridY 1;
        resultX = gridX 1;
    }
    // right
    if (gridModY < (type.HexValues.ExtraHeight + gridModX * m))
    {
        resultY = gridY 1;
        resultX = gridX;
    }
}

 

Should be pretty straight forward. 3 different results as Type A tiles contains 3 different zones. Middle , left and right.

And if it’s Type B ;

else
{
    if (gridModX >= type.HexValues.HalfWidth)
    {
        if (gridModY < (2* type.HexValues.ExtraHeight gridModX * m))
        {
            // Top
            resultY = gridY 1;
            resultX = gridX;
        }
        else
        {
            // Right
            resultY = gridY;
            resultX = gridX;
        }
    }

    if (gridModX < type.HexValues.HalfWidth)
    {
        if (gridModY < (gridModX * m))
        {
            // Top
            resultY = gridY 1;
            resultX = gridX;
        }
        else
        {
            // Left
            resultY = gridY;
            resultX = gridX 1;
        }
    }
}

 

Actually I guess I missed some extra lines here and there so I’ll just put the whole function too. ( my function works in 3D space though , it’s all same just don’t mind me using Vector3 )

 

privateVector3 GetHex(HexType type, Vector3 pos)
{
    var px = pos.X + type.HexValues.HalfWidth;
    var py = pos.Z + type.HexValues.Height /2;

    int gridX = (int)px / (int)(type.HexValues.Width);
    int gridY = (int)py / (int)type.HexValues.RowHeight;

    var gridModX = (int)px % (int)type.HexValues.Width;
    var gridModY = (int)py % (int)type.HexValues.RowHeight;

    bool gridTypeA =false;

    if (((int)gridY &1) ==0)
        gridTypeA =true;

    var resultY = gridY;
    var resultX = gridX;
    var m = type.HexValues.ExtraHeight / type.HexValues.HalfWidth;

    if (gridTypeA)
    {
        // middle
        resultY = gridY;
        resultX = gridX;
        // left
        if (gridModY < (type.HexValues.ExtraHeight gridModX * m))
        {
            resultY = gridY 1;
            resultX = gridX 1;
        }
        // right
        if (gridModY < (type.HexValues.ExtraHeight + gridModX * m))
        {
            resultY = gridY 1;
            resultX = gridX;
        }
    }
    else
    {
        if (gridModX >= type.HexValues.HalfWidth)
        {
            if (gridModY < (2* type.HexValues.ExtraHeight gridModX * m))
            {
                // Top
                resultY = gridY 1;
                resultX = gridX;
            }
            else
            {
                // Right
                resultY = gridY;
                resultX = gridX;
            }
        }

        if (gridModX < type.HexValues.HalfWidth)
        {
            if (gridModY < (gridModX * m))
            {
                // Top
                resultY = gridY 1;
                resultX = gridX;
            }
            else
            {
                // Left
                resultY = gridY;
                resultX = gridX 1;
            }
        }
    }

    returnnewVector3(resultX, 0, resultY);
}

 

With this function, we’ll be able to say “Mouse is on (150,250) coordinates, go highlight that hexagon” and it’ll convert (150,250) to the hexagon coordinates you need.

 

Hmm I guess we’re pretty much done right? Oh well I’ll give you just one more function as bonus, the one I use to draw hexagons in 3D world. I won’t explain it though as it’s pretty straight forward. 1 Hexagon = 4 Triangles = 12 vertices

 

privatevoid DrawTop()
{
    var zero =newVertexPositionTexture();

    var m = (_values.Height _values.RowHeight) / _values.Height;
    var p = (_values.RowHeight) / _values.Height;
   

    zero.Position =newVector3(MapCoordination.X _values.HalfWidth, MapCoordination.Y, MapCoordination.Z _values.Radius /2);
    zero.TextureCoordinate.X =0;
    zero.TextureCoordinate.Y = m;
    _vertices.Add(zero);

    zero.Position =newVector3(MapCoordination.X + _values.HalfWidth, MapCoordination.Y, MapCoordination.Z _values.Radius /2);
    zero.TextureCoordinate.X =1;
    zero.TextureCoordinate.Y = m;
    _vertices.Add(zero);

    zero.Position =newVector3(MapCoordination.X _values.HalfWidth, MapCoordination.Y, MapCoordination.Z + _values.Radius /2);
    zero.TextureCoordinate.X =0;
    zero.TextureCoordinate.Y = p;
    _vertices.Add(zero);

    //——————————————

    zero.Position =newVector3(MapCoordination.X + _values.HalfWidth, MapCoordination.Y, MapCoordination.Z + _values.Radius /2);
    zero.TextureCoordinate.X =1;
    zero.TextureCoordinate.Y = p;
    _vertices.Add(zero);

    zero.Position =newVector3(MapCoordination.X _values.HalfWidth, MapCoordination.Y, MapCoordination.Z + _values.Radius /2);
    zero.TextureCoordinate.X =0;
    zero.TextureCoordinate.Y = p;
    _vertices.Add(zero);

    zero.Position =newVector3(MapCoordination.X + _values.HalfWidth, MapCoordination.Y, MapCoordination.Z _values.Radius /2);
    zero.TextureCoordinate.X =1;
    zero.TextureCoordinate.Y = m;
    _vertices.Add(zero);

    //——————————————

    zero.Position =newVector3(MapCoordination.X + _values.HalfWidth, MapCoordination.Y, MapCoordination.Z + _values.Radius /2);
    zero.TextureCoordinate.X =1;
    zero.TextureCoordinate.Y = p;
    _vertices.Add(zero);

    zero.Position =newVector3(MapCoordination.X, MapCoordination.Y, MapCoordination.Z + _values.Height /2);
    zero.TextureCoordinate.X =0.5f;
    zero.TextureCoordinate.Y =1;
    _vertices.Add(zero);

    zero.Position =newVector3(MapCoordination.X _values.HalfWidth, MapCoordination.Y, MapCoordination.Z + _values.Radius /2);
    zero.TextureCoordinate.X =0;
    zero.TextureCoordinate.Y = p;
    _vertices.Add(zero);

    //——————————————

    zero.Position =newVector3(MapCoordination.X _values.HalfWidth, MapCoordination.Y, MapCoordination.Z _values.Radius /2);
    zero.TextureCoordinate.X =0;
    zero.TextureCoordinate.Y = m;
    _vertices.Add(zero);

    zero.Position =newVector3(MapCoordination.X, MapCoordination.Y, MapCoordination.Z _values.Height /2);
    zero.TextureCoordinate.X =0.5f;
    zero.TextureCoordinate.Y =0;
    _vertices.Add(zero);

    zero.Position =newVector3(MapCoordination.X + _values.HalfWidth, MapCoordination.Y, MapCoordination.Z _values.Radius /2);
    zero.TextureCoordinate.X =1;
    zero.TextureCoordinate.Y = m;
    _vertices.Add(zero);
}

 

Guess it may help some of you guys , it’s boring to calculate that vertex position after all. It works pretty well for me but you may need to tweak it a little.

 

It should be easy to create a hexagonal map structure with all those functions. I hope you guys like it!

Let me know if there is anything you don’t understand or if you have any improvement ideas. See you next time!

On Orthogonal Camera usage in Fez ( and Fedora )

It has been a long time since the last blog post , more than a month I guess eh? OK I was planning to write this for a long time now, it’s an old project where I tried to imitate camera usage of the famous and beloved platform game Fez. It’ll probably be a short post, some general guidelines and a sample project. Here we go , first of all;

 

What is Fez?

Fez is an adorable platform / puzzle game for XBox 360 ( supposed to be released in Q4 2011 as far as I know ). I found out about it only a few months ago when someone posted a gameplay video from PAX East 2011 on forums.

 

FEZ – PAX East 2011: XBLA Gameplay (2011) | HD

 

What makes it special is the usage of orthogonal camera and a great mix of 2D/3D world.  Also as you can see at the 2:15 minute mark, it has pretty nice puzzles using this 2D/3D world.

I fall in love with the game the second I saw this video and decided to give it a shot to create a Fez Clone. The main idea ( and what I’ll be talking about this post ) was just imitating camera usage, orthogonal camera and cool animations for switching dimensions but then I got carried away and added a lot more to it. ( see Fedora )

 

So what is Orthogonal View / Projection ?

Orthogonal projection is literally means representing a three dimensional world just in 2 dimensions. This is exactly what Fez did right? Losing the 3rd dimension means no depth so you can’t really say if the actual world is 2D or 3D until the camera rotates.

 

Orthogonal projection yields pretty nice results and I honestly believe it’s under used in gaming industry, especially in indie games. There are possible lots and lots of new and unexplored game mechanics one can achieve using orthogonal projection.

 

So what is the plan?

The plan is making a simple grid based 3D world first, Fez uses a pretty similar world structure after all. I won’t go deep into this really as creating a grid world shouldn’t be hard and the code is all in sample anyway. We don’t need anything complex either, something simple like this should do it ;

 

 

And then obviously we need to create and place an orthogonal camera.

 
CurrentCameraPosition = new Vector3(0, 0, CamDistance);
_lookPosition = new Vector3(0, 0, 0);
ViewMatrix = Matrix.CreateLookAt(CurrentCameraPosition, _lookPosition, new Vector3(0, 1, 0));
ProjectionMatrix = Matrix.CreateOrthographicOffCenter(400, 400, 240, 240, 0.2f, 5500.0f);

Now let’s have a look at it ;

CurrentCameraPosition is a Vector3 with x = 0 and y = 0. This means our orthogonal camera will be set on Z dimension. Also it doesn’t matter if the CamDistance is 1 or 1000 as I said before, there is no depth in orthogonal projection anyway. Only thing matters is if it’s positive or negative.

_lookPosition is obviously where it looks. Our camera will be rotating around the center.

There is nothing fancy about View Matrix, it’s just using the previous variable we created.

And projection matrix is where we decide what kind of projection we will use ( perspective or orthogonal ). Obviously we use orthogonal projection ( CreateOrthographicOffCenter ) and set some variable about the camera size. ( now we could also used CreateOrthographic method to create this but I prefer OffCenter method as it gives more flexibility. There isn’t much difference between them except that )

 

So now we should have a  view like this;

 

See how there is no feeling of depth and those crates looks like they are stacked on each other?

 

One last thing we have to do is adding transition animations. It’s kind of hard to explain it all here so I’ll just talk about the general outline. It’s all in sample code anyway.

So we have 4 different possible camera position right? ( +x , –x , +z, –z ) This means we have 8 possible different transitions ( clockwise and counter clockwise ). So what we have to do is just interpolate camera position from , let’s say +z to +x slowly.

We will have to keep track of some stuff though like , if we’re in the middle of an animation or what’s the starting and ending points of this animation and what’s the current progress of this animation.

Leaving little stuff like those aside , this is the main transition function we will use;

 private void PlayAnimation(GameTime gameTime)
{
    _rotationTime += gameTime.ElapsedGameTime.Milliseconds / ( RotationTimeTotal * 1000 );
    _rotationTime = MathHelper.Clamp(_rotationTime, 0.0f, 1.0f);
    _rotationAngle = MathHelper.SmoothStep(0, 90, _rotationTime);

    var _cameraRotatedPosition = Vector3.Transform(AnimationStart.CameraPosition, Matrix.CreateRotationY(MathHelper.ToRadians(_rotationAngle * ((AnimationEnd.Previous == AnimationStart) ? 1 : 1) )));
    _cameraRotatedPosition += _lookPosition;
    ViewMatrix = Matrix.CreateLookAt(_cameraRotatedPosition, _lookPosition, new Vector3(0, 1, 0));
}

It uses “_rotationTime” as an progress indicator. And we have a _rotationTimeTotal as we want all our animations to take exact same amount of time.

Then we calculate the angle we should rotate cam this iteration ( remember this block runs like hundreds of times for each animation , actually that’s something you can ( or maybe even should ) improve. Instead of calculating every single iteration, you may want to only calculate every 2 degree or something. The performance difference will be incredibly small but still that’s a more elegant approach )

Now that we have the angle, we’ll transform current camera position using that angle.

And finally set new View Matrix and keep doing this till we reach the point we need.

Notice that this function has 2 important points ; every animation should take same amount of time and camera position interpolation should be smooth ( I used SmoothStep for this one but of course you can switch to Lerp if you want to)

And this is pretty much how it should look while rotating ;

 

Fedora (2)

 

Now I know it doesn’t look that good in this screenshot but this sample is all about animation anyway and I’m sure it’ll look WAY better if you use a variety of textures for blocks etc.

 

You can find extra stuff I’ve done on this structure here in my Fedora Project page. There are few interesting additions like Bastion-lie world creation where objects fall from sky ( or floor rise from below ) as you move etc. All in all it was a fun project ( and actually Fedora was my XNA learning project ) but I’m not working on this anymore.

Hope you guys like it or find it useful. You can find the sample solution below, see you next time!

 

Visual Studio 2010 Solution

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