Unity UGUI图文混排(五) -- 一张图集对应多个Text
继上一篇说的更新了一张图集对应多个Text的功能,为了节省资源嘛
这里,但是也没有舍弃之前的一个Text一个图集,因为我感觉应该两个都有用,于是我重新写了一个脚本
1.其实大体跟前面的都没变,解析标签,获取表情的相关数据,这里只是将绘制图片的功能,移植到SpriteGraphic上,本地增加了一个刷新图片绘制信息的函数。
麻烦的是去找到SpriteGraphic绘制图片,也是因为这个感觉有很大的潜在问题,不过基本能用,具体看脚本
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
using System.Text.RegularExpressions; public class InlieSpriteText : Text { /// <summary>
/// 用正则取标签属性 名称-大小-宽度比例
/// </summary>
private static readonly Regex m_spriteTagRegex =
new Regex(@"<quad name=(.+?) size=(\d*\.?\d+%?) width=(\d*\.?\d+%?) />", RegexOptions.Singleline); /// <summary>
/// 图片资源
/// </summary>
private SpriteAsset m_spriteAsset;
/// <summary>
/// 图片渲染组件
/// </summary>
private SpriteGraphic m_spriteGraphic;
/// <summary>
/// CanvasRenderer
/// </summary>
private CanvasRenderer m_spriteCanvasRenderer; /// <summary>
/// 图片渲染管理
/// </summary>
private SpriteGraphicManager m_SGManager; #region 动画标签解析
//最多动态表情数量
int AnimNum = 8;
// List<int> m_AnimIndex;
List<SpriteTagInfor[]> m_AnimSpiteTag;
public List<InlineSpriteInfor[]> m_AnimSpriteInfor;
#endregion /// <summary>
/// 初始化
/// </summary>
protected override void OnEnable()
{
//在编辑器中,可能在最开始会出现一张图片,就是因为没有激活文本,在运行中是正常的。可根据需求在编辑器中选择激活...
base.OnEnable();
//对齐几何
alignByGeometry = true; #region 为了将SpriteGraphicManager显示到最上级,这里的SpriteGraphicManager可能会放在最下面,所以需要从全局去找
if (m_SGManager == null)
m_SGManager = GameObject.FindObjectOfType<SpriteGraphicManager>();
#endregion if (m_SGManager != null)
{
m_spriteGraphic = m_SGManager.GetComponent<SpriteGraphic>();
m_spriteCanvasRenderer = m_SGManager.GetComponent<CanvasRenderer>();
m_spriteAsset = m_spriteGraphic.m_spriteAsset;
} //初始化 调用顶点绘制
SetVerticesDirty();
} /// <summary>
/// 在设置顶点时调用
/// </summary>
public override void SetVerticesDirty()
{
base.SetVerticesDirty(); // m_AnimIndex = new List<int>();
m_AnimSpiteTag = new List<SpriteTagInfor[]>(); foreach (Match match in m_spriteTagRegex.Matches(text))
{
if (m_spriteAsset == null)
return; #region 解析动画标签
List<string> tempListName = new List<string>();
for (int i = 0; i < m_spriteAsset.listSpriteInfor.Count; i++)
{
// Debug.Log((m_spriteAsset.listSpriteInfor[i].name));
if (m_spriteAsset.listSpriteInfor[i].name.Contains(match.Groups[1].Value))
{
tempListName.Add(m_spriteAsset.listSpriteInfor[i].name);
}
}
if (tempListName.Count > 0)
{
SpriteTagInfor[] tempArrayTag = new SpriteTagInfor[tempListName.Count];
for (int i = 0; i < tempArrayTag.Length; i++)
{
tempArrayTag[i] = new SpriteTagInfor();
tempArrayTag[i].name = tempListName[i];
tempArrayTag[i].index = match.Index;
tempArrayTag[i].size = new Vector2(float.Parse(match.Groups[2].Value) * float.Parse(match.Groups[3].Value), float.Parse(match.Groups[2].Value));
tempArrayTag[i].Length = match.Length;
}
m_AnimSpiteTag.Add(tempArrayTag);
}
#endregion
}
} readonly UIVertex[] m_TempVerts = new UIVertex[4];
/// <summary>
/// 绘制模型
/// </summary>
/// <param name="toFill"></param>
protected override void OnPopulateMesh(VertexHelper toFill)
{
// base.OnPopulateMesh(toFill); if (font == null)
return; // We don't care if we the font Texture changes while we are doing our Update.
// The end result of cachedTextGenerator will be valid for this instance.
// Otherwise we can get issues like Case 619238.
m_DisableFontTextureRebuiltCallback = true; Vector2 extents = rectTransform.rect.size; var settings = GetGenerationSettings(extents);
cachedTextGenerator.Populate(text, settings); Rect inputRect = rectTransform.rect; // get the text alignment anchor point for the text in local space
Vector2 textAnchorPivot = GetTextAnchorPivot(alignment);
Vector2 refPoint = Vector2.zero;
refPoint.x = (textAnchorPivot.x == 1 ? inputRect.xMax : inputRect.xMin);
refPoint.y = (textAnchorPivot.y == 0 ? inputRect.yMin : inputRect.yMax); // Determine fraction of pixel to offset text mesh.
Vector2 roundingOffset = PixelAdjustPoint(refPoint) - refPoint; // Apply the offset to the vertices
IList<UIVertex> verts = cachedTextGenerator.verts;
float unitsPerPixel = 1 / pixelsPerUnit;
//Last 4 verts are always a new line...
int vertCount = verts.Count - 4; toFill.Clear(); //清楚乱码
for (int i = 0; i < m_AnimSpiteTag.Count; i++)
{
if (m_AnimSpiteTag[i].Length > 0)
{
//UGUIText不支持<quad/>标签,表现为乱码,我这里将他的uv全设置为0,清除乱码
for (int m = m_AnimSpiteTag[i][0].index * 4; m < m_AnimSpiteTag[i][0].index * 4 + 4; m++)
{
UIVertex tempVertex = verts[m];
tempVertex.uv0 = Vector2.zero;
verts[m] = tempVertex;
}
}
}
//计算标签 其实应该计算偏移值后 再计算标签的值 算了 后面再继续改吧
// CalcQuadTag(verts); if (roundingOffset != Vector2.zero)
{
for (int i = 0; i < vertCount; ++i)
{
int tempVertsIndex = i & 3;
m_TempVerts[tempVertsIndex] = verts[i];
m_TempVerts[tempVertsIndex].position *= unitsPerPixel;
m_TempVerts[tempVertsIndex].position.x += roundingOffset.x;
m_TempVerts[tempVertsIndex].position.y += roundingOffset.y;
if (tempVertsIndex == 3)
toFill.AddUIVertexQuad(m_TempVerts);
}
}
else
{
for (int i = 0; i < vertCount; ++i)
{
int tempVertsIndex = i & 3;
m_TempVerts[tempVertsIndex] = verts[i];
m_TempVerts[tempVertsIndex].position *= unitsPerPixel;
if (tempVertsIndex == 3)
toFill.AddUIVertexQuad(m_TempVerts);
}
} //计算标签 计算偏移值后 再计算标签的值
List<UIVertex> vertsTemp = new List<UIVertex>();
for (int i = 0; i < vertCount; i++)
{
UIVertex tempVer=new UIVertex();
toFill.PopulateUIVertex(ref tempVer,i);
vertsTemp.Add(tempVer);
}
CalcQuadTag(vertsTemp); m_DisableFontTextureRebuiltCallback = false; //更新绘制图片信息
if(m_SGManager!=null)
m_SGManager.UpdateSpriteInfor();
//DrawSprite();
} private IList<UIVertex> _OldVerts; #region 计算标签
/// <summary>
/// 解析quad标签 主要清除quad乱码 获取表情的位置
/// </summary>
/// <param name="verts"></param>
void CalcQuadTag(IList<UIVertex> verts)
{ m_AnimSpriteInfor = new List<InlineSpriteInfor[]>(); Vector3 _TempStartPos = Vector3.zero;
if(m_SGManager!=null)
_TempStartPos = transform.position - m_SGManager.transform.position; for (int i = 0; i < m_AnimSpiteTag.Count; i++)
{
SpriteTagInfor[] tempTagInfor = m_AnimSpiteTag[i];
InlineSpriteInfor[] tempSpriteInfor = new InlineSpriteInfor[tempTagInfor.Length];
for (int j = 0; j < tempTagInfor.Length; j++)
{
tempSpriteInfor[j] = new InlineSpriteInfor();
tempSpriteInfor[j].textpos = _TempStartPos + verts[((tempTagInfor[j].index + 1) * 4) - 1].position;
//设置图片的位置
tempSpriteInfor[j].vertices = new Vector3[4];
tempSpriteInfor[j].vertices[0] = new Vector3(0, 0, 0) + tempSpriteInfor[j].textpos;
tempSpriteInfor[j].vertices[1] = new Vector3(tempTagInfor[j].size.x, tempTagInfor[j].size.y, 0) + tempSpriteInfor[j].textpos;
tempSpriteInfor[j].vertices[2] = new Vector3(tempTagInfor[j].size.x, 0, 0) + tempSpriteInfor[j].textpos;
tempSpriteInfor[j].vertices[3] = new Vector3(0, tempTagInfor[j].size.y, 0) + tempSpriteInfor[j].textpos; //计算其uv
Rect newSpriteRect = m_spriteAsset.listSpriteInfor[0].rect;
for (int m = 0; m < m_spriteAsset.listSpriteInfor.Count; m++)
{
//通过标签的名称去索引spriteAsset里所对应的sprite的名称
if (tempTagInfor[j].name == m_spriteAsset.listSpriteInfor[m].name)
newSpriteRect = m_spriteAsset.listSpriteInfor[m].rect;
}
Vector2 newTexSize = new Vector2(m_spriteAsset.texSource.width, m_spriteAsset.texSource.height); tempSpriteInfor[j].uv = new Vector2[4];
tempSpriteInfor[j].uv[0] = new Vector2(newSpriteRect.x / newTexSize.x, newSpriteRect.y / newTexSize.y);
tempSpriteInfor[j].uv[1] = new Vector2((newSpriteRect.x + newSpriteRect.width) / newTexSize.x, (newSpriteRect.y + newSpriteRect.height) / newTexSize.y);
tempSpriteInfor[j].uv[2] = new Vector2((newSpriteRect.x + newSpriteRect.width) / newTexSize.x, newSpriteRect.y / newTexSize.y);
tempSpriteInfor[j].uv[3] = new Vector2(newSpriteRect.x / newTexSize.x, (newSpriteRect.y + newSpriteRect.height) / newTexSize.y); //声明三角顶点所需要的数组
tempSpriteInfor[j].triangles = new int[6];
}
m_AnimSpriteInfor.Add(tempSpriteInfor); _OldVerts = verts;
}
}
#endregion #region 更新图片的信息
public void UpdateSpriteInfor()
{
if (_OldVerts == null)
return; CalcQuadTag(_OldVerts);
}
#endregion }
2.这里新写了一个SpriteGraphicManager脚本用来管理SpriteGraphic的图片绘制,和获取InlieSpriteText传来的相关绘制图片的信息,SpriteGraphicManager就是绑定在SpriteGraphic上的,因为UGUI的渲染顺序是从上到下,SpriteGraphic的放置位置就显得比较尴尬了,应该可以用shader更改渲染层级,没去试,先这样吧,我这里将SpriteGraphic放在最下面的
using UnityEngine;
using System.Collections;
using System.Collections.Generic; /********
为了图片渲染在最上面
需要将他放砸canvas的最下层
应该可以改shader的渲染顺序 没去试 就这样写吧
*********/ [RequireComponent(typeof(SpriteGraphic))]
public class SpriteGraphicManager : MonoBehaviour { /// <summary>
/// 需要渲染的图片信息列表
/// </summary>
private List<InlineSpriteInfor> listSprite;
#region 动画标签解析
//最多动态表情数量
int AnimNum = 8;
List<InlineSpriteInfor[]> m_AnimSpriteInfor;
#endregion #region 更新图片信息
public void UpdateSpriteInfor()
{
listSprite = new List<InlineSpriteInfor>();
m_AnimSpriteInfor = new List<InlineSpriteInfor[]>(); // inline
// InlieSpriteText[] AllInlieSpriteText = GetComponentsInChildren<InlieSpriteText>();
// 找到所有InlieSpriteText的物体 ---- 这里隐藏问题蛮大的 他搜索的所有的InlieSpriteText
// 包括InlieSpriteText也是全局搜索的SpriteGraphicManager,意思SpriteGraphicManager最好只有一个
// 当然 可以自定义根据功能 自己改了 我这里是这么定义的
InlieSpriteText[] AllInlieSpriteText = GameObject.FindObjectsOfType<InlieSpriteText>(); for (int i = 0; i < AllInlieSpriteText.Length; i++)
{
if (AllInlieSpriteText[i].m_AnimSpriteInfor != null)
{
AllInlieSpriteText[i].UpdateSpriteInfor();
for (int j = 0; j < AllInlieSpriteText[i].m_AnimSpriteInfor.Count; j++)
{
m_AnimSpriteInfor.Add(AllInlieSpriteText[i].m_AnimSpriteInfor[j]);
listSprite.Add(AllInlieSpriteText[i].m_AnimSpriteInfor[j][0]);
}
}
}
DrawSprite();
}
#endregion #region update刷新动画
float fTime = 0.0f;
int iIndex = 0;
void Update()
{
if (m_AnimSpriteInfor == null)
return; fTime += Time.deltaTime;
if (fTime >= 0.1f)
{
//刷新一次 更新绘制图片的相关信息
UpdateSpriteInfor(); for (int i = 0; i < m_AnimSpriteInfor.Count; i++)
{
if (iIndex >= m_AnimSpriteInfor[i].Length)
{
listSprite[i] = m_AnimSpriteInfor[i][0];
}
else
{
listSprite[i] = m_AnimSpriteInfor[i][iIndex];
}
}
DrawSprite();
iIndex++;
if (iIndex >= AnimNum)
{
iIndex = 0;
}
fTime = 0.0f;
}
}
#endregion #region 绘制图片
/// <summary>
/// 绘制图片
/// </summary>
void DrawSprite()
{
Mesh m_spriteMesh = new Mesh(); List<Vector3> tempVertices = new List<Vector3>();
List<Vector2> tempUv = new List<Vector2>();
List<int> tempTriangles = new List<int>(); for (int i = 0; i < listSprite.Count; i++)
{
for (int j = 0; j < listSprite[i].vertices.Length; j++)
{
tempVertices.Add(listSprite[i].vertices[j]);
}
for (int j = 0; j < listSprite[i].uv.Length; j++)
{
tempUv.Add(listSprite[i].uv[j]);
}
for (int j = 0; j < listSprite[i].triangles.Length; j++)
{
tempTriangles.Add(listSprite[i].triangles[j]);
}
}
//计算顶点绘制顺序
for (int i = 0; i < tempTriangles.Count; i++)
{
if (i % 6 == 0)
{
int num = i / 6;
tempTriangles[i] = 0 + 4 * num;
tempTriangles[i + 1] = 1 + 4 * num;
tempTriangles[i + 2] = 2 + 4 * num; tempTriangles[i + 3] = 1 + 4 * num;
tempTriangles[i + 4] = 0 + 4 * num;
tempTriangles[i + 5] = 3 + 4 * num;
}
} m_spriteMesh.vertices = tempVertices.ToArray();
m_spriteMesh.uv = tempUv.ToArray();
m_spriteMesh.triangles = tempTriangles.ToArray(); if (m_spriteMesh == null)
return; GetComponent<CanvasRenderer>().SetMesh(m_spriteMesh);
GetComponent<SpriteGraphic>().UpdateMaterial();
}
#endregion }
3.差不多一张图集对应多个Text的功能就完了,看一下截图,因为这都是根据之前的更新的,看了之前工程的同学都应该能看明白,我架设你们都看过了
4.这里还更新了一个小东西,就是做聊天demo的时候感觉之前的标签太长,比如<quad name=meat size=20 width=1 />,确实有点长,本来应该表情也绘制在输入框的,一是自己也没去测试,二是有同学已经测试,但是发现不少问题,我暂时也就将标签缩短了<#meat>
5.之前的工程的基本功能都是基本完善的,最新的基本都是一些功能和逻辑上的扩展:
工程链接
Unity UGUI图文混排(五) -- 一张图集对应多个Text的更多相关文章
- Unity UGUI图文混排源码(三) -- 动态表情
这里是根据图文混排源码(二)进一步修改的,其他链接也不贴了,就贴一个链接就好了,第一次看这文章的同学可以先去看看其他几篇文章 Unity UGUI图文混排源码(二):http://blog.csdn. ...
- Unity UGUI图文混排源码(二)
Unity UGUI图文混排源码(一):http://blog.csdn.net/qq992817263/article/details/51112304 Unity UGUI图文混排源码(二):ht ...
- Unity UGUI图文混排源码(一)
Unity UGUI图文混排源码(一):http://blog.csdn.net/qq992817263/article/details/51112304 Unity UGUI图文混排源码(二):ht ...
- Unity UGUI图文混排(七) -- 下划线
之前更新超链接的时候,忘了搭配实现一个下划线的功能,这篇文章就是来补上这一个功能,时间有点长,一方面没有很好的思路,一方面也没多少时间. 先在网上收集了一下下划线的实现操作,一种是在文本下再创建一个文 ...
- Unity UGUI图文混排(六) -- 超链接
图文混排更新到超链接这儿,好像也差不多了,不过就在最后一点,博主也表现得相当不专业,直接整合了山中双木林同学提供的超链接的解决方案,博主甚至没来得及细看就直接复制了,但感觉还是挺好用的. 博主已经将超 ...
- Unity UGUI图文混排源码(四) -- 聊天气泡
这里有同学建议在做聊天气泡时,可以更改为一张图集对应多个Text,这样能节省资源,不过我突然想到每个Text一个图集,可以随时更换图集,这样表情图更丰富一些,于是我就先将现有的聊天demo改为了聊天气 ...
- [UGUI]图文混排(五):添加下划线
0.下划线标签 标签格式:<material=underline c=#ffffff h=1 n=*** p=***>blablabla...</material> mater ...
- Unity琐碎(3) UGUI 图文混排解决方案和优化
感觉使用Unity之后总能看到各种各样解决混排的方案,只能说明Unity不够体恤下情啊.这篇文章主要讲一下个人在使用过程中方案选择和优化过程,已做记录.顺便提下,开源很多意味着坑,还是要开实际需求. ...
- [UGUI]图文混排(二):Text源码分析
UGUI源码: https://bitbucket.org/Unity-Technologies/ui/downloads/?tab=tags 首先下载一份UGUI源码,这里我下载的版本是5.3.2f ...
随机推荐
- [CQOI 2011]动态逆序对
Description 题库链接 对于序列 \(A\) ,它的逆序对数定义为满足 \(i<j\) ,且 \(A_i>A_j\) 的数对 \((i,j)\) 的个数.给 \(1\) 到 \( ...
- [Luogu 3810]三维偏序
Description 有 $ n $ 个元素,第 $ i $ 个元素有 $ a_i $ .$ b_i $ .$ c_i $ 三个属性,设 $ f(i) $ 表示满足 $ a_j \leq a_i $ ...
- [WC2013]糖果公园
Description 题库链接 给你一棵 $n$ 个节点,有 $m$种颜色的树.每个节点上有一个颜色.定义一条树上路径的价值为 $sum_c V_c(\sum_{i=1}^{tim_c}W_i)$ ...
- ●洛谷P1903 [国家集训队]数颜色
题链: https://www.luogu.org/problemnew/show/P1903题解: 序列带修莫队, 推荐博客https://www.cnblogs.com/Paul-Guderian ...
- [Codeforces]856D - Masha and Cactus
题目大意:给出一棵树和若干条可以加入的边,要求加入若干条边使图是仙人掌并且加入的边权和最大,仙人掌定义为没有一个点属于超过1个环.(n,m<=200,000) 做法:这题的仙人掌跟平时见到的不太 ...
- bzoj 5289: [Hnoi2018]排列
Description Solution 首先注意到实际上约束关系构成了一棵树 考虑这个排列 \(p\),编号为 \(a[i]\) 的出现了,\(i\) 才可以出现 那么如果连边 \((a[i],i) ...
- bzoj4487[Jsoi2015]染色问题 容斥+组合
4487: [Jsoi2015]染色问题 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 211 Solved: 127[Submit][Status ...
- Thinkphp中的 I 函数(Thinkphp3.2.3版本)
I 函数的作用是获取系统变量,必要时还可以对变量值进行过滤及强制转化,I 函数的语法格式: I('变量类型.变量名/修饰符',['默认值'],['过滤方法或正则'],['额外数据源']) 一.获取变量 ...
- 移动端手势双击(MouseDown也可以在移动端响应,但是帧率太低)
void Update() { if (Input.touchCount > 0)//手指数量 { if(Input.GetTouch(0).phase == TouchPhase.Began ...
- Android.mk 详解
Android中增加本地程序或者库,这些程序与其所在路径没有关系,只和它们的Android.mk有关系. Android.mk与普通的makefile略有不同,Android.mk具有统一的写法,主要 ...