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.rhkb.cn/news/75632.html

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

相关文章

飞桨AI Studio可以玩多模态了?MiniGPT4实战演练!

MiniGPT4是基于GPT3的改进版本&#xff0c;它的参数量比GPT3少了一个数量级&#xff0c;但是在多项自然语言处理任务上的表现却不逊于GPT3。项目作者以MiniGPT4-7B作为实战演练项目。 创作者&#xff1a;衍哲 体验链接&#xff1a; https://aistudio.baidu.com/aistudio/proj…

前端如何打开钉钉(如何唤起注册表中路径与软件路径不关联的软件)

在前端唤起本地应用时&#xff0c;我查询了资料&#xff0c;在注册表中找到腾讯视频会议的注册表情况&#xff0c;如下&#xff1a; 在前端代码中加入 window.location.href"wemeet:"; 就可以直接唤起腾讯视频会议&#xff0c;但是我无法唤起钉钉 之所以会这样&…

leetcode每日一题Day2——344. 反转字符串

✨博主&#xff1a;命运之光 &#x1f984;专栏&#xff1a;算法修炼之练气篇&#xff08;C\C版&#xff09; &#x1f353;专栏&#xff1a;算法修炼之筑基篇&#xff08;C\C版&#xff09; &#x1f433;专栏&#xff1a;算法修炼之练气篇&#xff08;Python版&#xff09; …

【css】css实现一个简单的按钮

四种链接状态分别是&#xff1a; a:link - 正常的&#xff0c;未访问的链接a:visited - 用户访问过的链接a:hover - 用户将鼠标悬停在链接上时a:active - 链接被点击时 <style> a:link, a:visited {//未访问、访问过background-color: #07c160;//设置背景颜色color: wh…

【ASP.NET MVC】使用动软(五)(13)

一、问题 前文完成的用户登录后的首页如下&#xff1a; 后续账单管理、人员管理等功能页面都有相同的头部&#xff0c;左边和下边&#xff0c;唯一不同的右边内容部分&#xff0c;所以要解决重复设计的问题。 二、解决方法——使用布局页 在Views上右键添加新建项&#xff…

基于量子同态加密的改进多方量子私有比较

摘要量子同态加密在隐私保护方面具有明显的优势。本文提出了一种改进的基于量子同态加密的多方量子私钥比较协议。首先&#xff0c;引入可信密钥中心&#xff0c;安全辅助加密密钥的分发和解密密钥的更新&#xff0c;同时防止恶意服务器发布虚假结果的攻击;在保证所有参与者得到…

RPC原理与Go RPC详解

文章目录 RPC原理与Go RPC什么是RPC本地调用RPC调用HTTP调用RESTful API net/rpc基础RPC示例基于TCP协议的RPC使用JSON协议的RPCPython调用RPC RPC原理 RPC原理与Go RPC 什么是RPC RPC&#xff08;Remote Procedure Call&#xff09;&#xff0c;即远程过程调用。它允许像调用…

Spring Boot 配置多数据源【最简单的方式】

Druid连接池 Spring Boot 配置多数据源【最简单的方式】 文章目录 Druid连接池 Spring Boot 配置多数据源【最简单的方式】 0.前言1.基础介绍2.步骤2.1. 引入依赖2.2. 配置文件2.3. 核心源码Druid数据源创建器Druid配置项 DruidConfig 3.示例项目3.1. pom3.1.1. 依赖版本定义3.…

matlab使用教程(8)—绘制三维曲面图

1网格图和曲面图 MATLAB 在 x-y 平面中的网格上方使用点的 z 坐标来定义曲面图&#xff0c;并使用直线连接相邻的点。mesh 和surf 函数以三维形式显示曲面图。 • mesh 生成仅使用颜色来标记连接定义点的线条的线框曲面图。 • surf 使用颜色显示曲面图的连接线和面。 MATL…

网络安全 Day26-PHP 简单学习

PHP 简单学习 1. 为什么要学习PHP2. PHP语法3. php 变量4. 字符串数据5. PHP 函数6. 数组 1. 为什么要学习PHP php存量多开源软件多很多安全流程 渗透方法 sql注入基于PHP语言入门简单 2. PHP语法 格式: <?php 内容?>或<?内容?>结尾分号例子<?php phpin…

