Unity实现自定义图集(四)

以下内容是根据Unity 2020.1.0f1版本进行编写的

在之前的篇章中已经把自定义图集在编辑器上的使用,以及运行时所需的信息都准备好了,接下来就是魔改UGUI的Image组件,使其能够像Image那样运行时如果引用的资源有打自定义图集,则加载对应自定义图集的Texture。

1、思路

在这里插入图片描述
如图,想要模仿Image组件是怎么判断一个资源是否从有打图集的,先直接在Image组件上搜SpriteAtlas,发现只能搜出如上图这几个结果。

看起来应该是有一个SpriteAtlas的管理类,在Image初始化的时候注册了一个RebuildImage的事件,每当资源变动/运行游戏等情况时,就会执行这个RebuildImage的方法,方法调用时会传入一个SpriteAtlas的参数,SpriteAtlas类中有个CanBindTo的方法,看来这个应该就是判断资源是否有打图集的方法了。
在这里插入图片描述
再点进去看发现是外部方法,于是打开反编译软件看看有没有具体的代码
在这里插入图片描述
反编译软件里显示代码是写到了C++的内部文件,这样就看不到具体的实现过程了。但是我们可以自己实现一个类似的。

我们可以在自定义图集中多保存一份图集内全部资源的guid对应路径的字典(去掉之前的guid列表),然后在自定义的Image组件中保存一份当前引用资源的guid,当在某一个图集中找到自定义Image组件中的guid时,则认为该Image组件引用的资源已经打了自定义图集。

接下来就是如何在运行时把有自定义图集的自定义Image组件中的Texture换成自定义图集的Texture,并将其uv设对。

这里先实现编辑器的自定义图集Texture加载。

在前面的文章中就已经准备好了自定义图集的Texture,并且会在每次Unity启动前更新,那么编辑器下运行时只需要把存放在Library文件夹的Texture读取出来就可以了
在这里插入图片描述
读取出来后,自定义图集MyAtlas中已经保存有对应资源的uv信息了,这时候看Image代码(如图),发现传进去的uv是一个0~1的值。因此自定义图集保存时还需要多保存width和height两个值。

注意;这里不直接将保存的uv信息从int改成float后double,一是不希望保存太多小数,二是考虑到width和height值可能会有被其它地方用到的时候。

数据都准备好了,这时候还有一个问题,Image组件中,如果在上图的GenerateSimpleSprite方法中将原有的设置顶点信息和uv的代码去掉,增加判断当前Image资源是否已打自定义图集,并且加载图集的Texture并设置为材质球的Texture,会发现运行时资源是无法知道其guid的,甚至路径也不知道。

获取guid或者资源路径的代码一般使用的是AssetDataBase类,但是这个类是编辑器类,不能打包后在其它设备使用,打包时也会报错。看了一下Image的代码,猜测是Unity内部有自己的一套资源管理系统,能在运行时获取资源的信息,但是没有开放接口。

于是直接使用简单的办法,在自定义的Image组件上加一个guid变量,并且在对应的Editor类中对于每次Image引用的资源有变动,就刷新一次其引用资源的guid即可。

2、实现

在这里插入图片描述
首先需要去掉项目原来的UGUI插件,并从Unity官方下载UGUI源码,并将源码复制到项目中。(我这里复制的是魔改UGUI代码工程里的源码)

然后新建一个MyImage类,复制Image的代码,并按上面的思路修改
在这里插入图片描述
增加guid属性和纹理图属性,用于保存当前引用的资源guid和运行时资源对应图集的纹理图
在这里插入图片描述
在这里插入图片描述
接下来应该改动mainTexture,当获取mainTexture时,如果当前引用的资源存在自定义图集,那么应该直接返回自定义图集的图。

但是mainTexture没有set方法,只有get方法,因此先需要在其基础类Graphic类中将mainTexture虚拟属性增加一个空的set方法。然后再在MyImage中的get方法判断是否存在自定义图集的纹理图,若存在则直接返回,否则就按原来的代码执行。set方法也比较简单,就是把值赋给新增的m_MainTexture属性就行。

