Saturday, June 4, 2011

DotNetFish - Editor Minimap

Added the basic part of the minimap to the editor. Also added the ability to move more than 1 square using the shift and ctrl keys.

I'd still like to add the following features before going to work on the game itself.
  1. Need the ability to change a tile on the map
  2. Be able to navigate through the error tiles
  3. Need to be able to runs a check to make sure every edge tile is connected
I still think there is some bugs in the map generator, but I think I can wait on fixing those until I get further along.

Tuesday, May 31, 2011

DotNetFish - MVVM Part Deux

I only thought I was done refactoring the Projects to use the MVVM pattern. Turns out that two of the three views in the level editor were not converted yet. The Map Select window will not be converted anytime soon either, but its very simple to begin with and not a big deal if it isn't. It cannot be converted at this time because the GMap control does not support MVVM. The other page that I needed to convert is the Edit Level Window, where all of the map editing will be done. It took quite a bit of doing, but I finally forced it into compliance. I am not happy with the results though, and I think some more refactoring is in order.

The biggest challenge that I ran into was getting the my ViewModel for the page, and the custom Map Control to play nicely together. The custom canvas control that I am using does not support any sort of bindings, so I was forced to write my own.

Here is what a dependency property looks like

public static readonly DependencyProperty CurrentPointCommandProperty =
        DependencyProperty.Register(
            "CurrentPointObject",
            typeof(Point),
            typeof(MapCanvas),
            new PropertyMetadata(new PropertyChangedCallback(OnPropertyChanges))
            ); 

Dependency properties are quite easy once you get the hang of it. The string in the example above, is the name of a public property. The first type is the type of the property being referenced, and the second type is the type of whatever object the property resides in. This also contains a Callback when the property changes


private static void OnPropertyChanges(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
 (obj as MapCanvas).InvalidateVisual();
} 

So anytime a property changes the Visual on the mapCanvas is overwritten.

Nothing much to it so far. My biggest concern is the number of  DP's that I have to register just to do something simple.


Now, the second change I made here, was to use the MVVM Light Toolkit instead of the custom implementation I created to handle the commands. This toolkit allowed me in conjuction with the Blend SDK to wire up commands to events that fire on the page rather than the control.

For example

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WPF4"
 
<i:Interaction.Triggers>
        <i:EventTrigger EventName="KeyDown">
            <cmd:EventToCommand Command="{Binding OnKeyDown}" PassEventArgsToCommand="True" />
        </i:EventTrigger
</i:Interaction.Triggers>    

This code allows me to bind to the KeyDown Event. It allows my viewmodel to recieve the eventArgs as well. Very useful.

My next step is probably going to involve some refactoring. I think that I can use the MVVM Light messages to help pass information from ViewModel to ViewModel, and also ViewModel to View. Doing so should cut down on the amount of code and Dependency Properties required. Even if most of them are refactored out, I learned a ton about using them and debugging them!



Friday, May 20, 2011

DotNetFish - Sweeping Changes

Got a healthy dose of optimization finished in the map builder. It now approaches each tile from a much lower zoom level, and only goes to a higher zoom level when the map tile has a water/land edge. I'm still not 100% sure that this is the best approach to take., and it may be faster and simpler to process the tiles at a higher zoom level. This is only possible now due to the other changes I made to the build process. For a body of water that has a lot of water and long compared to edges should see a pretty significant improvement, although it will be slower when testing using only edge tiles.

Tiles are now processed much simpler than they were before. Its always difficult to make something simple. I realized that my design was much too complicated when it didn't need to be, so I simplified it significantly. I am now getting much better results, and far fewer error tiles.


I am almost ready to move away from the map generation process, and start focusing on some additions to the editor to allow you to fix error tiles, add spawn locations, etc. I have a few bugs to look at in the build process, and then I plan to focus on the editor.

Monday, May 2, 2011

DotNetFish - Headed towards optimization land

Looks like its time to take a trip towards optimization land.

I knocked one of the items off of my list, which was adding some directionality into the path finding to help it out. Then I attempted to process a small pond. This didn't go so well, as it ground to a halt. The problem I was having is that during debug I was saving each image I was processing. 800 tiles produces 200,000 images in a single directory which was a major source of the slowdown.

