您当前的位置: 首页 >  unity

Peter_Gao_

暂无认证

  • 0浏览

    0关注

    621博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

unity 小地图 (坐标数值差值转换法)

Peter_Gao_ 发布时间:2021-01-13 09:58:17 ,浏览量:0

小地图的制作网上其实有很多教程,最常见的就是MiniMap使用正交摄像机Render Texture制作,这种摄像机会实时在上空更新地图。但是使用摄像机无疑是耗费资源的,有时候需要的小功能其实只是需要标识自己所在的位置,这时候使用一张地形俯视图就完全可以达到我们的要求。

  首先我们需要一张地形正上方的俯视图一张作为小地图的背景。然后一个图片标识表示自己的位置。效果如下

然后我们需要将地形添加两个点,左下和右上两个点来获得地形的大小,同时注意将Canvas画布的位置与地形对齐

主要思路:根据地形的两点获得地形的尺寸,然后根据地图图片尺寸和地形尺寸的比例转换坐标,获得标识点与自身位置的对齐。

 

主要代码:

 
  1. ///

  2. /// 世界坐标转地图坐标

  3. ///

  4. ///

  5. ///

  6. public Vector2 WorldPositionToMap(Vector3 point)

  7. {

  8. var pos = point - Corner1.position; //得到当前位置相对于地形起始角的位置

  9. //小地图在右上角的起始位置

  10. var MapStart = new Vector2(Screen.width - mapRect.rect.width, (Screen.height - mapRect.rect.height-TopHeight));

  11.  
  12. var mapPos = new Vector2(

  13. MapStart.x+(point.x / terrainSize.x * mapRect.rect.width),

  14. MapStart.y+(point.z / terrainSize.y * mapRect.rect.height)); //缩放到能适配地图尺寸的点

  15. return mapPos;

  16.  
  17. }

  18. ///

  19. /// 地图坐标转世界坐标

  20. ///

  21. /// 屏幕坐标

  22. ///

  23. public Vector3 MapToWorld(Vector2 point)

  24. {

  25. var MapStart = new Vector2(Screen.width - mapRect.rect.width, (Screen.height - mapRect.rect.height));

  26. var pos = point - MapStart;

  27. var Posx = Corner1.position.x+(pos.x / mapRect.rect.width * terrainSize.x);

  28. var Posz = Corner1.position.z + (pos.y / mapRect.rect.height * terrainSize.y);

  29. var WorldMap = new Vector3(Posx, Camera.main.transform.position.y, Posz);

  30. return WorldMap;

  31. }

参考链接:https://blog.csdn.net/zjw1349547081/article/details/53517021

TopHeight是我项目里自定义的上边距,因为上面有一层背景所以需要减去。terrainSize是地形尺寸,mapRect是地图图片在初始化中实例化。

 
  1. // Use this for initialization

  2. void Start ()

  3. {

  4. mapRect = GetComponent();

  5. terrainSize = new Vector2(Corner2.position.x - Corner1.position.x,

  6. Corner2.position.z - Corner1.position.z);

  7. MaxHeight = mapRect.rect.height * 2;

  8. MaxWidth = mapRect.rect.width * 2;

  9. Num = NavImg.rect.width/mapRect.rect.width;

  10.  
  11. TopHeight = Top.rect.height;

  12. }

MaxHeight和MaxWidth是最大高度和最大宽度,是我后面为了限制小地图无限拉伸做的限制。

接下来我们只要实时更新标识与自身的位置就可以了。

 
  1. // Update is called once per frame

  2. void Update ()

  3. {

  4.  
  5. SizePictures();

  6. //掉地图指针位置更新

  7. NavImg.position=WorldPositionToMap(Camera.main.transform.position);

  8. NavImg.sizeDelta = new Vector2(mapImg.sizeDelta.x*Num, mapImg.sizeDelta.x * Num);

  9.  
  10. }

我这里更新的是摄像机的位置,如果想要人物之类绑定的话可自行修改。SizePictures是后面我们要说的自定义拖拽地图大小的方法,因为拖拽可能往左或者往右,所以为了不让标识图片大小变形,我这里让标识图片以宽度为准伸缩大小。

既然小地图标识绑定了,我们是不是该做个点击小地图,移动的摄像机视角的功能呢。

 
  1. ///

  2. /// 点击小地图主摄像机移动

  3. ///

  4. public void MapClick1()

  5. {

  6. Vector2 point = Input.mousePosition;

  7. Camera.main.transform.position = MapToWorld(point);

  8.  
  9. }

给小地图添加点击事件,将该方法绑定

