最近做了一个真实二维导航地图开发,写点心得和总结,希望对刚开始做这方面的童鞋有所启发。
先来看看最终效果,包括在线和离线两种显示:
1)在线模式,必须连接互联网
电子地图
卫星地图
2)离线模式 ,主要是使用本地离线瓦片
电子地图
卫星地图
3)实现功能和步骤:
a、地图瓦片主要来源于GMap,这个工具挺好用的,能够下载到的瓦片基本都能用,前期准备工作就是使用该工具下载好你想要显示的瓦片层级,并拷将瓦片拷贝到指定的路径下;
b、在GMap目录下找到地图相关的所有动态库.dll,拷贝到你已经创建好的Unity项目中;
c、使用刚刚拷贝的动态库进行编程,绘制瓦片使用底层Graphics.DrawTexture函数;
d、基本脚本写两个就行,一个写界面响应鼠标和按钮,一个用于绘制瓦片和地图刷新;
其中瓦片绘制部分的核心代码分享出来:
/// <summary>
/// 绘制地图瓦片
/// </summary>
protected virtual void DrawMap()
{
// 判断是否更新边界
if (Core.updatingBounds || MapProvider == EmptyProvider.Instance || MapProvider == null)
{
return;
}
// 瓦片调用锁
Core.tileDrawingListLock.AcquireReaderLock();
Core.Matrix.EnterReadLock();
try
{
//int index = 0;
// 遍历瓦片绘制的列表
foreach (var tilePoint in Core.tileDrawingList)
{
Core.tileRect.Location = tilePoint.PosPixel;
// 设置瓦片偏移(在坐标系中的像素偏移)
Core.tileRect.OffsetNegative(Core.compensationOffset);
// 瓦片找到标志
bool found = false;
// 根据信息从瓦片缓存区取出瓦片
Tile t = Core.Matrix.GetTileWithNoLock(Core.Zoom, tilePoint.PosXY);
// 瓦片不为空
if (t.NotEmpty)
{
foreach (GMapImage img in t.Overlays)
{
if (img == null || img.Img == null)
{
continue;
}
if (!found)
found = true;
// 获取纹理
Texture2D tileTexture2D = new Texture2D((int)Core.tileRect.Width, (int)Core.tileRect.Height);
tileTexture2D.LoadImage(img.Data.ToArray());
if (!img.IsParent)
{
if (!MapRenderTransform.HasValue)
{
long y = Core.tileRect.Y + Core.renderOffset.Y;
// 当瓦片上边缘在initTopMenuHeight以内,下边缘在initTopMenuHeight以外
if (y < initTopMenuHeight && (y + Core.tileRect.Height) > initTopMenuHeight)
{
// 将要显示区域
Rect showRect = new Rect(0, 0, 1f, Mathf.Abs((y + 256 - initTopMenuHeight) / (float)256));
// 将要显示高度
long showHeight = y + 256 - initTopMenuHeight;
Graphics.DrawTexture(
new Rect(Core.tileRect.X + Core.renderOffset.X, initTopMenuHeight, Core.tileRect.Width, showHeight), // 左上角坐标和宽高
tileTexture2D,
showRect,
0, 0, 0, 0, null);
}
else if (y >= initTopMenuHeight || (y + Core.tileRect.Height) <= 0)
{
Graphics.DrawTexture(new Rect(Core.tileRect.X + Core.renderOffset.X, Core.tileRect.Y + Core.renderOffset.Y, Core.tileRect.Width, Core.tileRect.Height),
tileTexture2D);
}
else
{
}
}
}
else
{
// 将计算移动到加载线程
System.Drawing.RectangleF srcRect = new System.Drawing.RectangleF((float)(img.Xoff * (img.Img.Width / img.Ix)), (float)(img.Yoff * (img.Img.Height / img.Ix)), (img.Img.Width / img.Ix), (img.Img.Height / img.Ix));
System.Drawing.Rectangle dst = new System.Drawing.Rectangle((int)Core.tileRect.X, (int)Core.tileRect.Y, (int)Core.tileRect.Width, (int)Core.tileRect.Height);
Graphics.DrawTexture(new Rect(dst.X, dst.Y, srcRect.Width, srcRect.Height), tileTexture2D);
}
Destroy(tileTexture2D);
}
}
// 如果获取的瓦片为空,则使用低版本的替换
else if (enableLowPixelTiles && MapProvider.Projection is MercatorProjection)
{
int zoomOffset = 1;
Tile parentTile = Tile.Empty;
long Ix = 0;
while (!parentTile.NotEmpty && zoomOffset < Core.Zoom && zoomOffset <= LevelsKeepInMemmory)
{
Ix = (long)Math.Pow(2, zoomOffset);
parentTile = Core.Matrix.GetTileWithNoLock(Core.Zoom - zoomOffset++, new GPoint((int)(tilePoint.PosXY.X / Ix), (int)(tilePoint.PosXY.Y / Ix)));
}
if (parentTile.NotEmpty)
{
long Xoff = Math.Abs(tilePoint.PosXY.X - (parentTile.Pos.X * Ix));
long Yoff = Math.Abs(tilePoint.PosXY.Y - (parentTile.Pos.Y * Ix));
// render tile
{
//foreach (GMapImage img in parentTile.Overlays)
//{
// if (img != null && img.Img != null && !img.IsParent)
// {
// if (!found)
// found = true;
// System.Drawing.RectangleF srcRect = new System.Drawing.RectangleF((float)(Xoff * (img.Img.Width / Ix)), (float)(Yoff * (img.Img.Height / Ix)), (img.Img.Width / Ix), (img.Img.Height / Ix));
// System.Drawing.Rectangle dst = new System.Drawing.Rectangle((int)Core.tileRect.X, (int)Core.tileRect.Y, (int)Core.tileRect.Width, (int)Core.tileRect.Height);
// g.DrawImage(img.Img, dst, srcRect.X, srcRect.Y, srcRect.Width, srcRect.Height, GraphicsUnit.Pixel, TileFlipXYAttributes);
// g.FillRectangle(SelectedAreaFill, dst);
// }
//}
}
}
}
绘制网格线
//if (ShowTileGridLines)
//{
// g.DrawRectangle(EmptyTileBorders, (int)Core.tileRect.X, (int)Core.tileRect.Y, (int)Core.tileRect.Width, (int)Core.tileRect.Height);
// {
// g.DrawString((tilePoint.PosXY == Core.centerTileXYLocation ? "CENTER: " : "TILE: ") + tilePoint, MissingDataFont, Brushes.Red, new RectangleF(Core.tileRect.X, Core.tileRect.Y, Core.tileRect.Width, Core.tileRect.Height), CenterFormat);
// }
//}
}
}
finally
{
Core.Matrix.LeaveReadLock();
Core.tileDrawingListLock.ReleaseReaderLock();
}
}
如果有需要的童鞋可以关注本号,后续我会继续更新三维地形和二维地形的分享^o^!!!!!!!!!。