Tile[0,0] tileIndex=0
Tile[0,1] tileIndex=1
Tile[9,9] tileIndex=100 and so on...
private Color GetMouseMapTileColor(int tileIndex, byte col, byte row){short red = 0;short green = 0;short blue = 0;if(_16BitColor ){// Because of the format 5-6-5 for 16bit color yields 65536 possible colors// 5 bits for red = 32 possible variants (31 shades, 1 with no red) // 6 bits for green = 64 possible variants (63 shades, 1 with no green)// 5 bits for blue = 32 possible variants (31 shades, 1 with no blue)// The 65536 possible colors comes from the all the possible // red\green\blue combinations//// This would allow for a map of size 256 x 256 if 1 color were to be used// for each tile. I have capped the map size @ 200 x 200. With a tile size// of 64 x 32 pixels, a map size of 12800 x 6400 pixels is possible. I think// this is plenty big enough. At my current scroll rate, it takes nearly// 90 seconds to scroll the width of the map.// // --- RED ---// For every 2048 tiles increment the red shade. This is derived as follows:// Because there are a possible 32 blue shades for every green shade and a// possible 64 green shades. This yields 2048 possible blue\green// combinations. The tile color is kept unique by incrementing the red// value when these combinations are exhausted. The 1+ is done so that // the 0,0 tile is not completely black. Black is reserved for anything// off the map. With only 32 variations of red possible a multiplier of 8 // is used in order to map it properly into a 32bit color's value. This// is necessary because I am using: Color.FromArgb(red,green,blue) to// generate the tile color. This returns a 32bit color. red = (short)((1+(tileIndex/2048)) * 8); // --- GREEN ---// Because there a possible 2048 possible green\blue combinations ensure// that the green will roll over when this number of tiles (or a multiple of)// is reached. Because there are a possible 64 green variations div this// tile by 32 (2048/32) = 64. The multiplier is used for the proper mapping // into the call to create the tile color. green = (short)(((tileIndex%2048)/32) * 4); // --- BLUE ---// Because there are 32 possible blue variants ensure we roll over the value// once it reaches 32. Again the multiplier is used for the proper mapping // into the call to create the tile color. blue = (short)((tileIndex%32) * 8); }else{ red = 128; green = (short)col; blue = (short)row;} return Color.FromArgb(red,green,blue);}
Now, as the mouse is moving over the map, the following code is used to determine the tile the mouse is over. Note: As the color is being placed into a tile, I store off the location of the tile into an array (colorIndexToTile[]) that is indexed by the tile's tileIndex.
if( _16BitColor ){ // Get the pixel color from the mouse map surface the cursor // is currently over (e.X and e.Y is the mouse position) ushort[] pixel16 = (ushort[])MMBackBuffer.LockRectangle(typeof(ushort), new Rectangle(e.X,e.Y,1,1), LockFlags.ReadOnly, new int[]{1}); MMBackBuffer.UnlockRectangle(); // Strip out the RGB components from the returned pixel // Anything you would want to know about how and why I do this can be found here: // www.gamedev.net/reference/articles/article1563.asp int red = (pixel16[0])>>11; int green = ((ushort)((pixel16[0]>>5)<<10))>>10; int blue = (ushort)(pixel16[0]<<11)>>11; // Check to see if we are over a tile if((red | green | blue) !=0) { // remove 1 from the red to compensate for it being added // in the GetMouseMapTileColor() call int tileIndex = (red-1)*2048 + green*32 + blue; newMousePosition = _colorIndexToTile[tileIndex]; }}else{ // Get the pixel color from the mouse map surface the cursor // is currently over int[] pixel32 = (int[])MMBackBuffer.LockRectangle(typeof(int), new Rectangle(e.X,e.Y,1,1), LockFlags.None, new int[]{1}); MMBackBuffer.UnlockRectangle(); c = Color.FromArgb(pixel32[0]); // if the cursor is not over any tiles then don't do anything // Note: the value 128 is the default set for the red component in the // Initialize{maptype}Map() procedures // A nice side effect of this short circuit is that when the mouse // is not over any tiles, the last tile selected remains highlighted if(c.R == 128) newMousePosition = new Point(c.G,c.B);}
I hope this helps. Let me know if anything is not clear or a possible better solution might exist. Again, it was something I didn't want to do (or rather didn't think about) but felt the engine should be compatible with this color depth. It was the first solution that popped into my mind.
Edit: Cut down tabs so code is at least viewable.