好了,小地图基本做好了,我们来试试自定义大小的功能,这个功能我做的不是很好,拖拽的时候总觉得挺费劲的,如果以后找到更好的方式再做修改。

 
  1. ///

  2. /// 小地图拖拽改变大小

  3. ///

  4. public void SizePictures()

  5. {

  6. // 当按住鼠标左键的时候

  7. if (Input.GetMouseButton(0)&&IsDrawing())

  8. {

  9. float h = Screen.width - Input.mousePosition.x - mapRect.sizeDelta.x;

  10. float v = Screen.height - Input.mousePosition.y - mapRect.sizeDelta.y;

  11.  
  12.  
  13. //小地图大小位置重置

  14. mapRect.sizeDelta = new Vector2(mapRect.sizeDelta.x+h, mapRect.sizeDelta.y+v);

  15. mapRect.anchoredPosition = new Vector2(0-mapRect.rect.width/2,0-(mapRect.rect.height/2)-TopHeight);

  16.  
  17. mapImg.sizeDelta = new Vector2(mapImg.sizeDelta.x + h, mapImg.sizeDelta.y + v);

  18. mapImg.anchoredPosition = new Vector2(0,0);

  19.  
  20. }

  21. }

  22. ///

  23. /// 判定是否可以拖拽小地图

  24. ///

  25. ///

  26. public bool IsDrawing()

  27. {

  28. bool Isdraw = false;

  29. //边缘检测

  30. //左,左下,下,三种情况可拖拽

  31. //左

  32. if (Input.mousePosition.x < (mapRect.transform.position.x - mapRect.rect.width / 2.0f + m_validityWidth))

  33. {

  34. Isdraw = true;

  35. if (Input.mousePosition.x < (mapRect.transform.position.x - MaxWidth / 2)|| Input.mousePosition.y < (mapRect.transform.position.y - MaxHeight / 2))

  36. {

  37. Isdraw = false;

  38. }

  39. }

  40. //如果鼠标位置离下侧边界的限定距离内

  41. else if ((Input.mousePosition.y < (mapRect.transform.position.y - mapRect.rect.height / 2.0f + m_validityWidth)))

  42. {

  43. Isdraw = true;

  44. if (Input.mousePosition.y < (mapRect.transform.position.y - MaxHeight / 2)|| Input.mousePosition.x < (mapRect.transform.position.x - MaxWidth / 2))

  45. {

  46. Isdraw = false;

  47. }

  48.  
  49. }

  50. else

  51. {

  52. Isdraw = false;

  53. }

  54.  
  55.  
  56. return Isdraw;

  57. }

判断鼠标是否在小地图的边缘处可进行拖拽,我这里小地图是在右上方所以只判定往左,左下,下方三种情况拖拽的可能性。

 

using UnityEngine;
using System.Collections;
using System.Diagnostics;
using UnityEngine.EventSystems;
using Debug = UnityEngine.Debug;
 
