UnityRTS相机的移动缩放功能

所谓RTS就是即时战略游戏(Real-Time Strategy Game)。

话不多说直接看一下demo:


相机的层级关系(移动的操作是对父物体进行操作,而缩放是对子物体主相机的操作):

以此场景为例,自己设置的一些参数,主要是移动速度,边界、缩放限制等。

代码如下(挂载到相机的父物体上)。有两种鼠标的控制方式,一种是边界检测,一种是鼠标拖动。这个代码是完整版的,也就是键盘也可以控制相机移动缩放的,如果只需要鼠标控制的,请往下看:

using UnityEngine;

/// <summary>
/// 
/// * Writer:June
/// *
/// * Data:2021.3.9
/// *
/// * Function:RTS模式的相机移动
/// *
/// * Remarks:
/// 
/// </summary>

public class CameraMoveControl : MonoBehaviour
{
    #region 移动
    /// <summary>
    /// 移动速度
    /// </summary>
    private float panSpeed;
    /// <summary>
    /// 正常速度
    /// </summary>
    [SerializeField] private float normalSpeed;
    /// <summary>
    /// 按shift加速
    /// </summary>
    [SerializeField] private float speedUp;
    /// <summary>
    /// 缓冲时间
    /// </summary>
    [SerializeField] private float moveTime;
    private Vector3 newPos;
    /// <summary>
    /// 边界限制
    /// </summary>
    [SerializeField] private float xLimMin, xLimMax;
    /// <summary>
    /// 这里的Y是指屏幕上下平移的限制
    /// </summary>
    [SerializeField] private float yLimMin, yLimMax;
    //-----------------------------------------------鼠标拖动操作相关字段----------------------------------------------------
    private Camera mainCamrea;
    private Vector3 startPoint, currentPoint;
    #endregion

    #region 缩放
    /// <summary>
    /// 主摄像机的位置组件
    /// </summary>
    private Transform mainCamreaTF;
    /// <summary>
    /// 缩放向量
    /// tips:相机的放大缩小改变的是相机自身坐标的yz值
    /// </summary>
    [SerializeField] private Vector3 zoomV3;
    /*
     * 需要注意的是缩放限制:
     * x轴与y轴限制后的缩放比值要一致,不然会出现缩放不平滑的现象
     * 
     */
    /// <summary>
    /// 缩放最大最小值
    /// </summary>
    [SerializeField] private Vector3 zoomMin, zoomMax;
    private Vector3 newMainCamreaPos;
    /// <summary>
    /// 缩放时间
    /// </summary>
    [SerializeField] private float zoomTime;
    #endregion

    private void Start()
    {
        //判断是否有子物体
        mainCamreaTF = transform.childCount > 0 ? transform.GetChild(0) : null;
        if (mainCamreaTF) newMainCamreaPos = mainCamreaTF.localPosition;
        mainCamrea = Camera.main;
    }


    private void Update()
    {
        //按左shift加速
        panSpeed = Input.GetKey(KeyCode.LeftShift) ? speedUp : normalSpeed;
        //移动
        ControlCamreaMove();
        //缩放
        ControlCamreaZoom();
    }

    /// <summary>
    /// 控制相机缩放
    /// </summary>
    private void ControlCamreaZoom()
    {
        if (mainCamreaTF)
        {
            if (Input.GetKey(KeyCode.R)) newMainCamreaPos += zoomV3 * Time.deltaTime;//放大
            if (Input.GetKey(KeyCode.F)) newMainCamreaPos -= zoomV3 * Time.deltaTime;//缩小
            newMainCamreaPos += Input.GetAxis("Mouse ScrollWheel") * zoomV3;
            ZoomLimit(ref newMainCamreaPos);
            //刷新最终位置
            mainCamreaTF.localPosition = Vector3.Lerp(mainCamreaTF.localPosition, newMainCamreaPos, zoomTime * Time.deltaTime);
        }
    }


    /// <summary>
    /// 控制相机移动
    /// </summary>
    private void ControlCamreaMove()
    {
        Vector3 movePos = transform.position;
        newPos.Set(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));

