Unity Image(RawImage) 实现按轴心放大缩小,序列化存储轴心信息,实现编译器窗口保存轴心

工作时分配给我的要实现的功能,写的时候遇到挺多的坑的,在此记录一下

效果

放大缩小的效果
请添加图片描述

2.编译器扩展窗口记录请添加图片描述

实现点

1.Json序列化存储图片轴心位置, 放大倍率,放大所需要的事件
2.用了编译器扩展工具便于保存轴心信息

坑点

1.Image和RawImage的坐标都是以轴心位置计算的,更改轴心就需要重定位
2.确保画布的分辨率和测试的屏幕分辨率一致
3.计算轴心偏移和别忘记在乘以自己的放大倍率

工具的使用

1.打开WSC/保存图片轴心工具,在Image位置挂在需要保存轴心的图像,输出name作为key,并在Scene窗口中直接拖动轴心确定位置(不建议在Inspector中手动输入轴心修改,这样会让图像重定位)
请添加图片描述请添加图片描述
2.程序调用

无论是简化key传入还是传入轴心对象的方式都需要传入要放大的Image

请添加图片描述

请添加图片描述

代码

using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;namespace YBZ
{public class ControlImage : MonoBehaviour{   // 需要控制的图片[Header("2D的图像,如果是视屏改为RawImage进行推流即可")]public Image image;// Start is called before the first frame updatevoid Start(){   if(image == null){if(!TryGetComponent<Image>(out image)){gameObject.AddComponent<Image>();image = GetComponent<Image>();}}rect = image.GetComponent<RectTransform>();// 先读取json中的文件Utility.Instance.ReadData();StartCoroutine(five());}IEnumerator five(){Utility.Instance.ImageZoom(image, Utility.Instance.dict["1"]);yield return new WaitForSeconds(1);Utility.Instance.ImageZoom(image, Utility.Instance.dict["2"]);yield return new WaitForSeconds(1.01f);Utility.Instance.ImageZoom(image, Utility.Instance.dict["3"]);yield return new WaitForSeconds(1.01f);Utility.Instance.ImageZoom(image, Utility.Instance.dict["4"]);yield return new WaitForSeconds(1.01f);Utility.Instance.ImageZoom(image, Utility.Instance.dict["5"]);yield return new WaitForSeconds(3.01f);Utility.Instance.ImageZoom(image, Utility.Instance.dict["6"]);yield return new WaitForSeconds(1.01f);Utility.Instance.ImageZoom(image, Utility.Instance.dict["7"]);yield return new WaitForSeconds(1.51f);Utility.Instance.ImageZoom(image, Utility.Instance.dict["8"]);yield return new WaitForSeconds(1.51f);Utility.Instance.ImageZoom(image, Utility.Instance.dict["9"]);yield return new WaitForSeconds(2.01f);Utility.Instance.ImageZoom(image, Utility.Instance.dict["10"]);yield return new WaitForSeconds(2.01f);Utility.Instance.ImageZoom(image, Utility.Instance.dict["11"]);yield return new WaitForSeconds(2.01f);Utility.Instance.ImageZoom(image, Utility.Instance.dict["12"]);yield return new WaitForSeconds(2.01f);Utility.Instance.ImageZoom(image, Utility.Instance.dict["RESET"]);}// 图片的放大接口public void ZoomEvent(Image image, string key){Utility.Instance.ZoomPivot(image, key);}}// 单例模式// 命名冲突时,请指定命名空间// 使用前一定要读取数据!public class Utility{public static Utility instance;public static Utility Instance { get{if(instance == null) instance = new Utility();return instance;}}// 放大点位置的字典public Dictionary<String, ZoomPoint> dict = new Dictionary<string, ZoomPoint>();//json文件的位置,这个位置默认是在SteamingAssets下的private string jsonFileName ="/2DPivots.json";private string filePath =""; // "StreamingAssets/2Dpivots"public void SetFilePath(string value) => filePath = value;// 写入数据public void WriteDataTest(){Data data = new Data();data.zoomPoints = new List<ZoomPoint>();ZoomPoint point1 = new ZoomPoint{name = "1",pivot = new Vector2(0.75f,0.75f)};ZoomPoint point2 = new ZoomPoint{name = "2",pivot = new Vector2(0.5f,0.5f)};data.zoomPoints[0] = point1;data.zoomPoints[1] = point2;string js = JsonUtility.ToJson(data);// 获取项目路径string fileUrl;if(filePath == ""){fileUrl = Application.streamingAssetsPath + jsonFileName;}else{fileUrl = filePath;}using(StreamWriter sw  = new StreamWriter(fileUrl)){   sw.WriteLine(js); //保存数据sw.Close(); sw.Dispose();}}  public void WriteData(ZoomPoint zp){Data data = ReadData();if(data != null && data.zoomPoints != null){foreach(var temp in data.zoomPoints){if(temp.name == zp.name){Debug.LogError("轴心名字重复 !(⊙_⊙)?");return;}}}data.zoomPoints.Add(zp);string js = JsonUtility.ToJson(data);// 获取项目路径string fileUrl;if(filePath == ""){fileUrl = Application.streamingAssetsPath + jsonFileName;}else{fileUrl = filePath;}using(StreamWriter sw  = new StreamWriter(fileUrl)){   sw.WriteLine(js); //保存数据sw.Close(); // 关闭文档sw.Dispose();}Debug.Log("保存成功(*^▽^*)");}/// <summary>/// 读取数据,在外界不需要接受Data只需要调用即可,返回的Data仅供我自己编写其他程序耦合使用,忽略返回值/// 请在调用dict 前一定要先调用ReadData函数/// </summary>public Data ReadData(){// 获取项目路径string fileUrl;if(filePath == ""){fileUrl = Application.streamingAssetsPath + jsonFileName;}else{fileUrl = filePath;}//读取文件string readDate;using (StreamReader sr = File.OpenText(fileUrl)){readDate = sr.ReadLine();sr.Close();}Data data = JsonUtility.FromJson<Data>(readDate);// 分配内存if(data == null ){data = new Data();data.zoomPoints = new List<ZoomPoint>();return data;}// 数据保存到字典里foreach(ZoomPoint zp  in data.zoomPoints){dict.TryAdd(zp.name, zp);}return data;}/// <summary>/// 按点放大轴心,无法捕获动画一定确保放大的动画之间不会冲突,简化了ImageZoom的调用/// </summary>/// <param name="zoomObj">被放大图像</param>/// <param name="key">轴心的名字</param>public void ZoomPivot(Image zoomObj, string key){ImageZoom(zoomObj, dict[key]);}/// <summary>/// 按倍率,轴心定位的方法放大图形,如果目标的轴心不在中心,会在设定完轴心后将目标移动到轴心,/// 需要注意的事,图片的坐标位置是以轴心位置为确定的,也因此放大缩小不改变图像的世界坐标/// </summary>/// <param name="zoomObj">需要方法的图像</param>/// <param name="x">轴心的x</param>/// <param name="y">轴心的y</param>/// <param name="zoomMagnification">放大倍率</param>/// public void ImageZoom(Image zoomObj , ZoomPoint zp){float x = zp.pivot.x;float y = zp.pivot.y;float zoomMagnification = zp.zoomMagnification;float time = zp.time;// 当前和目标按图轴心位置 Vector3 currentPivotPostition = new Vector3(zoomObj.rectTransform.rect.width * zoomObj.rectTransform.pivot.x, zoomObj.rectTransform.rect.height * zoomObj.rectTransform.pivot.y) * zoomMagnification;Vector3 targetPivotPosition = new Vector3(zoomObj.rectTransform.rect.width * x, zoomObj.rectTransform.rect.height * y) * zoomMagnification;zoomObj.rectTransform.pivot = new Vector2(x, y); // 设定轴心zoomObj.transform.position += targetPivotPosition - currentPivotPostition; // 重定位Vector3 targetPostion = zoomObj.transform.position + currentPivotPostition - targetPivotPosition;//位移Translate(zoomObj, targetPostion, time);// 2023.7.30 经过测试,缩放仍然是更具初始轴心,能够达到理想效果不需要将LocalScale恢复为1// 为了结算范围失控的问题,需要将localScale恢复为1,再放大为需要的大小// zoomObj.rectTransform.localScale = new Vector3(1,1,1);Vector3 targetScale = new Vector3(zoomMagnification, zoomMagnification, zoomMagnification);zoomObj.rectTransform.DOScale(targetScale, time);}// 该方法主要是需要将目标点移动到坐标终点public void Translate(Image zoomObj, Vector3 target, float time){// 计算当前轴心和新轴心之间的位置Vector3 current = zoomObj.transform.position;// 移动zoomObj.transform.DOMove(target, time);}}// 数据存储接受类[Serializable]public class Data{// 不能用字典直接存储,可以采用数据列表这样的连续空间// public ZoomPoint[] zoomPoints;// public Dictionary<string, ZoomPoint> zoomPoints;public List<ZoomPoint> zoomPoints;}// 可序列化[Serializable]public class ZoomPoint{// 点名称, 将作为Key被字典存储public string name;// 轴心X坐标public Vector2 pivot = Vector2.one / 2;// 放大倍率,小于1是为缩小倍率,小于0是取绝对值,不允许原点对称缩放,需要保证计算轴心逻辑正确// 默认设为1.5f 放大倍率public float zoomMagnification = 5f;// 改变的需要的时间,默认设为1fpublic float time = 1.0f;public override string ToString(){return $"name = {this.name}, pivot = ({pivot.ToString()}), zoomMagnification = {this.zoomMagnification}, time = {this.time}";}}// 实现编译器窗口扩展public class Editor :  ScriptableWizard {//  文件路径public string filePath = Application.streamingAssetsPath + "/2DPivots.json";[SerializeField]public Image image;// 作为轴心点保存定位的Keynew public string name;// 轴心public Vector2 pivot;// 放大倍率public float zoomMagnification = 5f;// 动画时间public float time = 1.0f;[MenuItem("WSC/保存图片轴心")]public static void CreateWizard() {ScriptableWizard.DisplayWizard<Editor>("Image zoom info save","退出", "保存当前轴心");}private int count = 1;void OnWizardCreate(){Utility.Instance.SetFilePath(filePath);Utility.Instance.ReadData();Debug.Log("轴心更新完毕(^-^)V");}void OnWizardOtherButton(){pivot = image.rectTransform.pivot;if (name == null) name = (count++).ToString();ZoomPoint zp = new ZoomPoint{name = this.name,pivot = pivot,zoomMagnification = this.zoomMagnification,time = this.time};// reset image pivotUtility.Instance.WriteData(zp);}}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/22885.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度学习:探究Tensor和Numpy

目录 引言 1 pytorch中Tensor 1.1 什么是Tensor 1.2 为什么需要Tensor 1.3 如何创建Tensor 1.3.1 从已有其他数据结构转化创建为Tensor 1.3.2 随机初始化一个Tensor 1.3.3 从已保存文件加载一个Tensor 1.4 Tensor的特性 1.4.1 丰富的常用函数操作 1.4.2 灵活的dtype和…

maven开发利器:idea安装maven依赖分析插件 Maven Helper,谁用谁知道!

大家好&#xff0c;我是三叔&#xff0c;很高兴这期又和大家见面了&#xff0c;一个奋斗在互联网的打工人。 这篇博客给大家介绍一款博主实战开发中一直在使用的pom开发分析利器&#xff0c;教大家玩转maven&#xff1a;使用idea安装 Maven Helper 插件&#xff0c;可以分析依…

企业电子招标采购系统源码Spring Boot + Mybatis + Redis + Layui + 前后端分离 构建企业电子招采平台之立项流程图 tbms

&#xfeff; 项目说明 随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大&#xff0c;公司对内部招采管理的提升提出了更高的要求。在企业里建立一个公平、公开、公正的采购环境&#xff0c;最大限度控制采购成本至关重要。符合国家电子招投标法律法规及相关规范&am…

数据结构-链表

&#x1f5e1;CSDN主页&#xff1a;d1ff1cult.&#x1f5e1; &#x1f5e1;代码云仓库&#xff1a;d1ff1cult.&#x1f5e1; &#x1f5e1;文章栏目&#xff1a;数据结构专栏&#x1f5e1; 目录 目录 代码总览&#xff1a; 接口slist.h&#xff1a; slist.c: 1.什么是链表 1.1链…

用C语言构建一个数字识别卷积神经网络

卷积神经网络的具体原理和对应的python例子参见末尾的参考资料2.3. 这里仅叙述卷积神经网络的配置, 其余部分不做赘述&#xff0c;构建和训练神经网络的具体步骤请参见上一篇: 用C语言构建一个手写数字识别神经网路 卷积网络同样采用简单的三层结构&#xff0c;包括输入层con…

k8s pod数据存储Volumes

一、说在前面的话 在 Kubernetes 的 Deployment 中&#xff0c;您可以使用多种类型的 Volumes 来管理 Pod 中的数据。 作用是用来共享目录及配置&#xff0c;不用在每个pod里进行配置。 本文主要概述怎么使用HostPath、PersistentVolumeClaim、ConfigMap。 二、k8s有哪些Vol…

《golang设计模式》第一部分·创建型模式-04-抽象工厂模式(Abstract Factory)

文章目录 1. 概述1.1 角色1.2 类图 2. 代码示例2.1 设计2.2 代码2.3 类图 1. 概述 1.1 角色 AbstractFactory&#xff08;抽象工厂&#xff09;&#xff1a;它声明了一组用于创建产品的方法&#xff0c;每一个方法对应一种产品。ConcreteFactory&#xff08;具体工厂&#xf…

vue el-input 使用 回车键会刷新页面的问题

场景&#xff1a; vue项目中 在输入框输入字符并按下回车键搜索时&#xff0c;不会进行搜索&#xff0c; 而是会刷新页面 原因&#xff1a; 当form表单中只有一个input时&#xff0c;按下回车建会自动触发页面的提交功能&#xff0c; 产生刷新页面的行为 解决&#xff1a; 在…

Spring 事务详解(注解方式)

目 录 序言 1、编程式事务 2、配置声明式事务 2.1 基于TransactionProxyFactoryBean的方式&#xff08;不常用&#xff0c;因为要为每一个类配置TransactionProxyFactoryBean&#xff09; 2.2 基于AspectJ的XML方式&#xff08;常用&#xff0c;可配置在某些类下的所有子…

无涯教程-Perl - unless...else 语句函数

Perl 除非语句后可以跟可选的 else 语句&#xff0c;该语句在布尔表达式为true时执行。 unless...else - 语法 Perl编程语言中的unless... else 语句的语法为- unless(boolean_expression) {# statement(s) will execute if the given condition is false } else {# stateme…

322. 零钱兑换

322. 零钱兑换 原题链接&#xff1a;完成情况&#xff1a;一开始错误原因 解题思路&#xff1a;参考代码&#xff1a;__322 零钱兑换__错误思路还得是dp去做 原题链接&#xff1a; 零钱兑换 完成情况&#xff1a; 一开始错误 原因 /*解题思路&#xff1a;1.先sort一下coins…

react ant icon的简单使用

refer: 快速上手 - Ant Design 1.引入ant npm install antd --save 2.在页面引用&#xff1a; import { StarOutlined } from ant-design/icons; 如果想要引入多个icon&#xff0c;可以这样书写&#xff1a; import { UserOutlined, MailOutlined, PieChartOutlined } fr…

2023年第三届工业自动化、机器人与控制工程国际会议 | IET独立出版 | EI检索

会议简介 Brief Introduction 2023年第三届工业自动化、机器人与控制工程国际会议&#xff08;IARCE 2023&#xff09; 会议时间&#xff1a;2023年10月27 -30日 召开地点&#xff1a;中国成都 大会官网&#xff1a;www.iarce.org 2023年第三届工业自动化、机器人与控制工程国际…

SocialFi 的开发中如何利用 NFTScan API 获取 NFT 数据

SocialFi 作为社交媒体与 Web3 的创新融合&#xff0c;致力于构建更加开放去中心化的社交平台。它赋能用户拥有数据控制权、实现内容价值&#xff0c;并通过代币经济建立起激励与治理机制&#xff0c;这正是 Web3 社交的独特魅力所在。SocialFi 为我们描绘了一个更加用户驱动、…

数据安全能力框架模型-详细解读(三)

数据安全能力框架内涵 “奇安信数据安全能力框架”体现了数据安全治理从组织机构安全治理&#xff0c;到数字化环境具体管控、分析能力分层逐步落实的工程方法。 它以企业数据安全的战略目标和风险容忍度为输入&#xff0c;明确数据安全治理的组织&#xff1b;以合规与治理需…

AtcoderABC227场

A - Last CardA - Last Card 题目大意 一共 K 张卡片分发给 N 个人&#xff0c;这些人的编号为 1, 2, …, N 从第 A 个人开始&#xff0c;按照顺序依次将卡片发给以下人员&#xff1a;A, A1, A2, …, N, 1, 2, …问最后一个卡片将发给哪个人&#xff1f; 具体来说&#xff0c;…

uniapp自定义头部导航栏

有时我们需要一些特殊的头部导航栏页面&#xff0c;取消传统的导航栏&#xff0c;来增加页面的美观度。 下面我就教大家如何配置&#xff1a; 一、效果图 二、实现 首先在uniapp中打开pages.json配置文件&#xff0c;在单个路由配置style里面设置导航栏样式​​​​​​nav…

【网络基础实战之路】基于MGRE多点协议的实战详解

系列文章传送门&#xff1a; 【网络基础实战之路】设计网络划分的实战详解 【网络基础实战之路】一文弄懂TCP的三次握手与四次断开 【网络基础实战之路】基于MGRE多点协议的实战详解 【网络基础实战之路】基于OSPF协议建立两个MGRE网络的实验详解 PS&#xff1a;本要求基于…

【GitOps系列】使用 ArgoCD ApplicationSet 来实现多环境管理

文章目录 前言自动多环境管理概述自动化管理多环境实战示例应用简介ApplicationSet 简介部署 ApplicationSet访问多环境 创建新环境实验结语 前言 聊起多环境&#xff0c;通常可能会立即想到下面几个常见的环境&#xff1a; 开发环境测试环境预发布环境生产环境 为了让不同职…

JSP--Java的服务器页面

jsp是什么&#xff1f; jsp的全称是Java server pages,翻译过来就是java的服务器页面。 jsp有什么作用&#xff1f; jsp的主要作用是代替Servlet程序回传html页面的数据&#xff0c;因为Servlet程序回传html页面数据是一件非常繁琐的事情&#xff0c;开发成本和维护成本都非常高…