//图片仿视频窗口缩放类
public class Test : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    [Header("有效检测的边缘宽度")]
    public float m_validityWidth = 10f;
 
    //存储操作的拖拽方向(默认为无操作)
    private DragDirection m_direction = DragDirection.None;
 
    //1.上方  //5.左上角
    //2.下方  //6.左下角
    //3.左方  //7.右上角
    //4.右方  //8.右下角
 
    //存储当前操作图片位置
    private Vector3 tTargetPos;
    //存储鼠标位置
    private Vector3 tMousePos;
    //存储当前图片宽度
    private float tWidth;
    //存储当前图片高度
    private float tHeight;
 
    //存储不动点位置坐标
    //解释一下:当我们拖动每个边界时至少有一个点时应该不动的,我们就以该点为基准点,当拖动单面有两点不动时我们取两点的中间点为基准点
    private Vector3 m_basePoint;
 
    /// 
    /// 拖拽时刷新数据
    /// 
    /// 
    void DoRefresh(PointerEventData eventData)
    {
        //刷新鼠标位置
        tMousePos = eventData.position;
        //刷新图片位置
        tTargetPos = transform.position;
        //刷新图片宽度
        tWidth = GetComponent().sizeDelta.x;
        //刷新图片高度
        tHeight = GetComponent().sizeDelta.y;
    }
 
    //拖动开始触发
    public void OnBeginDrag(PointerEventData eventData)
    {
        //刷新数据方法
         DoRefresh(eventData);
 
    }
    //拖动进行中触发
    public void OnDrag(PointerEventData eventData)
    {
        //刷新数据方法
        DoRefresh(eventData);
 
        #region 判定拖动方向
        //如果鼠标位置离左侧边界的限定距离内,设置对应的方向
        if (tMousePos.x < (tTargetPos.x - tWidth / 2.0f + m_validityWidth))
        {
            m_direction = DragDirection.Left;
            //上
            if (tMousePos.y > (tTargetPos.y + tHeight / 2.0f - m_validityWidth))
            {
                m_direction = DragDirection.LeftUp;
            }
            //下
            else if ((tMousePos.y < (tTargetPos.y - tHeight / 2.0f + m_validityWidth)))
            {
                m_direction = DragDirection.LeftDown;
            }
 
        }
        //如果鼠标位置离右侧边界的限定距离内
        else if (tMousePos.x > (tTargetPos.x + tWidth / 2.0f - m_validityWidth))
        {
            m_direction = DragDirection.Right;
            //上
            if (tMousePos.y > (tTargetPos.y + tHeight / 2.0f - m_validityWidth))
            {
                m_direction = DragDirection.RightUp;
            }
            //下
            else if ((tMousePos.y < (tTargetPos.y - tHeight / 2.0f + m_validityWidth)))
            {
                m_direction = DragDirection.RightDown;
            }
        }
        //如果鼠标位置离上侧边界的限定距离内
        else if (tMousePos.y > (tTargetPos.y + tHeight / 2.0f - m_validityWidth))
        {
            m_direction = DragDirection.Up;
            //左
            if (tMousePos.x < (tTargetPos.x - tWidth / 2.0f + m_validityWidth))
            {
                m_direction = DragDirection.LeftUp;
            }
            //右
            else if (tMousePos.x > (tTargetPos.x + tWidth / 2.0f - m_validityWidth))
            {
                m_direction = DragDirection.RightUp;
            }
        }
        //如果鼠标位置离下侧边界的限定距离内
        else if ((tMousePos.y < (tTargetPos.y - tHeight / 2.0f + m_validityWidth)))
        {
            m_direction = DragDirection.Down;
            //左
            if (tMousePos.x < (tTargetPos.x - tWidth / 2.0f + m_validityWidth))
            {
                m_direction = DragDirection.LeftDown;
            }
            //右
            else if (tMousePos.x > (tTargetPos.x + tWidth / 2.0f - m_validityWidth))
            {
                m_direction = DragDirection.RightDown;
            }
        }
        else
        {
            m_direction = DragDirection.None;
        }
 
 
        #endregion
 
        //根据当前判定的方向做出相应的仿视频窗口缩放
        switch (m_direction)
        {
            case DragDirection.Left:
                DoLeft();
                break;
            case DragDirection.Right:
                DoRight();
                break;
            case DragDirection.Up:
                DoUp();
                break;
            case DragDirection.Down:
                DoDown();
                break;
            case DragDirection.LeftUp:
                DoLeftUp();
                break;
            case DragDirection.LeftDown:
                DoLeftDown();
                break;
            case DragDirection.RightUp:
                DoRightUp();
                break;
            case DragDirection.RightDown:
                DoRightDown();
                break;
            default:
               // Debug.Assert(false);
                break;
        }
 
    }
 
    #region 各个方向对应的调整方法
    /// 
    /// 左拖动改变图片横向大小
    /// 
    void DoLeft()
    {
        //设定基准点坐标
        m_basePoint = tTargetPos + new Vector3(tWidth / 2.0f, 0, 0);
        //设定图片宽度
        float ttWidth = Mathf.Abs(m_basePoint.x - tMousePos.x);
        GetComponent().sizeDelta = new Vector2(ttWidth, tHeight);
        //设置图片位置
        transform.position = m_basePoint - new Vector3(ttWidth / 2.0f, 0, 0);
    }
    /// 
    /// 右拖动改变图片横向大小
    /// 
    void DoRight()
    {
        //设定基准点坐标
        m_basePoint = tTargetPos - new Vector3(tWidth / 2.0f, 0, 0);
        //设定图片宽度
        float ttWidth = Mathf.Abs(m_basePoint.x - tMousePos.x);
        GetComponent().sizeDelta = new Vector2(ttWidth, tHeight);
        //设置图片位置
        transform.position = m_basePoint + new Vector3(ttWidth / 2.0f, 0, 0);
    }
    /// 
    /// 上拖动改变图片横向大小
    /// 
    void DoUp()
    {
        //设定基准点坐标
        m_basePoint = tTargetPos - new Vector3(0, tHeight / 2.0f, 0);
        //设定图片高度
        float ttHeight = Mathf.Abs(m_basePoint.y - tMousePos.y);
        GetComponent().sizeDelta = new Vector2(tWidth, ttHeight);
        //设置图片位置
        transform.position = m_basePoint + new Vector3(0, ttHeight / 2.0f, 0);
    }
    /// 
    /// 下拖动改变图片横向大小
    /// 
    void DoDown()
    {
        //设定基准点坐标
        m_basePoint = tTargetPos + new Vector3(0, tHeight / 2.0f, 0);
        //设定图片高度
        float ttHeight = Mathf.Abs(m_basePoint.y - tMousePos.y);
        GetComponent().sizeDelta = new Vector2(tWidth, ttHeight);
        //设置图片位置
        transform.position = m_basePoint - new Vector3(0, ttHeight / 2.0f, 0);
    }
    /// 
    /// 左上拖动改变图片横向大小
    /// 
    void DoLeftUp()
    {
        //设定基准点坐标
        m_basePoint = tTargetPos + new Vector3(tWidth / 2.0f, -tHeight / 2.0f, 0);
        //设定图片宽度
        float ttWidth = Mathf.Abs(m_basePoint.x - tMousePos.x);
        //设定图片高度
        float ttHeight = Mathf.Abs(m_basePoint.y - tMousePos.y);
        GetComponent().sizeDelta = new Vector2(ttWidth, ttHeight);
        //设置图片位置
        transform.position = m_basePoint + new Vector3(-ttWidth / 2.0f, ttHeight / 2.0f, 0);
    }
    /// 
    /// 左下拖动改变图片横向大小
    /// 
    void DoLeftDown()
    {
        //设定基准点坐标
        m_basePoint = tTargetPos + new Vector3(tWidth / 2.0f, tHeight / 2.0f, 0);
        //设定图片宽度
        float ttWidth = Mathf.Abs(m_basePoint.x - tMousePos.x);
        //设定图片高度
        float ttHeight = Mathf.Abs(m_basePoint.y - tMousePos.y);
        GetComponent().sizeDelta = new Vector2(ttWidth, ttHeight);
        //设置图片位置
        transform.position = m_basePoint + new Vector3(-ttWidth / 2.0f, -ttHeight / 2.0f, 0);
    }
    /// 
    /// 右上拖动改变图片横向大小
    /// 
    void DoRightUp()
    {
        //设定基准点坐标
        m_basePoint = tTargetPos + new Vector3(-tWidth / 2.0f, -tHeight / 2.0f, 0);
        //设定图片宽度
        float ttWidth = Mathf.Abs(m_basePoint.x - tMousePos.x);
        //设定图片高度
        float ttHeight = Mathf.Abs(m_basePoint.y - tMousePos.y);
        GetComponent().sizeDelta = new Vector2(ttWidth, ttHeight);
        //设置图片位置
        transform.position = m_basePoint + new Vector3(ttWidth / 2.0f, ttHeight / 2.0f, 0);
    }
    /// 
    /// 右下拖动改变图片横向大小
    /// 
    void DoRightDown()
    {
        //设定基准点坐标
        m_basePoint = tTargetPos + new Vector3(-tWidth / 2.0f, tHeight / 2.0f, 0);
        //设定图片宽度
        float ttWidth = Mathf.Abs(m_basePoint.x - tMousePos.x);
        //设定图片高度
        float ttHeight = Mathf.Abs(m_basePoint.y - tMousePos.y);
        GetComponent().sizeDelta = new Vector2(ttWidth, ttHeight);
        //设置图片位置
        transform.position = m_basePoint + new Vector3(ttWidth / 2.0f, -ttHeight / 2.0f, 0);
    }
    #endregion
 
    //拖动结束触发
    public void OnEndDrag(PointerEventData eventData)
    {
        //重置拖动方向
        m_direction = DragDirection.None;
    }
 
}
 