After fixing this issue, I will still need to increase the performance. I don't want to spend 4-5 hours building the map of a small lake. So far, I have followed the advanced rule of optimization which states

Don't Optimize Yet

You see, I have not done much performance tuning up to this point, although I did optimize the actual process of processing the tile. I think its important to know when to optimize. I'm now to the point where I need to start processing larger maps, so it makes sense to address this issue now.  I could have made these changes earlier of course, since I understood where the bottleneck was occurring, but there were more important things to work on.

I may have touched on the optimizations that I need to perform, but what it comes down to is processing the edge tiles at the largest magnification, and processing everything else at a much smaller magnification.

Currently, I am processing each 256 tile at the largest zoom setting into  256 tiles. Each of those tiles is having its borders processed as well. A good first optimization would be to only break a tile down into smaller tiles if it actually has an edge on it. Add in zooming out a few levels, and the performance should increase several orders of magnitude.

Currently it took about 6-7 minutes to process 1200 tiles which was about 1000x1000 feet. Given that even a fairly small lake hear my house  is 52,800x 26,400, you can easily understand why this is so important.


On a final note:
After the second run, I had approximately a 4% failure rate. Now I have something to shoot towards beating.

Sunday, May 1, 2011

DotNetFish - A* PathFinding First Pass

It took me a full day to implement, but the map builder can now find a path to an unconnected edge.

The map builder is coming along nicely. I have a few more issues to iron out with the path finding in general that need to be fixed. Once that is done the generation part will be finished for now. Maybe next week I'll be able to hammer out the rest of the path finding.

Current Items of interest
  1. Double edge connections. Loops need to be implemented. For example, is tile A has 2 connections on the same side but nowhere to go, then the tile next to it needs to have a loop added to it,this will require some new tiles.
  2. Need directionality for finding potential matches when looking for target tiles to pathfind to. It should travel away from the starting side first. Only if no potential matches are found should it look behind it.

Friday, March 25, 2011

Appfabric Caching Admin Client

http://mdcadmintool.codeplex.com/Been doing some work with appfabric. One of the things I don't like about it, is the lack of a way to mange the cache with a GUI. Currently, you can only manage your cache and clusters with powershell. One thing that I haven't been able to do is visualize the items inside the cache. But I did find a great solution to this.

http://mdcadmintool.codeplex.com/

The client seems pretty stable, although there are still some issues with it. I hope that the guy that wrote it continues to improve it. Maybe in the future MS will provide a easy to use client but until then, this will have to do.

Saturday, March 12, 2011

DotNetFish - We've got MVVM

Just a quick status update. Implemented MVVM pattern for the TileBuilder Project. It was the most time consuming of the WPF projects to do. The other ones should fall quickly now. Won't be able to work on it this weekend, as I am going to do some research(IE real fishing). Real fish taste better anyways.

Sunday, March 6, 2011

DotNetFish .01 and .02 Road Map