深度学习实践——循环神经网络实践

系列实验 深度学习实践——卷积神经网络实践&#xff1a;裂缝识别 深度学习实践——循环神经网络实践 深度学习实践——模型部署优化实践 深度学习实践——模型推理优化练习 代码可见于&#xff1a;https://download.csdn.net/download/weixin_51735061/88131380?spm1001.201…

【Linux】进程间通信——管道

目录 写在前面的话 什么是进程间通信 为什么要进行进程间通信 进程间通信的本质理解 进程间通信的方式 管道 System V IPC POSIX IPC 管道 什么是管道 匿名管道 什么是匿名管道 匿名管道通信的原理 pipe()的使用 匿名管道通信的特点 拓展代码 命名管道 什么是命…

ChatGPT结合知识图谱构建医疗问答应用 (二) - 构建问答流程

一、ChatGPT结合知识图谱 上篇文章对医疗数据集进行了整理&#xff0c;并写入了知识图谱中&#xff0c;本篇文章将结合 ChatGPT 构建基于知识图谱的问答应用。 下面是上篇文章的地址&#xff1a; ChatGPT结合知识图谱构建医疗问答应用 (一) - 构建知识图谱 这里实现问答的流程…

备忘录模式——撤销功能的实现

1、简介 1.1、概述 备忘录模式提供了一种状态恢复的实现机制&#xff0c;使得用户可以方便地回到一个特定的历史步骤。当新的状态无效或者存在问题时&#xff0c;可以使用暂时存储起来的备忘录将状态复原。当前很多软件都提供了撤销&#xff08;Undo&#xff09;操作&#xf…

Spring AOP

1.什么是 Spring AOP&#xff1f; AOP&#xff08;Aspect Oriented Programming&#xff09;&#xff1a;面向切面编程&#xff0c;它是⼀种思想&#xff0c;它是对某⼀类事情的集中处理。⽐如⽤户登录权限的效验&#xff0c;没学 AOP 之前&#xff0c;我们所有需要判断⽤户登…

ClickHouse(七):Clickhouse数据类型-2

进入正文前&#xff0c;感谢宝子们订阅专题、点赞、评论、收藏&#xff01;关注IT贫道&#xff0c;获取高质量博客内容&#xff01; &#x1f3e1;个人主页&#xff1a;含各种IT体系技术&#xff0c;IT贫道_Apache Doris,Kerberos安全认证,大数据OLAP体系技术栈-CSDN博客 &…

openlayers渲染rgb三波段cog时达到类似rgba的效果(去掉黑底)

图是arcgis渲染成rgb的&#xff0c;由于没有透明度波段&#xff0c;底下是黑的。 为了能在前端显示透明效果&#xff0c;之前是用python处理数据&#xff0c;给它加个透明度波段 后来研究了一下ol的样式表达式&#xff0c;可以直接在前端去掉黑底 样式设置代码如下 const s…

Socks IP轮换:为什么是数据挖掘和Web爬取的最佳选择?

在数据挖掘和Web爬取的过程中&#xff0c;IP轮换是一个非常重要的概念。数据挖掘和Web爬取需要从多个网站或来源获取数据&#xff0c;而这些网站通常会对来自同一IP地址的请求进行限制或封锁。为了避免这些问题&#xff0c;数据挖掘和Web爬取过程中需要使用Socks IP轮换技术。在…

云原生势不可挡,如何跳离云原生深水区?

云原生是云计算领域一大热词&#xff0c;伴随云原生概念而来的是数字产业迎来井喷、数字变革来临、数字化得以破局以及新一波的技术红利等等。云原生即“云”原生&#xff0c;顾名思义是让“应用”最大程度地利用云的能力&#xff0c;发挥云价值的最佳路径。具体来说&#xff0…

Eureka增加账号密码认证登录

一、业务背景 注册中心Eureka在微服务开发中经常使用到&#xff0c;用来管理发布的微服务&#xff0c;供前端或者外部调用。但是如果放到生产环境&#xff0c;我们直接通过URL访问的话&#xff0c;这显然是不安全的。 所以需要给注册中心加上登录认证。 通过账号和密码认证进行…