/// 
/// 拖拽方向枚举
/// 
public enum DragDirection
{
    None,       //无
    Up,         //上
    Down,       //下
    Left,       //左
    Right,      //右
    LeftUp,     //左上
    RightUp,    //右上
    LeftDown,   //左下
    RightDown   //右下
}

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
 
public class MapControl : MonoBehaviour {
    //小地图图片
    public RectTransform NavImg;
    //地形的左下和右上两个点
    public Transform Corner1, Corner2;
    //上界面
    public RectTransform Top;
    //上界面的高度
    private float TopHeight;
    //地形的大小
    private Vector2 terrainSize;
    //获取当前地图背景的位置
    private RectTransform mapRect;
    //获取当前地图的位置
    public RectTransform mapImg;
 
    [Header("拖拽速度")]
    public float MoveSpeed;
 
    [Header("有效检测的边缘宽度")]
    public float m_validityWidth = 10f;
 
    //最大宽度
    private float MaxWidth;
    //最大高度
    private float MaxHeight;
    //倍数
    private float Num;
    
 
    // Use this for initialization
    void Start ()
    {
        mapRect = GetComponent();
        terrainSize = new Vector2(Corner2.position.x - Corner1.position.x,
            Corner2.position.z - Corner1.position.z);
        MaxHeight = mapRect.rect.height * 2;
        MaxWidth = mapRect.rect.width * 2;
        Num =  NavImg.rect.width/mapRect.rect.width;
 
        TopHeight = Top.rect.height;
    }
    /// 
    /// 世界坐标转地图坐标
    /// 
    /// 
    /// 
    public Vector2 WorldPositionToMap(Vector3 point)
    {
        var pos = point - Corner1.position;    //得到当前位置相对于地形起始角的位置
        //小地图在右上角的起始位置
        var MapStart = new Vector2(Screen.width - mapRect.rect.width, (Screen.height - mapRect.rect.height-TopHeight));
 
        var mapPos = new Vector2(
            MapStart.x+(point.x / terrainSize.x * mapRect.rect.width),
            MapStart.y+(point.z / terrainSize.y * mapRect.rect.height));   //缩放到能适配地图尺寸的点
        return mapPos;
 
    }
    /// 
    /// 地图坐标转世界坐标
    /// 
    /// 屏幕坐标
    /// 
    public Vector3 MapToWorld(Vector2 point)
    {  
        var MapStart = new Vector2(Screen.width - mapRect.rect.width, (Screen.height - mapRect.rect.height));
        var pos = point - MapStart;
        var Posx = Corner1.position.x+(pos.x / mapRect.rect.width * terrainSize.x);
        var Posz = Corner1.position.z + (pos.y / mapRect.rect.height * terrainSize.y);
        var WorldMap = new Vector3(Posx, Camera.main.transform.position.y, Posz);
        return WorldMap;
    }
 