.01 roadmap major tasks left to complete
  1.  Refactor the WPF projects to use the MVVM pattern (http://msdn.microsoft.com/en-us/magazine/dd419663.aspx) Damn you Billy, and your insistence that I learn patterns!
  2. Complete the processing of Error tiles in the level designer
  3. Implement the ability to set a spawn location on the level
  4. Create the WPF Game client
  5. Integrate the Physics engine into the project
  6. Get Boat movement working
.02 roadmap major tasks
  1. Improve the performance of the level designer
  2. Implement the fish and fish related behavior
  3. Implement Lake Depth
  4. Implement the first fishing method: Casting

This should give you an idea of what I plan to tackle first. Improving performance of the level designer will probably be the most challenging part of .02. Then again, when you are building stuff that doesn't have any sort of reference, it always takes longer than you think. 


DotNetFish - Horseshoes and Hand Grenades

I've been able to make a little progress this weekend. To start with, I changed the datatype of the edge points from a Point, to a list of bytes. This was necessary because eventually you might see tiles that have mroe than two edge points, and it was also needed for the next change I made, which was the edge tile will now check the surrounding tiles to see if they have any edges it needs to line up with.

This change makes the map look quite a bit better, as most of the tiles connect properly. However, I still have quite a few tiles that are showing up as an error tile. This is where the old saying that close only counts in horseshoes and hand grenades. I'm close, but that's not good enough for me. I really would like to have 99.999% of the tiles be correct. This calls for me to implement one final feature of the generator process, and that is pathfinding.  Here is what I plan to do


  1. Go to the next error tile
  2. Check to see if this error tile is actually an edge tile, if not then set it to water or land
  3. If it is an edge tile, find a path from the edge connector around it to the closest edge tile that has an open edge. 
  4. Convert the tiles along the path into edge tiles 

Before                           After


Orange Tiles are Edge Tiles, Red lines are edge connection points


I ran a test this morning, and I think that this is the last large change I need to make in order to get the map looking good.

I also sat down for a few minutes, and thought a bit about the road map for release .01 and release .02. I made a significant change to .01, in that I moved the ability to cast for fish into .02. I did this because there is a whole host of logic that needs to be implemented related to casting, such as fish and their behavior, lake depth, etc. I'd rather be able to get .01 out without those features.

Tuesday, March 1, 2011

DotNetFish - Quick Update

Got the color matching to work now, so the correct tile should be selected in that regard. Next on my list is working on getting the rest of the tiles to line up properly.

Sunday, February 27, 2011

DotNetFish - Status Update

I was able to get some work done with DotNetFish over the weekend. This was the first weekend in almost a month that I was able to work on the project. If you remember from my last post, I had a short bucket list of items that I needed to implement. First on the list is getting the edge tiles land/water orientation to be correct. Here is how I planned to implement this.

  • Each map graphics tile would need to know if its edge was water/land or contains both.
  • when determining which tile to place, I need to check the edges to determine a match
Its funny how something that seems simple, takes so much longer. After modifying the client to accept the new graphics tile I needed to re-write the .csv file to inclued the edge type information. This proved to be an repetitive task. After fiddling with it for a bit, I decided that using an xml file would work much better. After thinking about it even more, I decided that having a program generate the xml file would work even better. So, I wrote a new application called maptilebuilder that processes a .png file. It steps through each tile in the image and allows you to manually set the edge points as well as the edge type. A future improvement would be to have it generate the xml file with minimal input, but that can wait.

So, even though I only got step 1a finished, it still is progress. I've got all of the changes in place for the second step, I just need to finish the code that chooses based on the edge type. 


Thursday, February 10, 2011

DotNetFish - When Progress Hurts

Spent some time working on the project recently. I was able to implement the following features

  • Level editor now displays the map properly
  • You can use the arrow keys to scroll around the map
Its great to be able to finally visualize how the map actually looks. The downside, is that now I know how bad the map actually looks. Being able to view the tiles has brought several problems to my attention. Here are the things I need to get fixed.
  • Need to get the land/water on the edge tiles to orientate properly.
  • Need to figure out why the tiles don't match the area I selected
  • Need to improve the tile selection process
Those are the three pressing issues. Hopefully next time progress wont hurt so much!

You can grab the latest from https://github.com/aaronmell/DotNetFish/

Friday, January 28, 2011

DotNetFish - Lack of Motivation

Its been hard to get motivated to work on the project lately. I was sick with the stomach flu at the first of the month, and that really took the wind out of my sails. However, I was able to get one more thing working. Maps are now saved after creation, and can be loaded.

Here is a short rundown of the most critical tasks I need to finish
  • I need to get tile rendering completed on the editor. Once I have this done, I will be able to view the map.
  • I need to create a way to define a spawn point on the map.
Once I finish those two tasks on the editor. I will be able to commence work on the client. Here's the short list of what I need to do there.
  • Get the rendering completed
  • Get the boat to move
  • Get the boat to be able to fish
Once I've got that done, I should have a minimally viable product for testing. This means that I will have a full tool chain, and can start implementing features. There are a few other things that I need to work on though

  • Need to refactor the tile creation process to take into account the start and end points of land
  • Need to refactor all of the WPF projects to use a pattern for the UI. Will either use MVP or MVVM pattern
The game solution will probably not be refactored to use MVP or MVVM, because I plan to use it from the start, and it should be simple to go back and get the others done. Its just a bit tedious, and that sucks the motivation right out of you when things are tedious. 

Hopefully February will be a better month.

Sunday, January 9, 2011

DotNetFish - Progress is being made

You just can't see it yet. I got the first iteration of the tiling process push to github. However, it is still rough. I added a few safeguards to show a red tile if there was an error, just so I could get some other work done. The initial map tiler does the following logic to assign a tile to an edge. I have a csv file that defines the edge points for each tile in the tileset. 1. check the edges for changes between water and land. 2. take these points and convert them to the 12 possible points that can be used on a tile. 3. find the tile that matches those 2 points and assign that tile to the arraylist There are a couple of problems with this that I have found. 1. It might be possible to have more or less than 2 edges. This can be an issue with really small streams having 2 edges, and also some tiles with water on the edge only have 1 edge depending on the color. So any tiles like that will be red. I will probably need to add some 2 edge tiles, but that can be a future improvement. Dealing with 1 edge tiles is more tricky, and I haven't figured out a good method to deal with them yet, other than expanding the range of colors that count as water. 2. Edge tiles might not match up properly. The next iteration needs to do things differently. Right now it doesn't check the surrounding tiles to see where its edges are. It needs to do this, and if a surrounding tile has an edge, it needs to use it first. This should prevent any issues with tiles not lining up properly, as long as the CSV file is correct. (I probably need to write a small program to generate the CSV automatically). The next step is to get the Editor to save/load the map, and get it to show the map in the editor. Once I get the tiler finished, I'll try to put up another post showing how that works in code.

Saturday, January 1, 2011

DotNetFish - A Change of Course

Last night I was looking at some data. My goal is to provide a map that is very close to the actual size of the lake. I came to a very cold and clear realization, that the map tiler as a stand alone piece of software will never work in that regard. This holds very true when you look at larger lakes in the US such as Sam Rayburn in Texas. Don't even ask about how big lake superior is(huge!). I always thought that it would be nice to allow the user to be able to import a map they draw into the program, but I don't think this is feasible. Besides, if I want this game to be as realistic as possible, then I want to be able to fish on real lakes. So, with that being said, I'm going to remove the MapTiler project completely, and integrate it into the Level Designer, where is should have been all along. I hope, and this is a big hope, that the Gmap controls for WPF are just as easy to use. The work I posted yesterday won't be lost though. I will reuse nearly all of it. The only different is that I will remove the black to white step, and no longer be saving an image. So I am removing a step here, which is always good. It has been said that it is hard to design a simple solution. I can definitely agree with that. Hopefully, the solution I have now is 1 step simpler than the last one. *Update* If you check out github, MapTiler is now gone, and all of the code has been integrated into Level Designer. It compiles, but that's about it. By the end of the day tomorrow, I should have level designer sorted out, and have it actually outputting some useful data.

Friday, December 31, 2010

DotNetFish - Optimizing the Tiling Routines

I made an optimization to the tiling routine and pushed the changes up to Github. Let me take a minute to explain what change I made. Orginally, I was writing each tile to the large bitmap, and then going through the bitmap pixel by pixel, and determining if the pixel needed to be set to white or black. Now I am doing the following.
  1. Create two new bitmaps, all black and all white
  2. instead of writing the tile directly to the bitmap, manipulate the 256x256 tile
  3. check the edges of the bitmap for water
  4. if the bitmap edge has both water and land, then you have to scan each pixel and change it from black to white. 
  5. otherwise you can just use the all black or all white bitmaps.
This has a few advantages. Instead of having to check  65k pixels per tile for tiles that only have all water or all land, you only have to check 1024. Now then, This takes me pretty far along the path of optimization. Its still a bit slow though. In order to improve the speed I will need to drop into using, pointers, and bitmapdata. I suggest you take a look at this article Bob Powell's website Understanding Locking Bits and The BitmapData Class He has a very good faq regarding GDI+ and I have used it every time I have ever had to manipulate graphics in GDI+. Its a bit complicated, but basically, we are going to manipulate an array of pixel values instead of the pixels themselves, which cuts out a bunch of the overhead. Here is the relevant code to get the bitmap data
BitmapData bmpData = bitmap.LockBits(
    new Rectangle(0, 0, bitmap.Width, bitmap.Height),
    ImageLockMode.ReadWrite,
    PixelFormat.Format32bppArgb);
            
//This is a pointere that referenece the location of the first pixel of data 
System.IntPtr Scan0 = bmpData.Scan0;

//calculate the number of bytes
int bytes = bmpData.Stride * bitmap.Height;

//An array of bytes. Just remember that each pixel format has a different number of bytes.
//In our case, the number of bytes is 4 per pixel or RGBA. 
byte[] rgbValues = new byte[bytes];

//Safely copying the data to a managed array
System.Runtime.InteropServices.Marshal.Copy(Scan0,
                rgbValues, 0, bytes);
The above code gets the bitmap data. After that we would loop through the edges looking for the different tile types. The important line here is the position, that makes sure we grab the right values for each pixel
//Loop though all of the pixels on the Y edge
for (int y = 0; y < bitmap.Height; y+=255)
{
    for (int x = 0; x < bitmap.Width; x+=5)
    {
        int position = (y * bmpData.Stride) + (x * 4);

        retval = IsWater(rgbValues[position], rgbValues[position + 1], rgbValues[position + 2]);

        if (retval == true)
            hasWater = true;
        else 
            hasLand = true; 

        if (hasLand && hasWater)
            break;
    }
        if (hasLand && hasWater)
            break;
}
We do the same thing for the x edges if we havent already detected both water and land.. Lastly, here is how we set the color values.
private void PaintTile(int height, int width, ref byte[] rgbValues, int stride)
{
    for (int x = 0; x < width; x++)
    {
        for (int y = 0; y < height; y++)
        {
            int position = (y * stride) + (x * 4);

            if (rgbValues[position] == 204 && rgbValues[position + 1] == 179 && rgbValues[position + 2] == 153)
                rgbValues[position] = rgbValues[position + 1] = rgbValues[position + 2] = 255;
            else
                rgbValues[position] = rgbValues[position + 1] = rgbValues[position + 2] = 0;
        }
    }
} 
I used a reference type here instead of a value. Its a better choice here since as soon as this method is called the data gets saved back into the bitmap using the following code
//Save the manipulated data back to the bitmap.
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, Scan0, bytes);
bitmap.UnlockBits(bmpData);
Make sure you always call UnlockBits when you are done! Go grab commit 3a8f1b95c1a6fd1bd1e8053 if you want to see what the project looks like up to this point.