        #region 鼠标操作
        #region 方式1(鼠标到达边缘,检测后操作相机移动)
        //Vector2 mousePos = Input.mousePosition;
        //鼠标在四个边缘检测
        //if (mousePos.x > Screen.width * 0.9f && mousePos.x < Screen.width) newPos.x = 1;
        //if (mousePos.x < Screen.width * 0.1f && mousePos.x > 0) newPos.x = -1;
        //if (mousePos.y > Screen.height * 0.9f && mousePos.y < Screen.height) newPos.z = 1;
        //if (mousePos.y < Screen.height * 0.1f && mousePos.y > 0) newPos.z = -1;

        movePos += newPos.normalized * panSpeed * Time.deltaTime;
        #endregion

        #region 方式2(鼠标右键拖动控制相机移动)
        //首先判断相机是否为空
        if (mainCamrea)
        {
            //鼠标右键按下时记录起始位置
            if (Input.GetMouseButtonDown(1))
            {
                //新建的世界坐标系下的平面,用于检测射线
                Plane plane = new Plane(Vector3.up, Vector3.zero);
                Ray ray = mainCamrea.ScreenPointToRay(Input.mousePosition);
                float distance;
                if (plane.Raycast(ray, out distance)) 
                {
                    //获取碰撞位置
                    startPoint = ray.GetPoint(distance);
                }
            }
            //鼠标右键一直按下时记录当前点位置
            if (Input.GetMouseButton(1))
            {
                Plane plane = new Plane(Vector3.up, Vector3.zero);
                Ray ray = mainCamrea.ScreenPointToRay(Input.mousePosition);
                float distance;
                if (plane.Raycast(ray, out distance))
                {
                    currentPoint = ray.GetPoint(distance);
                }
                movePos += (startPoint - currentPoint);
            }
        }
        #endregion
        #endregion

        BoundaryLimit(ref movePos);
        transform.position = Vector3.Lerp(transform.position, movePos, moveTime);
    }


    /// <summary>
    /// 边界限制
    /// </summary>
    /// <param name="_pos">要限制的目标向量</param>
    private void BoundaryLimit(ref Vector3 _pos)
    {
        _pos.x = Mathf.Clamp(_pos.x, xLimMin, xLimMax);
        _pos.z = Mathf.Clamp(_pos.z, yLimMin, yLimMax);
    }


    /// <summary>
    /// 缩放限制
    /// </summary>
    /// <param name="_v3">要限制的目标向量</param>
    private void ZoomLimit(ref Vector3 _v3)
    {
        _v3.y = Mathf.Clamp(_v3.y, zoomMin.y, zoomMax.y);
        _v3.z = Mathf.Clamp(_v3.z, zoomMin.z, zoomMax.z);
    }
}

 


这个代码是后来我觉得其实没必要用键盘来操控相机,根据我玩过的一些类似游戏,比较多都是鼠标操作的,所以删了键盘操作的部分:

using UnityEngine;

/// <summary>
/// 
/// * Writer:June
/// *
/// * Data:2021.3.9
/// *
/// * Function:RTS模式的相机移动
/// *
/// * Remarks:
/// 
/// </summary>

public class CameraMoveControl : MonoBehaviour
{
    #region 移动
    /// <summary>
    /// 移动速度
    /// </summary>
    private float panSpeed;
    /// <summary>
    /// 正常速度
    /// </summary>
    [SerializeField] private float normalSpeed;
    /// <summary>
    /// 按shift加速
    /// </summary>
    [SerializeField] private float speedUp;
    /// <summary>
    /// 缓冲时间
    /// </summary>
    [SerializeField] private float moveTime;
    private Vector3 newPos;
    /// <summary>
    /// 边界限制
    /// </summary>
    [SerializeField] private float xLimMin, xLimMax;
    /// <summary>
    /// 这里的Y是指屏幕上下平移的限制
    /// </summary>
    [SerializeField] private float yLimMin, yLimMax;
    //-----------------------------------------------鼠标拖动操作相关字段----------------------------------------------------
    private Camera mainCamrea;
    private Vector3 startPoint, currentPoint;
    #endregion

    #region 缩放
    /// <summary>
    /// 主摄像机的位置组件
    /// </summary>
    private Transform mainCamreaTF;
    /// <summary>
    /// 缩放向量
    /// tips:相机的放大缩小改变的是相机自身坐标的yz值
    /// </summary>
    [SerializeField] private Vector3 zoomV3;
    /*
     * 需要注意的是缩放限制:
     * x轴与y轴限制后的缩放比值要一致,不然会出现缩放不平滑的现象
     * 
     */
    /// <summary>
    /// 缩放最大最小值
    /// </summary>
    [SerializeField] private Vector3 zoomMin, zoomMax;
    private Vector3 newMainCamreaPos;
    /// <summary>
    /// 缩放时间
    /// </summary>
    [SerializeField] private float zoomTime;
    #endregion