protected void SpriteGUI(){EditorGUI.BeginChangeCheck();EditorGUILayout.PropertyField(m_Sprite, m_SpriteContent);if (EditorGUI.EndChangeCheck()){var newSprite = m_Sprite.objectReferenceValue as Sprite;if (newSprite){MyImage.Type oldType = (MyImage.Type)m_Type.enumValueIndex;if (newSprite.border.SqrMagnitude() > 0){m_Type.enumValueIndex = (int)MyImage.Type.Sliced;}else if (oldType == MyImage.Type.Sliced){m_Type.enumValueIndex = (int)MyImage.Type.Simple;}//自定义改动MyImage myImage = target as MyImage;if(myImage.sprite){string path = AssetDatabase.GetAssetPath(newSprite);string guid = AssetDatabase.AssetPathToGUID(path);m_guid.stringValue = guid;Debug.Log("image editor set guid: " + guid);}else{m_guid.stringValue = "";}EditorUtility.SetDirty(myImage);}(serializedObject.targetObject as MyImage).DisableSpriteOptimizations();}

在Editor文件夹下新建MyImageEditor脚本,复制ImageEditor代码,增加每次资源变动获取资源的guid并赋值到MyImage类的guid属性上。(自定义改动部分)
在这里插入图片描述
接着在MyAtlas类实现一个类似SpriteAtlas的CanBindTo方法。用于判断资源是否存在自定义图集。这里仅实现了在编辑器模式下的图集纹理加载,即加载保存到Library文件夹下的纹理图。
在这里插入图片描述
同理,在自定义图集管理类中也需要加一个CanBindTo方法,用于全局调用。

最后是改一下生成VertexHelper的方法,对应有4个方法,分别对应Image Type中的simple、sliced、tiled、filled模式。其中,平铺图tiled模式,如果将平铺图资源打进图集,可能会导致顶点数大大增加,因此一般不会把平铺图打图集,此外平铺图的生成比较麻烦,所以这里的改动忽略了平铺图生成VertexHelper的方法(即使用tiled平铺图不会合批)。

代码如下:

Simple模式:

private void GenerateSimpleSprite(VertexHelper vh, bool lPreserveAspect){Vector4 drawingDimensions = GetDrawingDimensions(lPreserveAspect);Vector4 vector = (activeSprite != null) ? DataUtility.GetOuterUV(activeSprite) : Vector4.zero;Color color = this.color;vh.Clear();//vh.AddVert(new Vector3(drawingDimensions.x, drawingDimensions.y), color, new Vector2(vector.x, vector.y));//vh.AddVert(new Vector3(drawingDimensions.x, drawingDimensions.w), color, new Vector2(vector.x, vector.w));//vh.AddVert(new Vector3(drawingDimensions.z, drawingDimensions.w), color, new Vector2(vector.z, vector.w));//vh.AddVert(new Vector3(drawingDimensions.z, drawingDimensions.y), color, new Vector2(vector.z, vector.y));//自定义改动if(Application.isPlaying){MyAtlas atlas = MyAtlasManager.CanBindTo(this);Debug.LogError("atlas: " + atlas);if (atlas){Texture2D texture2D = atlas.GetTexture(OnSetMainTexture);RectInfo rectInfo = atlas.GetRectInfo(guid);if (texture2D && rectInfo != null){mainTexture = texture2D;int textureWidth = atlas.GetWidth();int textureHeight = atlas.GetHeight();float x = (float)(rectInfo.x + vector.x * rectInfo.width) / textureWidth;float y = (float)(rectInfo.y + vector.y * rectInfo.height) / textureHeight;float z = (float)(rectInfo.x+ vector.z * rectInfo.width) / textureWidth;float w = (float)(rectInfo.y+ vector.w * rectInfo.height) / textureHeight;vector = new Vector4(x, y, z, w);}}else{mainTexture = null;}}vh.AddVert(new Vector3(drawingDimensions.x, drawingDimensions.y), color, new Vector2(vector.x, vector.y));vh.AddVert(new Vector3(drawingDimensions.x, drawingDimensions.w), color, new Vector2(vector.x, vector.w));vh.AddVert(new Vector3(drawingDimensions.z, drawingDimensions.w), color, new Vector2(vector.z, vector.w));vh.AddVert(new Vector3(drawingDimensions.z, drawingDimensions.y), color, new Vector2(vector.z, vector.y));vh.AddTriangle(0, 

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

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

相关文章

Maven 入门详解

在 Java 世界中,项目依赖管理就像是一张错综复杂的网,稍有不慎就会陷入 “依赖地狱”。而 Maven,就像一位经验丰富的"项目经理",为我们提供了一套标准化的项目管理方案,将混乱的依赖关系梳理得井井有条。 1.…

IDM6.42下载器最新版本,提速你的网络生活!

🚀【速度与激情,IDM 6.42来袭!】💣 Hey, 亲爱的下载达人们!👋 今天我要给你们安利一个神器——Internet Download Manager(简称IDM),版本6.42,这可不是普通的…

k8s为什么用Calico

‌Calico是一种开源的网络和安全解决方案,主要用于容器、虚拟机、宿主机之间的网络连接。‌ 它支持Kubernetes、OpenShift、Docker EE、OpenStack等PaaS或IaaS平台,提供高效的网络通信和安全控制功能‌12。 Calico的核心组件包括Felix、etcd、BIRD等。F…

leetcode 22.括号生成

思路:dfs回溯 其实这道题看起来很像栈,但考虑到多种可能方案输出,我们需要用dfs来做。 乍一看好像没啥思路。我们可以从括号的特点入手,括号我们知道都是成对存在的,那么无论多少对括号,其实第一个符号肯…

数据结构(排序)

1概述 一、定义 排序是将一组数据元素按照某个关键字的值递增或递减的次序重新排列的过程。这个关键字是数据元素中的某个数据项,通过比较关键字的大小来确定数据元素的先后顺序。 二、目的 便于查找 例如在一个有序数组中查找某个元素,使用二分查找等算…

DeepACO:用于组合优化的神经增强蚂蚁系统解决TSP问题的代码阅读

总体概括 DeepACO与普通ACO不同的是将问题输入实例输入到一个训练的网络中,将网络训练成为一个类似于专家知识的模块,可以生成相应的启发式矩阵网络,从而省去相应的专家知识。 其中在训练网络的代码中: 是进行监督式训练通过trai…

TCL Android面试题大全及参考答案

能谈谈Jetpack组件吗? Jetpack 是一套用于 Android 开发的工具和组件库,它可以帮助开发者更高效地构建高质量的 Android 应用。 一、主要组件分类 架构组件: ViewModel:负责存储和管理与界面相关的数据,当屏幕旋转或配置发生变化时,ViewModel 可以帮助保存数据,避免数据…

shutil模块简介

shutil 是 Python 标准库中的一个模块,主要用于文件和目录的高阶操作。 以下是 shutil 模块的一些常见功能: 复制文件和目录: shutil.copy(src, dst): 复制文件内容和权限。dst 可以是文件路径或目录路径。如果是目录路径,文件将…

大模型基础:基本概念、Prompt、RAG、Agent及多模态

随着大模型的迅猛发展,LLM 作为人工智能的核心力量,正以前所未有的方式重塑着我们的生活、学习和工作。无论是智能语音助手、自动驾驶汽车,还是智能决策系统,大模型都是幕后英雄,让这些看似不可思议的事情变为可能。本…

前端框架选择指南

前端框架选择指南 引言 在搭建现代网站时,你可能会面临一个常见但又重要的抉择——该选择哪个前端框架?这是一个看似简单的问题,但却隐藏着无数的选择和复杂性。前端框架就像建筑的蓝图,为建筑师(开发者)提供了构建结构的方式。而不同的框架则对应了不同的建筑风格和材…

软键盘一直存在实现

在此记录系统需要提供方法给APP可以控制当接入物理键盘时软键盘保持显示实现方法,网上找了很多方法都不管用,最终还是要自己去研究源码和系统设置内功能,最终找到了一个超级简单的方法;我们只需要在\packages\apps\Settings\src\c…

java中的I/O(8个案例+代码+效果图)

目录 1.File类 1)常用构造方法 1)File(String pathname) 2)File(String parent, String child) 3)File(File parent, String child) 2)常用方法 1)boolean canRead() 2)boolean canWrite() 3&am…

计算机网络——ftp

在网络通信中,控制连接和数据连接是两种不同类型的连接,它们各自具有特定的功能和用途。 一、控制连接 定义与功能: 控制连接主要用于在通信双方之间传输控制信息,以建立、维护和终止数据连接。它负责协调和管理数据传输的过程&am…

Leetcode - 周赛418

目录 一,3309. 连接二进制表示可形成的最大数值 二,3310. 移除可疑的方法 三,3311. 构造符合图结构的二维矩阵 四,3312. 查询排序后的最大公约数 一,3309. 连接二进制表示可形成的最大数值 本题数据范围较小&#…

操作系统中的进程管理详细介绍——进程的调度与通信

进程管理是操作系统中至关重要的功能之一,它负责协调和管理计算机系统中运行的所有进程。以下是对进程管理各个方面的详细介绍: 1. 进程调度 进程调度是操作系统决定哪个进程在何时运行的过程,目的是最大化CPU的利用率和系统的整体性能。常…

chatGPT模型接口分享

前言: 仅供学习和交流,请合理使用。 API:https://api.gptnet.org key:sk-x9Rmq3HeHh5z9EIi8wFaXCl02OfxRSk5UAFodYm1o4zo5X3i 支持模型:gpt-3.5-turbo、gpt-3.5-turbo-16k、gpt-4o-mini、llama-3.1-405b 暂时支持以上四个模型…

Java基础-基础知识体系小结 Q/A

文章目录 知识体系Q&AJava 中应该使用什么数据类型来代表价格?怎么将 byte 转换为 String?Java 中怎样将 bytes 转换为 long 类型?存在两个类,B 继承 A,C 继承 B,我们能将 B 转换为 C 么? 如 C (C) B;Java 中 操作符是线…

Java初阶~~四种内部类总结

文章目录 1.内部类的分类2.局部内部类2.1.基本语法2.2就近原则的理解 3.匿名内部类3.1基于接口的匿名内部类3.2基于普通类的匿名内部类3.3基于抽象类的匿名内部类3.4匿名内部类的细节3.5匿名内部类实践3.5.1作为实参进行传递3.5.2实践案例 4.成员内部类4.1基本介绍4.2外部类&am…

5本一投就中的极速期刊,性价比高,1周-1个月录用,见刊极快!

在当今快节奏的学术界,研究者们不仅追求高质量的研究成果,还希望能够迅速地将这些成果分享给全球的同行。为此,科检易学术精心挑选了10本以高效审稿流程著称的期刊,这些期刊不仅性价比高,而且从投稿到录用的时间极短&a…

ARM base instruction -- asr

算术右移,结果带符号。 Arithmetic Shift Right (immediate) shifts a register value right by an immediate number of bits, shifting in copies of the sign bit in the upper bits and zeros in the lower bits, and writes the result to the destination reg…