要生成POI点,先生成三个类,MapBoxManager(管理类),MapHelper(帮助类),Marker(自身数据类),这三个类的目的是处理POI数据显示,管理的,下面我会一一介绍这三个类的作用。
首先,是管理类--MapBoxManager
它的作用,存储生成的POI点,对POI进行增删查改,以及相关信息显示。。。
public class MapBoxManager : MonoBehaviour {
public AbstractMap map;//地图
public Camera mapCamera;//地图相机
public Transform POIContainer;//装POI容器
[SerializeField]
private GameObject prefab;//POI预制体
[HideInInspector]
public List<Marker> markers;//存储所有的POI
public float hight = 0;//POI 的海拔高度
private float _scale = 1f;//POI缩放比例系数
[SerializeField]
private float initZoom = 12;//初始化比例尺
public static MapBoxManager instance;
private void Awake()
{
instance = this;
}
// Use this for initialization
void Start () {
markers = new List<Marker>();
map.SetZoom(initZoom);
//对地图做任何事件操作都会更新POI
map.OnUpdated += OnUpdatedMarkerts;
}
private void OnDestroy()
{
map.OnUpdated -= OnUpdatedMarkerts;
}
/// <summary>
/// 更新POI位置状态
/// </summary>
private void OnUpdatedMarkerts()
{
if (markers != null && markers.Count > 0)
{
//POI大小的比例随地图大小变动
float curretValue =( map.Zoom - initZoom)*0.5f;
if (curretValue>0.5f)
{
curretValue = 0.5f;
}
else if (curretValue < -0.5f)
{
curretValue = -0.5f;
}
Debug.Log(curretValue);
foreach (var m in markers)
{
//经纬度坐标转Unity世界坐标
var pos = MapHelper.instance.GeoToWorldPositon(m.longitude, m.latitude);
m.transform.localPosition = new Vector3(pos.x, hight, pos.z);
var scale = m.transform.localScale;
m.transform.localScale = new Vector3(1+ curretValue, 1, 1 + curretValue);//这里初始化时默认POI大小为 Vector3.one
}
}
}
/// <summary>
/// 查找一个POI
/// </summary>
public Marker FindMarker(string uuid)
{
return markers.Find(x => x.uuid == uuid);
}
/// <summary>
/// 删除POi点
/// </summary>
public void RemoveMarker(string uuid)
{
var m= markers.Find(x=> x.uuid == uuid);
RemoveMarker(m);
}
/// <summary>
/// 删除POI点
/// </summary>
public void RemoveMarker(Marker m)
{
if (markers!=null&&markers.Count>0)
{
markers.Remove(m);
}
}
/// <summary>
/// 创建POI点
/// </summary>
public void CreateMarker(Marker m)
{
CreateMarker(m.uuid, m.type, m.longitude, m.latitude, m.customData);
}
/// <summary>
/// 创建POI点
/// </summary>
public void CreateMarker(string uuid,string type,double lon,double lat,object custom)
{
var current= Instantiate(prefab, POIContainer);
Marker m= current.AddComponent<Marker>();
m.uuid = uuid;
m.type = type;
m.latitude = lat;
m.longitude = lon;
m.customData = custom;
m.Init += Init;
m.OnEnter += OnEnter;
m.OnExit += OnExit;
m.OnLeftClick += OnLeftClick;
m.OnRightClick += OnRightClick;
m.OnDoubleClick += OnDoubleClick;
m.OnDrag += OnDrag;
m.OnEndDrag += OnEndDrag;
m.OnDestory += OnDestory;
markers.Add(m);
}
private void Init(MarkerBase obj)
{
Debug.Log("初始化!");
var pos = MapHelper.instance.GeoToWorldPositon(obj.longitude, obj.latitude);
obj.transform.localPosition = new Vector3(pos.x, hight, pos.z);
}
private void OnEnter(MarkerBase obj)
{
Debug.Log("移入!");
}
private void OnExit(MarkerBase obj)
{
Debug.Log("移出!");
}
private void OnLeftClick(MarkerBase obj)
{
Debug.Log("左击!");
}
private void OnRightClick(MarkerBase obj)
{
Debug.Log("右击!");
}
private void OnDrag(MarkerBase obj)
{
Debug.Log("拖拽中!");
}
private void OnEndDrag(MarkerBase obj)
{
Debug.Log("拖拽结束!");
}
private void OnDoubleClick(MarkerBase obj)
{
Debug.Log("双击!");
}
private void OnDestory(MarkerBase obj)
{
Debug.Log("销毁!");
}
}
其次,是帮助类——mapHelper
它存在的目的是:对坐标转化,获取,
public class MapHelper : MonoBehaviour {
public static MapHelper instance;
private AbstractMap _map;
private Camera mapCamera;
private void Awake()
{
instance = this;
}
private void Start()
{
_map = MapBoxManager.instance.map;
mapCamera = MapBoxManager.instance.mapCamera;
}
/// <summary>
/// 设置2D地图的中心点
/// </summary>
/// <param name="key"></param>
/// <param name="param"></param>
private void SetMapCenter(double lon, double lat)
{
Vector2d latlng = new Vector2d
{
x = lat,
y = lon,
};
_map.UpdateMap(latlng);
}
/// <summary>
/// 经纬度坐标转Unity世界坐标
/// </summary>
public Vector3 GeoToWorldPositon(double lon,double lat)
{
Vector2d location = new Vector2d()
{
x = lat,
y = lon
};
//地理坐标转世界坐标
return _map.GeoToWorldPosition(location, true);
}
/// <summary>
/// Unity世界坐标转世界坐标
/// </summary>
public void WorldToGeoPositon(Vector3 position, out double lon,out double lat)
{
Vector2d location = _map.WorldToGeoPosition(position);
lon = location.y;
lat = location.x;
}
/// <summary>
/// 经纬度转换屏幕坐标
/// </summary>
public Vector3 GetScreenPoint(double lng, double lat)
{
Vector2d latlng = new Vector2d
{
x = lat,
y = lng,
};
var pos = _map.GeoToWorldPosition(latlng);
pos.y = 0;
Vector3 screenPos = mapCamera.WorldToScreenPoint(pos);
return new Vector2(screenPos.x, screenPos.y);
}
/// <summary>
/// 世界坐标转屏幕坐标
/// </summary>
public Vector2 GetScreenPoint(Vector3 pos)
{
Vector3 screenPos = mapCamera.WorldToScreenPoint(pos);
return new Vector2(screenPos.x, screenPos.y);
}
/// <summary>
/// 世界坐标转经纬度
/// </summary>
public void GetLatlng(Vector3 position, out double lng, out double lat)
{
Vector3 mousePosScreen = GetScreenPoint(position);
mousePosScreen.z = mapCamera.transform.localPosition.y;
var pos = mapCamera.ScreenToWorldPoint(mousePosScreen);
Vector2d location = _map.WorldToGeoPosition(pos);
lng = location.y;
lat = location.x;
}
/// <summary>
/// 屏幕坐标转获取经纬度
/// </summary>
public void GetLatlng(Vector2 mousePositiong, out double lng, out double lat)
{
Vector3 mousePosScreen = mousePositiong;
mousePosScreen.z = mapCamera.transform.localPosition.y;
var pos = mapCamera.ScreenToWorldPoint(mousePosScreen);
Vector2d location = _map.WorldToGeoPosition(pos);
lng = location.y;
lat = location.x;
}
}
最后是POI自身的数据类——marker
这里为方便扩展,我做了个基类markerBase
public class MarkerBase : MonoBehaviour {
/// <summary>
/// 唯一标识符
/// </summary>
public string uuid { get; set; }
/// <summary>
/// 名字
/// </summary>
public string name { get; set; }
/// <summary>
/// 类型
/// </summary>
public string type { get; set; }
/// <summary>
/// 经度
/// </summary>
public double longitude { get; set; }
/// <summary>
/// 纬度
/// </summary>
public double latitude { get; set; }
/// <summary>
/// 对象类
/// </summary>
public object customData { get; set; }
/// <summary>
/// 初始化
/// </summary>
public Action<MarkerBase> Init;
/// <summary>
/// 移入事件
/// </summary>
public Action<MarkerBase> OnEnter;
/// <summary>
/// 移出事件
/// </summary>
public Action<MarkerBase> OnExit;
/// <summary>
/// 双击事件
/// </summary>
public Action<MarkerBase> OnDoubleClick;
/// <summary>
/// 左击击事件
/// </summary>
public Action<MarkerBase> OnLeftClick;
/// <summary>
/// 左击击事件
/// </summary>
public Action<MarkerBase> OnRightClick;
/// <summary>
/// 拖拽开始事件
/// </summary>
public Action<MarkerBase> OnBeginDrag;
/// <summary>
/// 拖拽中事件
/// </summary>
public Action<MarkerBase> OnDrag;
/// <summary>
/// 拖拽结束事件,
/// UI:鼠标拖拽已经封装好 直接在这对拖拽结束进行复制即可
/// </summary>
public Action<MarkerBase> OnEndDrag;
/// <summary>
/// 初始化
/// </summary>
public Action<MarkerBase> OnDestory;
}
然后是挂载到POI点身上的marker类,
public class Marker : MarkerBase,IPointerClickHandler, IBeginDragHandler, IEndDragHandler, IDragHandler, IPointerEnterHandler, IPointerExitHandler
{
//XXX:拖拽物体需要检测
/// <summary>
/// 目标对象的屏幕坐标
/// </summary>
private Vector3 targetScreenPoint;
/// <summary>
/// 获得鼠标的位置和cube位置差
/// </summary>
private Vector3 offset;
private bool isDrag = false;
private void Start()
{
//初始化
if (base.Init != null) base.Init(this);
}
/// <summary>
/// 移入
/// </summary>
void IPointerEnterHandler.OnPointerEnter(PointerEventData eventData)
{
if (base.OnEnter != null) base.OnEnter(this);
}
/// <summary>
/// 移出
/// </summary>
void IPointerExitHandler.OnPointerExit(PointerEventData eventData)
{
if (base.OnExit != null) base.OnExit(this);
}
/// <summary>
/// 开始拖拽
/// </summary>
void IBeginDragHandler.OnBeginDrag(PointerEventData eventData)
{
if (base.OnBeginDrag != null) base.OnBeginDrag(this);
}
/// <summary>
/// 拖拽中
/// </summary>
void IDragHandler.OnDrag(PointerEventData eventData)
{
if (CheckGameObject())
{
var pos = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, targetScreenPoint.z));
offset = this.transform.position - pos;
}
if (isDrag)
{
//当前鼠标所在的屏幕坐标
Vector3 curScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, targetScreenPoint.z);
//把当前鼠标的屏幕坐标转换成世界坐标
Vector3 curWorldPoint = Camera.main.ScreenToWorldPoint(curScreenPoint);
this.transform.position = curWorldPoint + offset;
if (base.OnDrag != null) base.OnDrag(this);
}
}
/// <summary>
/// 拖拽结束
/// </summary>
void IEndDragHandler.OnEndDrag(PointerEventData eventData)
{
if (base.OnEndDrag != null) base.OnEndDrag(this);
}
/// <summary>
/// 移入
/// </summary>
void IPointerClickHandler.OnPointerClick(PointerEventData eventData)
{
if (eventData.button == PointerEventData.InputButton.Right)
{
if (base.OnRightClick != null) base.OnRightClick(this);
}
else if (eventData.button == PointerEventData.InputButton.Left)
{
//XXX:双击一定会触发单击
if (base.OnLeftClick != null) base.OnLeftClick(this);
if (eventData.clickCount==2)
{
if (base.OnDoubleClick != null) base.OnDoubleClick(this);
}
}
}
private void OnDestroy()
{
//被销毁时
if (base.OnDestory != null) base.OnDestory(this);
}
/// <summary>
/// 检查是否点击到cbue
/// </summary>
/// <returns></returns>
bool CheckGameObject()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hitInfo;
//XXX:POI物体的layer层设置为 POI
if (Physics.Raycast(ray, out hitInfo, Mathf.Infinity, LayerMask.GetMask("POI")))
{
isDrag = true;
//得到射线碰撞到的物体
targetScreenPoint = Camera.main.WorldToScreenPoint(this.transform.position);
return true;
}
return false;
}
}
到这里基本已经成了,这时候需要把管理类,帮助类挂到地图上,创建一个POI预制体把marker.cs挂上,再写个测试类就行了。
测试类:
public class MapBoxTest : MonoBehaviour
{
public Transform button;
public Camera UICamera;
public RectTransform panel;
private void Start()
{
GameObject objDrag = null;
var self = button.gameObject.AddComponent<EventTrigger>();
self.triggers = new List<EventTrigger.Entry>(3) {
new EventTrigger.Entry()
{
eventID = EventTriggerType.BeginDrag,
callback = new EventTrigger.TriggerEvent()
},
new EventTrigger.Entry()
{
eventID = EventTriggerType.Drag,
callback = new EventTrigger.TriggerEvent()
},
new EventTrigger.Entry()
{
eventID = EventTriggerType.EndDrag,
callback = new EventTrigger.TriggerEvent()
}
};
//开始拖拽
self.triggers[0].callback.AddListener((d) =>
{
objDrag = Instantiate(self.gameObject, self.transform.parent);
objDrag.GetComponent<Image>().raycastTarget = false;
});
//拖拽中
self.triggers[1].callback.AddListener((d) =>
{
if (objDrag != null)
{
Vector3 pos;
if (RectTransformUtility.ScreenPointToWorldPointInRectangle(panel, Input.mousePosition, UICamera,out pos))
{
objDrag.transform.position = pos;
}
}
});
//拖拽结束
self.triggers[2].callback.AddListener((d) =>
{
double lng, lat;
Vector2 pos = Input.mousePosition;
MapHelper.instance.GetLatlng(pos, out lng, out lat);
Marker m = new Marker()
{
uuid = Guid.NewGuid().ToString(),
name = "测试",
latitude = lat,
longitude = lng,
};
Destroy(objDrag, 0.1f);
Debug.Log(lng+":"+ lat);
MapBoxManager.instance.CreateMarker(m);
});
}
}
效果如下: