Unity实现以鼠标为中心缩放物体(一)

  • 方法一:UGUI下动态设置Pivot
    • Canvas.renderMode = ScreenSpaceCamera
    • Canvas.renderMode = ScreenSpaceOver
    • 完整代码
  • 说明

方法一:UGUI下动态设置Pivot

因为canvas的renderMode有多种方式,在不同方式下Canvas的缩放系数不一致,目前我是分开用来不同的方法,希望后面可以找到办法将两个方法统一,在任何模式下都可以使用;

Canvas.renderMode = ScreenSpaceCamera

 /// <summary>/// 将鼠标的坐标转换到target的pivot坐标,统一在屏幕坐标下进行计算/// 1.取得target的屏幕坐标/// 2.鼠标相对于target的本地坐标/// 3.将鼠标的本地坐标映射到 target的 Pivot坐标/// 4.计算中需要考虑target的缩放/// </summary>/// <param name="screenPos">屏幕坐标系中的点</param>private void SetPivot(Vector2 screenPos){Vector3 oriPos = target.position;   // 原世界空间位置Vector2 oriPivot = target.pivot;    // 原轴心位置Vector3 curPos = new Vector3();     // 当前在世界空间中的位置Vector2 curPivot = new Vector2();   // 当前轴心位置(将轴心位置移动到鼠标点击位置) Vector2 targetScreenPos = UICamera.WorldToScreenPoint(target.position);Vector2 mouseLocalForTarget = screenPos - targetScreenPos;float t1 = oriPivot.x * target.rect.width * tarCurScale * -1f;float t2 = (1 - oriPivot.x) * target.rect.width * tarCurScale;mouseLocalForTarget.x = Mathf.Clamp(mouseLocalForTarget.x, t1, t2);curPivot.x = Remap(mouseLocalForTarget.x, t1, t2, 0f, 1f);t1 = oriPivot.y * target.rect.height * tarCurScale * -1f;t2 = (1 - oriPivot.y) * target.rect.height * tarCurScale;mouseLocalForTarget.y = Mathf.Clamp(mouseLocalForTarget.y, t1, t2);curPivot.y = Remap(mouseLocalForTarget.y, t1, t2, 0f, 1f);target.pivot = curPivot;curPos = oriPos + new Vector3((curPivot - oriPivot).x * target.rect.width * canvasScale * tarCurScale, (curPivot - oriPivot).y * target.rect.height * canvasScale * tarCurScale, 0);target.position = curPos;}// Canvas RenderModel = ScreenSpaceCamera 模式时,可以使用该模式private void ScaleScreenSpaceCamera(Vector2 center, float delta){// 过滤掉重复的轴心设置if (lastCenter != center){SetPivot(center);lastCenter = center;}tarCurScale = target.localScale.x;tarCurScale += (Input.GetAxis("Mouse ScrollWheel") > 0) ? 0.1f : (-0.1f);if (tarCurScale <= 3 && tarCurScale >= 0.5f){target.localScale = Vector3.one * tarCurScale;}else{tarCurScale = (tarCurScale > 3) ? 3f : 0.5f;}}

Canvas.renderMode = ScreenSpaceOver

     // Canvas RenderModel = ScreenSpaceOverlay 模式时,可以使用该模式private void ScaleScreenSpaceOverlay(Vector2 center, float delta){float delX = center.x - target.position.x;float delY = center.y - target.position.y;Vector2 pivot = new Vector2();pivot.x = delX / target.rect.width / tarCurScale;pivot.y = delY / target.rect.height / tarCurScale;tarCurScale = target.localScale.x;tarCurScale += (delta > 0) ? 0.1f : (-0.1f);if (tarCurScale <= 3 && tarCurScale >= 0.5f){target.localScale = Vector3.one * tarCurScale;}else{tarCurScale = (tarCurScale > 3) ? 3f : 0.5f;}target.pivot += pivot;// 增加画布的缩放系数,当画布大小和screen大小不一致时,画布也是有缩放的target.position += new Vector3(delX, delY, 0) * canvasScale;}

完整代码