    /// 
    /// 点击小地图主摄像机移动
    /// 
    public void MapClick1()
    {
        Vector2 point = Input.mousePosition;
        Camera.main.transform.position = MapToWorld(point);
 
    }
 
    // Update is called once per frame
    void Update ()
    {
        
        SizePictures();
        //掉地图指针位置更新
        NavImg.position=WorldPositionToMap(Camera.main.transform.position);
        NavImg.sizeDelta = new Vector2(mapImg.sizeDelta.x*Num, mapImg.sizeDelta.x * Num);
 
    }
 
  /// 
  /// 小地图拖拽改变大小
  /// 
    public void SizePictures()
    {
        // 当按住鼠标左键的时候  
        if (Input.GetMouseButton(0)&&IsDrawing())
        {
            float h = Screen.width - Input.mousePosition.x - mapRect.sizeDelta.x;
            float v = Screen.height - Input.mousePosition.y - mapRect.sizeDelta.y;
 
 
            //小地图大小位置重置
            mapRect.sizeDelta = new Vector2(mapRect.sizeDelta.x+h, mapRect.sizeDelta.y+v);
            mapRect.anchoredPosition = new Vector2(0-mapRect.rect.width/2,0-(mapRect.rect.height/2)-TopHeight);
 
            mapImg.sizeDelta = new Vector2(mapImg.sizeDelta.x + h, mapImg.sizeDelta.y + v);
            mapImg.anchoredPosition = new Vector2(0,0);
 
        }
    }
    /// 
    /// 判定是否可以拖拽小地图
    /// 
    /// 
    public bool IsDrawing()
    {
        bool Isdraw = false;
        //边缘检测
        //左,左下,下,三种情况可拖拽
        //左
        if (Input.mousePosition.x < (mapRect.transform.position.x - mapRect.rect.width / 2.0f + m_validityWidth))
        {
            Isdraw = true;
            if (Input.mousePosition.x < (mapRect.transform.position.x - MaxWidth / 2)|| Input.mousePosition.y < (mapRect.transform.position.y - MaxHeight / 2))
            {
                Isdraw = false;
            }
        }
        //如果鼠标位置离下侧边界的限定距离内
        else if ((Input.mousePosition.y < (mapRect.transform.position.y - mapRect.rect.height / 2.0f + m_validityWidth)))
        {
            Isdraw = true;
            if (Input.mousePosition.y < (mapRect.transform.position.y - MaxHeight / 2)|| Input.mousePosition.x < (mapRect.transform.position.x - MaxWidth / 2))
            {
                Isdraw = false;
            }
           
        }
        else
        {
            Isdraw = false;
        }
 
 
        return Isdraw;
    }
 
}

https://blog.csdn.net/qq_30300405/article/details/88660207

 

 

 

关注
打赏
1664521772
查看更多评论
立即登录/注册

微信扫码登录

0.0519s