不使用摄像机制作小地图,以及自定义拖拽小地图大小

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

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

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

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

主要代码:

/// <summary>
    /// 世界坐标转地图坐标
    /// </summary>
    /// <param name="point"></param>
    /// <returns></returns>
    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;

    }
    /// <summary>
    /// 地图坐标转世界坐标
    /// </summary>
    /// <param name="point">屏幕坐标</param>
    /// <returns></returns>
    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;
    }

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

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

 // Use this for initialization
    void Start ()
    {
        mapRect = GetComponent<RectTransform>();
        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;
    }

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

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

 // 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);

    }

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

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

/// <summary>
    /// 点击小地图主摄像机移动
    /// </summary>
    public void MapClick1()
    {
        Vector2 point = Input.mousePosition;
        Camera.main.transform.position = MapToWorld(point);

    }

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

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

/// <summary>
  /// 小地图拖拽改变大小
  /// </summary>
    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);

        }
    }
    /// <summary>
    /// 判定是否可以拖拽小地图
    /// </summary>
    /// <returns></returns>
    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;
    }

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

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;

    /// <summary>
    /// 拖拽时刷新数据
    /// </summary>
    /// <param name="eventData"></param>
    void DoRefresh(PointerEventData eventData)
    {
        //刷新鼠标位置
        tMousePos = eventData.position;
        //刷新图片位置
        tTargetPos = transform.position;
        //刷新图片宽度
        tWidth = GetComponent<RectTransform>().sizeDelta.x;
        //刷新图片高度
        tHeight = GetComponent<RectTransform>().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 各个方向对应的调整方法
    /// <summary>
    /// 左拖动改变图片横向大小
    /// </summary>
    void DoLeft()
    {
        //设定基准点坐标
        m_basePoint = tTargetPos + new Vector3(tWidth / 2.0f, 0, 0);
        //设定图片宽度
        float ttWidth = Mathf.Abs(m_basePoint.x - tMousePos.x);
        GetComponent<RectTransform>().sizeDelta = new Vector2(ttWidth, tHeight);
        //设置图片位置
        transform.position = m_basePoint - new Vector3(ttWidth / 2.0f, 0, 0);
    }
    /// <summary>
    /// 右拖动改变图片横向大小
    /// </summary>
    void DoRight()
    {
        //设定基准点坐标
        m_basePoint = tTargetPos - new Vector3(tWidth / 2.0f, 0, 0);
        //设定图片宽度
        float ttWidth = Mathf.Abs(m_basePoint.x - tMousePos.x);
        GetComponent<RectTransform>().sizeDelta = new Vector2(ttWidth, tHeight);
        //设置图片位置
        transform.position = m_basePoint + new Vector3(ttWidth / 2.0f, 0, 0);
    }
    /// <summary>
    /// 上拖动改变图片横向大小
    /// </summary>
    void DoUp()
    {
        //设定基准点坐标
        m_basePoint = tTargetPos - new Vector3(0, tHeight / 2.0f, 0);
        //设定图片高度
        float ttHeight = Mathf.Abs(m_basePoint.y - tMousePos.y);
        GetComponent<RectTransform>().sizeDelta = new Vector2(tWidth, ttHeight);
        //设置图片位置
        transform.position = m_basePoint + new Vector3(0, ttHeight / 2.0f, 0);
    }
    /// <summary>
    /// 下拖动改变图片横向大小
    /// </summary>
    void DoDown()
    {
        //设定基准点坐标
        m_basePoint = tTargetPos + new Vector3(0, tHeight / 2.0f, 0);
        //设定图片高度
        float ttHeight = Mathf.Abs(m_basePoint.y - tMousePos.y);
        GetComponent<RectTransform>().sizeDelta = new Vector2(tWidth, ttHeight);
        //设置图片位置
        transform.position = m_basePoint - new Vector3(0, ttHeight / 2.0f, 0);
    }
    /// <summary>
    /// 左上拖动改变图片横向大小
    /// </summary>
    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<RectTransform>().sizeDelta = new Vector2(ttWidth, ttHeight);
        //设置图片位置
        transform.position = m_basePoint + new Vector3(-ttWidth / 2.0f, ttHeight / 2.0f, 0);
    }
    /// <summary>
    /// 左下拖动改变图片横向大小
    /// </summary>
    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<RectTransform>().sizeDelta = new Vector2(ttWidth, ttHeight);
        //设置图片位置
        transform.position = m_basePoint + new Vector3(-ttWidth / 2.0f, -ttHeight / 2.0f, 0);
    }
    /// <summary>
    /// 右上拖动改变图片横向大小
    /// </summary>
    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<RectTransform>().sizeDelta = new Vector2(ttWidth, ttHeight);
        //设置图片位置
        transform.position = m_basePoint + new Vector3(ttWidth / 2.0f, ttHeight / 2.0f, 0);
    }
    /// <summary>
    /// 右下拖动改变图片横向大小
    /// </summary>
    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<RectTransform>().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;
    }

}

/// <summary>
/// 拖拽方向枚举
/// </summary>
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<RectTransform>();
        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;
    }
    /// <summary>
    /// 世界坐标转地图坐标
    /// </summary>
    /// <param name="point"></param>
    /// <returns></returns>
    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;

    }
    /// <summary>
    /// 地图坐标转世界坐标
    /// </summary>
    /// <param name="point">屏幕坐标</param>
    /// <returns></returns>
    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;
    }

    /// <summary>
    /// 点击小地图主摄像机移动
    /// </summary>
    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);

    }

  /// <summary>
  /// 小地图拖拽改变大小
  /// </summary>
    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);

        }
    }
    /// <summary>
    /// 判定是否可以拖拽小地图
    /// </summary>
    /// <returns></returns>
    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;
    }

}

好的,今天的学习就到这里了。

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值