using UnityEngine;
using UnityEngine.EventSystems;/// <summary>
/// UI拖动平移、以鼠标为中心进行缩放组件
/// </summary>
public class UICenterScale : MonoBehaviour, IScrollHandler
{public Canvas canvas;               // UI画布public Camera UICamera;             // UI摄像机public RectTransform Mask;          // 遮罩      public RectTransform target;        // 缩放和移动的目标物体 private float tarCurScale = 1;      // 物体当前的缩放private float canvasScale;          // 画布的缩放,canvas在不同的模式下,或画布大小和屏幕不一致时,会存在缩放private Vector2 lastCenter;         // 用于保存开始缩放时鼠标的位置private void Start(){canvasScale = canvas.transform.localScale.x;tarCurScale = target.localScale.x;}// 滚轮缩放public void OnScroll(PointerEventData eventData){if (canvas.renderMode == RenderMode.ScreenSpaceCamera){ScaleScreenSpaceCamera(eventData.position, eventData.scrollDelta.y);}else{ScaleScreenSpaceOverlay(eventData.position, eventData.scrollDelta.y);}}/// <summary>/// 将鼠标的坐标转换到target的pivot坐标,统一在屏幕坐标下进行计算/// 1.取得target的屏幕坐标/// 2.鼠标相对于target的本地坐标/// 3.将鼠标的本地坐标映射到 target的 Pivot坐标/// 4.计算中需要考虑target的缩放/// </summary>/// <param name="screenPos">屏幕坐标系中的点</param>private void SetPivot(Vector2 screenPos){Vector3 oriPos = target.position;   // 原世界空间位置Vector2 oriPivot = target.pivot;    // 原轴心位置Vector3 curPos = new Vector3();     // 当前在世界空间中的位置Vector2 curPivot = new Vector2();   // 当前轴心位置(将轴心位置移动到鼠标点击位置) Vector2 targetScreenPos = UICamera.WorldToScreenPoint(target.position);Vector2 mouseLocalForTarget = screenPos - targetScreenPos;float t1 = oriPivot.x * target.rect.width * tarCurScale * -1f;float t2 = (1 - oriPivot.x) * target.rect.width * tarCurScale;mouseLocalForTarget.x = Mathf.Clamp(mouseLocalForTarget.x, t1, t2);curPivot.x = Remap(mouseLocalForTarget.x, t1, t2, 0f, 1f);t1 = oriPivot.y * target.rect.height * tarCurScale * -1f;t2 = (1 - oriPivot.y) * target.rect.height * tarCurScale;mouseLocalForTarget.y = Mathf.Clamp(mouseLocalForTarget.y, t1, t2);curPivot.y = Remap(mouseLocalForTarget.y, t1, t2, 0f, 1f);target.pivot = curPivot;curPos = oriPos + new Vector3((curPivot - oriPivot).x * target.rect.width * canvasScale * tarCurScale, (curPivot - oriPivot).y * target.rect.height * canvasScale * tarCurScale, 0);target.position = curPos;}// Canvas RenderModel = ScreenSpaceCamera 模式时,可以使用该模式private void ScaleScreenSpaceCamera(Vector2 center, float delta){// 过滤掉重复的轴心设置if (lastCenter != center){SetPivot(center);lastCenter = center;}tarCurScale = target.localScale.x;tarCurScale += (Input.GetAxis("Mouse ScrollWheel") > 0) ? 0.1f : (-0.1f);if (tarCurScale <= 3 && tarCurScale >= 0.5f){target.localScale = Vector3.one * tarCurScale;}else{tarCurScale = (tarCurScale > 3) ? 3f : 0.5f;}}// Canvas RenderModel = ScreenSpaceOverlay 模式时,可以使用该模式private void ScaleScreenSpaceOverlay(Vector2 center, float delta){float delX = center.x - target.position.x;float delY = center.y - target.position.y;Vector2 pivot = new Vector2();pivot.x = delX / target.rect.width / tarCurScale;pivot.y = delY / target.rect.height / tarCurScale;tarCurScale = target.localScale.x;tarCurScale += (delta > 0) ? 0.1f : (-0.1f);if (tarCurScale <= 3 && tarCurScale >= 0.5f){target.localScale = Vector3.one * tarCurScale;}else{tarCurScale = (tarCurScale > 3) ? 3f : 0.5f;}target.pivot += pivot;// 增加画布的缩放系数,当画布大小和screen大小不一致时,画布也是有缩放的target.position += new Vector3(delX, delY, 0) * canvasScale;}// 重映射函数,将x 从t1—t2的范围内映射到s1—s2的范围private float Remap(float x, float t1, float t2, float s1, float s2){return (x - t1) / (t2 - t1) * (s2 - s1) + s1;}//private void OnDrawGizmos()//{//    Gizmos.color = Color.red;//    Gizmos.DrawSphere(target.position, 0.2f);//}
}

说明

该方法主要是通过将鼠标位置转化为到ui物体的Pivot坐标,动态改变UI物体的pivot来实现以鼠标为中心的缩放。在计算过程中需要注意Canvas在不同的模式下画布的引起物体位置偏移。还有一种方法是创建一个空物体作为要缩放对象的父物体,缩放时将父物体位置设置到鼠标世界空间位置,通过通过缩放父物体来实现以鼠标点为中心缩放的效果,这个方法将在后面补充。

ScreenSpaceCamera 下,设置pivot的方法计算可能不好,能力有限,总觉得有某个地方没有想通,肯定是可以有更简单的方法。