    private void Start()
    {
        //判断是否有子物体
        mainCamreaTF = transform.childCount > 0 ? transform.GetChild(0) : null;
        if (mainCamreaTF) newMainCamreaPos = mainCamreaTF.localPosition;
        mainCamrea = Camera.main;
    }


    private void Update()
    {
        //按左shift加速
        panSpeed = Input.GetKey(KeyCode.LeftShift) ? speedUp : normalSpeed;
        //移动
        ControlCamreaMove();
        //缩放
        ControlCamreaZoom();
    }

    /// <summary>
    /// 控制相机缩放
    /// </summary>
    private void ControlCamreaZoom()
    {
        if (mainCamreaTF)
        {
            newMainCamreaPos += Input.GetAxis("Mouse ScrollWheel") * zoomV3;
            ZoomLimit(ref newMainCamreaPos);
            //刷新最终位置
            mainCamreaTF.localPosition = Vector3.Lerp(mainCamreaTF.localPosition, newMainCamreaPos, zoomTime * Time.deltaTime);
        }
    }


    /// <summary>
    /// 控制相机移动
    /// </summary>
    private void ControlCamreaMove()
    {
        Vector3 movePos = transform.position;
        newPos = Vector3.zero;
        #region 鼠标操作
        #region 方式1(鼠标到达边缘,检测后操作相机移动)
        Vector2 mousePos = Input.mousePosition;
        //鼠标在四个边缘检测
        if (mousePos.x > Screen.width * 0.9f && mousePos.x < Screen.width) newPos.x = 1;
        if (mousePos.x < Screen.width * 0.1f && mousePos.x > 0) newPos.x = -1;
        if (mousePos.y > Screen.height * 0.9f && mousePos.y < Screen.height) newPos.z = 1;
        if (mousePos.y < Screen.height * 0.1f && mousePos.y > 0) newPos.z = -1;
        movePos += newPos.normalized * panSpeed * Time.deltaTime;
        #endregion

        #region 方式2(鼠标右键拖动控制相机移动)
        //首先判断相机是否为空
        if (mainCamrea)
        {
            //鼠标右键按下时记录起始位置
            if (Input.GetMouseButtonDown(1))
            {
                //新建的世界坐标系下的平面,用于检测射线
                Plane plane = new Plane(Vector3.up, Vector3.zero);
                Ray ray = mainCamrea.ScreenPointToRay(Input.mousePosition);
                float distance;
                if (plane.Raycast(ray, out distance))
                {
                    //获取碰撞位置
                    startPoint = ray.GetPoint(distance);
                }
            }
            //鼠标右键一直按下时记录当前点位置
            if (Input.GetMouseButton(1))
            {
                Plane plane = new Plane(Vector3.up, Vector3.zero);
                Ray ray = mainCamrea.ScreenPointToRay(Input.mousePosition);
                float distance;
                if (plane.Raycast(ray, out distance))
                {
                    currentPoint = ray.GetPoint(distance);
                }
                movePos += (startPoint - currentPoint);
            }
        }
        #endregion
        #endregion

        BoundaryLimit(ref movePos);
        transform.position = Vector3.Lerp(transform.position, movePos, moveTime);
    }


    /// <summary>
    /// 边界限制
    /// </summary>
    /// <param name="_pos">要限制的目标向量</param>
    private void BoundaryLimit(ref Vector3 _pos)
    {
        _pos.x = Mathf.Clamp(_pos.x, xLimMin, xLimMax);
        _pos.z = Mathf.Clamp(_pos.z, yLimMin, yLimMax);
    }


    /// <summary>
    /// 缩放限制
    /// </summary>
    /// <param name="_v3">要限制的目标向量</param>
    private void ZoomLimit(ref Vector3 _v3)
    {
        _v3.y = Mathf.Clamp(_v3.y, zoomMin.y, zoomMax.y);
        _v3.z = Mathf.Clamp(_v3.z, zoomMin.z, zoomMax.z);
    }
}

 

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值