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)

相关推荐

  • Unity实现场景漫游相机

    本文实例为大家分享了Unity实现场景漫游相机的具体代码,供大家参考,具体内容如下 前言 拿到场景后总喜欢在场景里面玩一段时间,那这个脚本就是你的不二选择 代码里加了注释,改起来也很方便. 使用方法 把脚本拖拽到场景相机上,开箱即用. WASD前后左右移动 QE为上下 Shift加速 鼠标右键按住旋转视角 ESC退出游戏 源码 #if ENABLE_INPUT_SYSTEM && ENABLE_INPUT_SYSTEM_PACKAGE #define USE_INPUT_SYSTEM us

  • Unity3D基于陀螺仪实现VR相机功能

    Unity自带陀螺仪功能,今天就利用陀螺仪实现一个VR相机功能.步骤如下: 1.打开Unity,创建一个新的C#脚本GyroController.cs,并挂在MainCamera游戏对象上,如图: 代码如下: using UnityEngine; using System.Collections; public class GyroController : MonoBehaviour { // Fields private readonly Quaternion baseIdentity = Q

  • Unity3D实现相机跟随控制

    本文实例为大家分享了Unity3D实现相机跟随控制的具体代码,供大家参考,具体内容如下 跟随算法 要实现3D摄像机的控制第一步就是先实现摄像机跟随物体移动. 要想让相机跟随物体移动,就要明白在一定角度下相机与物体的位置关系. 首先设置相机与物体之间的距离distance,相机与xz平面的角度为roll 所以根据三角关系可以求得映射在xz平面的距离d为distancecos(rool),相机高度为distancesin(roll). 如下图 现在就可以确定相机的高度了即y轴的坐标相机的y轴坐标应该

  • Unity实现截屏以及根据相机画面截图

    在游戏开发和软件开发中,经常需要截图的功能,分带UI的截图和不带UI的截图功能.代码如下: using System.Collections; using System.Collections.Generic; using UnityEngine; public static class ScreenShotForCamera{ public static void CaptureScreen(string _path = null) { if (_path == null) _path = "

  • Unity实现相机截图功能

    最近做项目的时候需要在游戏里截一张高清截图,研究了一下写成脚本,方便以后使用. 脚本可以自定义分辨率,用相机截高清截图.可以用代码动态截图,也可以在编辑模式下截图. 注意截图宽高比要正确,宽高比不正确时可能会出问题. 截图效果: 脚本: CameraCapture.cs using UnityEngine; using System.IO; /// <summary> /// 相机截图 /// <para>ZhangYu 2018-07-06</para> /// &l

  • Unity相机移动之屏幕边缘检测

    本文实例为大家分享了Unity相机移动之屏幕边缘检测的具体代码,供大家参考,具体内容如下 功能: 类似LOL 红警 相机移动方式. 鼠标移动到屏幕边缘,相机随之移动. 当然还有可以加亿一点点细节,比如鼠标指针变化,滚轮推进拉远视野,中键平移视野等.(没做). 效果图: 这里做了可视化数据(可以看到限定的屏幕距离),线框内为检测的距离. 代码: 复制脚本,直接挂载相机上就可以用. using UnityEngine; /// <summary> /// 相机边缘移动 /// </summa

  • UnityRTS实现相机移动缩放功能

    所谓RTS就是即时战略游戏(Real-Time Strategy Game). 话不多说直接看一下demo: 相机的层级关系(移动的操作是对父物体进行操作,而缩放是对子物体主相机的操作): 以此场景为例,自己设置的一些参数,主要是移动速度,边界.缩放限制等. 代码如下(挂载到相机的父物体上).有两种鼠标的控制方式,一种是边界检测,一种是鼠标拖动.这个代码是完整版的,也就是键盘也可以控制相机移动缩放的,如果只需要鼠标控制的,请往下看: using UnityEngine; /// <summary

  • jQuery实现的鼠标滚轮控制图片缩放功能实例

    本文实例讲述了jQuery实现的鼠标滚轮控制图片缩放功能.分享给大家供大家参考,具体如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> &

  • iOS使用UIScorllView实现两指缩放功能

    两指缩放功能不仅可以用UIPinchGestureRecognizer手势来实现,还能用UIScorllView来实现,UIScrollView可以轻松的实现最大与最小缩放值,以及滚动的效果.代码如下: #import "ViewController.h" @interface ViewController () @property (weak, nonatomic) IBOutlet UIScrollView *scrollView; @property (strong, nonat

  • WinForm实现的图片拖拽与缩放功能示例

    本文实例讲述了WinForm实现的图片拖拽与缩放功能.分享给大家供大家参考,具体如下: 最近做项目的时候遇到上传施工平面布置图,查看,因为图片比较大,一般的显示器分辨率无法显示全,然后还需要放大看清楚图片里面的文字内容,所以需要用到图片的拖拽与缩放功能.这里整理下具体操作. 首先新建一个窗体,拖一个panel控件到窗体中,然后在拖一个pictureobx控件到panel中,然后在添加个上传图片的按钮: 具体代码: using System; using System.Collections.Ge

  • Android控件实现图片缩放功能

    1 简介 先来一张效果图 TIM图片.gif 上图中灰色的一块是ImageView控件,ImageView中的图片进行左右上下移动,以及双指缩放. 对于android控件的缩放移动,点这里----android控件的缩放,移动 2 使用步骤 布局layout <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.

  • iOS实现简单的头部缩放功能

    本文通过实例代码给大家介绍了iOS实现简单的头部缩放功能.实现思路有头部视图,滚动视图,控制头部动画等多个示例代码块,大家可以参考下本文. 简单实现并集成一个头部缩放的功能,适用于UIScrollView以及其子类. 头部伴随模糊效果放大缩小,并在一定位置时悬停充当导航栏.这里提供实现思路,如有符合可直接使用. 效果如下图. 实现: 首先分解为两部分,一部分为头部视图,一部分为滚动视图.头部视图负责展示,滚动视图负责控制头部视图如何展示,比如放大和缩小. 一:头部视图 头部视图拆解为负责展示图片

  • Android WebView支持input file启用相机/选取照片功能

    webview要调起input-file拍照或者选取文件功能,可以在webview.setWebChromeClient方法中重写指定的方法,来拦截webview的input事件,并做我们相应的操作. Android代码 webView.setWebChromeClient(new WebChromeClient() { @Override public void onProgressChanged(WebView view, int newProgress) { if (newProgress

  • 使用OpenCV实现仿射变换—缩放功能

    前面介绍怎么样实现平移的功能,接着下来演示缩放功能.比如在一个文档里插入一个图片,发现这个图片占用太大的面积了,要把它缩小,才放得下,与文字的比例才合适.这样的需求,就需要使用仿射变换的缩放功能,而实现这个功能的方法,就是采用齐次坐标的变换功式: 可看到最后一条公式,就是缩放公式,要实现二维图像的缩放,需要构造前面那个缩放矩阵,因此在OpenCV也是构造一个2X3的矩阵.不过,在缩放变换里,要考虑另外一个问题,比如图片放大之后,原来两点像素的距离变大了,在中间留下了空间,那么中间空白的像素点怎么

  • Android图片采样缩放功能实例代码

    为什么要对Android中的图片进行采样缩放呢? 是为了更加高效的加载Bitmap.假设通过imageView来显示图片,很多时候ImageView并没有图片的原始尺寸那么大,这时候把整张图片加载进来后再设给ImageView是没有必要的,因为ImagView并没有办法显示原始的图片. 所以我们可以使用BitmapFactory.Options按照一定的采样率加载缩小后的图片,将缩小后的图片在ImageView中显示,这样就能降低内存占用,在一定程度上避免OOM,提高bitma加载时候的性能.

  • Android 图片处理缩放功能

    PS:在开发中我们会遇到一些图片处理问题,比如说缓存图片了.限制图片大小了.查看图片了等.上一篇文章介绍了图片的全景效果查看,今天介绍一个图片缩放,我们如果有时间的话,可以自己写一个属于自己的库,里面会用到view的按压.事件分发.手势等一些知识,如果没有时间或者不会其他的方法,不妨来看看这个PhotoView.这是一个图片缩放库,对于这样的还有GitView等,下面我就介绍一些用法. 功能: 正常加载图片 双击放大 手势随意缩放 随意拖动查看图片每一个角落 结合其他设置可实现翻转 效果图 1:

随机推荐