要生成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);
        });
    }  
}

效果如下:

unity ui 地图导航标记_MapBox