UnityRTS实现相机移动缩放功能

 更新时间:2021年3月12日 10:00  点击:1849

所谓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);
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持猪先飞。

[!--infotagslink--]

相关文章

  • 红米K30至尊纪念版相机拍照怎么去水印?

    红米K30至尊纪念版相机拍照怎么去水印?红米K30至尊纪念版拍照的时候总是自动添加水印,想要关闭水印,该怎么操作呢?下面我们就来看看详细的教程,需要的朋友可以参考下...2020-12-08
  • 手机相机怎么拍摄慢动作? 华为手机拍摄慢动作的技巧

    手机相机怎么拍摄慢动作?华为手机想要拍摄慢动作的照片效果,该怎么拍摄呢?下面我们就来看看华为手机拍摄慢动作的技巧,需要的朋友可以参考下...2020-12-08
  • OpenCV实现相机标定板

    这篇文章主要为大家详细介绍了OpenCV实现相机标定板,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-04-16
  • 终结你的选择困难症 读完这个就能愉快的买相机了

    每次当朋友问起小编,该如何去选择相机的时候,我总是陷入深深的思考,我该如何回答才好呢……然后我请教了资深器材党耕三于是有了这篇文章。...2016-07-04
  • OPPO Ace2相机人像模式有哪些拍摄技巧?

    OPPO Ace2相机人像模式有哪些拍摄技巧?拍人物的时候,用人像模式拍出的效果会比较好,该怎么使用人像模式呢?下面我们就来看看详细的教程,需要的朋友可以参考下...2020-06-29
  • Unity实现场景漫游相机

    这篇文章主要为大家详细介绍了Unity实现场景漫游相机,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-12-08
  • UnityRTS实现相机移动缩放功能

    这篇文章主要为大家详细介绍了UnityRTS实现相机的移动缩放功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-03-12
  • 运动相机GoPro撑不住了:裁员15% 宣布业务重组

    据外媒报道,运动相机制造商GoPro周三宣布,将对公司业务进行重组,裁员大约15%以降低支出实现盈利。...2016-12-07
  • Unity实现相机截图功能

    这篇文章主要为大家详细介绍了Unity实现相机截图功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
  • Unity3D基于陀螺仪实现VR相机功能

    这篇文章主要为大家详细介绍了Unity3D基于陀螺仪实现VR相机功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-06-25
  • 尼康新机在华注册 或将发高端无反相机

    【IT168 资讯】眼看今年已经过半,在上半年中尼康已经靠D5和D500两款重量级新品带给我们不小惊喜,那么在下半年他们会有什么计划呢?近日,尼康在中国注册了一款代号为“N1546”的相机,通常情况下这意味着近期内这款新机会发布。而如果根据早前传闻推测,这很有可能会是计划于Photokina期间发布的搭载更大尺寸传感器的尼康无反相机。...2016-08-27
  • oppo findx2pro怎么拍月亮? oppo相机超级月亮玩法

    oppo findx2pro怎么拍月亮?oppo findx2pro手机想要拍月亮,该怎么拍的月亮又大又清晰呢?下面我们就来看看oppo相机拍摄月亮的技巧,需要的朋友可以参考下...2020-12-08