Tuesday, December 28, 2010

DotNetFish - Level Designer Pushed

Got the basics of the level designer pushed up. It only properly sets all water or all land tiles for the time being. I need to rework my tile size though. Next up will be to get the other tiles working properly. Once I get this done I plan to do a post about it.
https://github.com/aaronmell/DotNetFish/commit/daf9dee014baa1e6821846ec6a0806bd05ab38ef

if your interested

Monday, December 20, 2010

DotNetFish - Map Tiling Pushed

Just wanted to write a short post to let everyone know that the Tiling program is up.
You can grab the latest from GitHub.

https://github.com/aaronmell/DotNetFish/

I still need to make a few improvements to the program, including optimizing the color transform and removing a bunch of commented code that is no longer needed.

Once I get that tidied up, I will start work on the program that will actually turn the image file into an actual map.

Tuesday, November 30, 2010

DotNetFish Part 1 - Using Gmap.net to create the map image.

Now its time to get down to business and do some actual work. Below is the technology stack I am planning to use for this project.

I have decided to use Gmap.Net to help me build the map. If you havent heard of this great project, you should go check them out. GMap.Net This project makes it very easy to display a map from google, or any number of mapping servers. Getting setup was dead easy. For this tool, I just went with a standard Winform project, This will only be used internally, and no reason to spend time learning WPF right now when I don't need it.

