I'd still like to add the following features before going to work on the game itself.
- Need the ability to change a tile on the map
- Be able to navigate through the error tiles
- Need to be able to runs a check to make sure every edge tile is connected
public static readonly DependencyProperty CurrentPointCommandProperty =
DependencyProperty.Register(
"CurrentPointObject",
typeof(Point),
typeof(MapCanvas),
new PropertyMetadata(new PropertyChangedCallback(OnPropertyChanges))
);
private static void OnPropertyChanges(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
(obj as MapCanvas).InvalidateVisual();
}
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.
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.
// config map MainMap.Position = new PointLatLng(35.2276723549358, -97.22351074); MainMap.MapType = MapType.GoogleMap; MainMap.MinZoom = 1; MainMap.MaxZoom = 17; MainMap.Zoom = 10;
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))
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);
}
}
}
}
}