Unity实现以鼠标为中心缩放物体(一)相关推荐

  1. unity相机脚本 鼠标滚轮控制缩放

    1.创建一个onWhellScroll函数并放在LateUpdate内(LateUpdate是内置函数与Update一样) public class detailCameraHandle : Mono ...

  2. js 以鼠标为中心缩放图片

    原理 使用的绘制方法 void ctx.drawImage(image, dx, dy, dWidth, dHeight); 参数说明: dx image的左上角在目标canvas上 X 轴坐标. d ...

  3. Unity2D 实现UGUI滚动鼠标滑轮以鼠标位置点为中心缩放图片

    先放参考文章: Unity3d UGUI以鼠标位置点为中心缩放图片(含项目源码)https://blog.csdn.net/qq_33789001/article/details/117749837 ...

  4. Unity鼠标控制摄像机 围绕物体旋转

    Unity鼠标控制摄像机 围绕物体旋转 角度范围判定 // An highlighted block using UnityEngine;public class CameraCtrl : MonoB ...

  5. Qwt Plot Magnifier 缩放以鼠标为中心

    Qwt Plot Magnifier 缩放以鼠标为中心 问题 功能预览 更改 问题 使用QwtPlotMagnifier时,用滚轮缩放时,缩放中心是QwtPlot的中间. 现需要改成在鼠标中间进行缩放 ...

  6. unity 用四元素实现摄像机的跟随鼠标旋转,缩放

    此文章中的摄像机是第三人称游戏摄像机,脚本挂载在游戏人物身上 用四元素实现的unity摄像机跟随鼠标旋转缩放,并且有障碍物遮挡的时候摄像机会自动往前移. float MouseZ = -(Input. ...

  7. QT学习笔记(三)——vs2019+Qt实现打开影像并以鼠标为中心用滚轮控制图片缩放

    vs2019+Qt实现打开影像并以鼠标为中心用滚轮控制图片缩放 之前写了一个博客讲怎么显示一张影像,那个是基于Qpainter的 今天使用QLabel来显示影像,并且用鼠标滚轮控制缩放. 关于图像的打 ...

  8. Unity鼠标滚轴缩放大小

    void Update () {//鼠标滚轴缩放大小(轴值取值范围-1~1)//大于0时if(Input.GetAxis("Mouse ScrollWheel") > 0){ ...

  9. Unity实用小工具或脚本——3D物体带坐标轴的拖拽

    一.前言 我们最近要做一个线路的规划编辑,并且是在三维场景中,编辑完就立马能用.立马能用还好说,有特别多的轮子可以用,在三维场景中实时编辑就有点意思了.其实功能就是类似于在Unity的编辑界面操作一个 ...

最新文章

  1. 7-Python3从入门到实战—基础之数据类型(字典-Dictionary)
  2. office365中文版
  3. UA OPTI512R 傅立叶光学导论23 透镜成像系统的物理光学模型
  4. Android开源框架——依赖注入ButterKnife
  5. android studio中使用x5 webview来读写cookies的问题
  6. iOS中的多线程一般使用场景
  7. Chess Queen【数学】
  8. pandas尾部添加一条_Numpy与Pandas
  9. 【视频目标检测数据集收集】B站、YouTube等各大网站视频下载工具:Annie(现更名为lux)的下载与安装教程
  10. c语言指数公式_c语言指数函数
  11. C中code定义的数据要存储在ROM程序存储区基于8051单片机C语言编程实例100例都用CODE定义数组。因为51单片机RAM128字节汇编语言标号代表指令所在ROM地址标号+DB定义数据在ROM
  12. 程序员通常都有哪些业余爱好
  13. CRT控制台显示中文乱码问题
  14. 贾扬清:把生命浪费在有意思的事情上
  15. 677_AUTOSAR_TR_Methodology_文档阅读4
  16. [BZOJ]1071: [SCOI2007]组队 STL优先队列
  17. win10系统Apache无法启动怎么办?
  18. 商务统计_14 统计指数
  19. layui表格复选框赋值,获取表格复选框选中值,表格复选框回选
  20. 利用WebOffice控件来进行编辑office文档。

热门文章

  1. 建站系列教程(二)--本地局域网访问和域名解析
  2. 1-6 类、属性和方法(一)
  3. 基于drawio作图系统仿processOn风格的二次开发
  4. Python字典常见操作方法 - 增加、删除、修改
  5. Zabbix6.0LTS 如何帮助应对现有挑战?创始人35分钟演讲分享
  6. win10小课堂:常见电脑蓝屏的解决办法
  7. 面经 大数据开发工程师 招银网络科技
  8. Linux多进程实现生产者消费者问题
  9. Part I A Simple game of air hockey(空气曲棍球)-Chapter2 Defining Vertices and Shaders
  10. 微信小程序开发文档和开发工具放出破解版-亲测可用