Now then, lets look at what is needed to get Gmap.net Running

  1. Grab the source code of the latest stable branch from the Gmap.Net repository.
  2. Load the source code into visual studio and build the project
  3. You can skip the first two steps, and just grab the binaries, but those don't come with examples, which you'll probably want.
  4. Add the Gmap.Net.Core.Dll and the Gmap.Net.WindowsForms.dll to your references. (Make sure that if you copy the refrences to your project directory, that the System.Data.Sqlite.dll is in the same directory as the two Gmap Dll's
  5. Add the Gmap.WindowsForms.dll to your toolbox, so you can have access to the Gmap map control
Once you have done all of this, you should be able to add a Map control to your form. In the Constructor for your form, you will want to add this code.


// config map 
MainMap.Position = new PointLatLng(35.2276723549358, -97.22351074);
MainMap.MapType = MapType.GoogleMap;
MainMap.MinZoom = 1;
MainMap.MaxZoom = 17;
MainMap.Zoom = 10; 

That should get a basic map up and running on your form. Now for my application I need to do the following

  1. Allow the user to select a lake with a selection tool
  2. After the user has selected a lake, build an image from the tileset.
  3. Do some processing of the image. (Turn the image black and White)
We really don't need to know how the map stuff works, except that the map is divided up into tiles. The way the app will work, is when the user selects a lake, the start and end points longitude and latitude is saved. Gmap already provides a nice selection tool by holding the shift key. This allows us to zoom in on the map using shift. I don't need the zoom ability, but the selection box is perfect. So I modified the Gmap code to not zoom in when using the selection tool. Easy as pie.


Here is the code I am using to get the Tile Coordinates

PureProjection prj = null;
int maxZoom;
int zoom = 15;
GMaps.Instance.AdjustProjection(type, ref prj, out maxZoom);
GMaps.Instance.Mode = AccessMode.ServerOnly;
GMaps.Instance.ImageProxy = new WindowsFormsImageProxy();
//This line converts the LatLng to the Proper TileXY given the level of zoom.
//Remember that each level of zoom has a different TileXY coordinate for a given Lat and Lng
prj.FromPixelToTileXY(prj.FromLatLngToPixel(p.Lat, p.Lng, zoom))


Once we know which tiles we need, it will be very simple to get those tiles and stitch them together into the image.

Here is the code that does the stitching.
using (Bitmap bmp = new Bitmap(tilesWide * 256, tilesHigh * 256))
            {
                for (int x = 0; x < tilesWide; x++)
                {
                    for (int y = 0; y < tilesHigh; y++)
                    {
                        using (Graphics gfx = Graphics.FromImage(bmp))
                        {
                            Exception ex;
                            WindowsFormsImage tile = GMaps.Instance.GetImageFrom(type, new GPoint(startTile.X + x, startTile.Y - y), zoom, out ex) as WindowsFormsImage;

                            if (ex != null)
                            {
                                e.Cancel = true;
                                return;
                            }
                            else if (tile != null)
                            {
                                using (tile)
                                {
                                    gfx.DrawImage(tile.Img, x * 256, (tilesHigh - y - 1) * 256);
                                   
                                }
                            }
                        }
                    }
                }

Tuesday, November 2, 2010

Creating a Game Part 1

I've decided to write a series of posts about creating a game using the .net platform. Why do this? because game development has always fascinated me. Also, getting this out in public is motivation to finish something and ship it. That's the most difficult thing to do in software development, is to ship a product. I've read that if you are overweight, a good way to lose weight it to post online your weight each week or so, as you attempt to lose weight. It's great motivation to do so, and I am hoping that this series of posts will motivate me to produce something tangible.

Now that we have the fancy introduction out of the way, its time to get down to business. For this project, I have chosen WPF as my development platform. It seems like a fairly logical choice over something like Silverlight. After doing a lot of research and thinking, I just came to the conclusion that Silverlight is not the perfect fit as a platform for what I wish to do.

So, what kind of game do you plan to write? Well, I plan to create a fishing game. That's right I said fishing game, big whoop, you wanna fight? In all seriousness, its a subject matter that interest me, and I haven't see any games like the kind of game I want to create. The basic premise of the game, is that you control a fishing boat, and you fish on lakes with other people or just by yourself in a single player mode.

So before we can write a single line of code, we probably should do some planning, and decide on what minimum set of features we need in order to release something that works. In the beginning, I am going to focus on the single player part of the game. Below is the things I need to get working first
  • Create an image that represents a lake. This will be used to build a map/level of a lake that is fishable
  • Take an image that represents a lake, and turn it into a map/level, and save it
  • Load a saved map into the app
  • Get the boat moving around the map.
  • Allow the player to cast for fish.

 I plan to work on the tools to build the levels first, the reason being, is that I plan to add a lot of detail to the maps as we go along, and I want to make it a painless as possible to regenerate new levels as needed.