首页 > 其他分享 >Unity UGUI图文混排(五) -- 一张图集对应多个Text

Unity UGUI图文混排(五) -- 一张图集对应多个Text

时间:2022-12-13 14:36:41浏览次数:53  
标签:spriteAsset -- Text List ++ int Unity new tempSpriteInfor


继上一篇说的更新了一张图集对应多个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的功能就完了,看一下截图,因为这都是根据之前的更新的,看了之前工程的同学都应该能看明白,我架设你们都看过了

Unity UGUI图文混排(五) -- 一张图集对应多个Text_聊天气泡

4.这里还更新了一个小东西,就是做聊天demo的时候感觉之前的标签太长,比如<quad name=meat size=20 width=1 />,确实有点长,本来应该表情也绘制在输入框的,一是自己也没去测试,二是有同学已经测试,但是发现不少问题,我暂时也就将标签缩短了<#meat>

Unity UGUI图文混排(五) -- 一张图集对应多个Text_图文混排_02

5.之前的工程的基本功能都是基本完善的,最新的基本都是一些功能和逻辑上的扩展:  ​​工程链接​​

标签:spriteAsset,--,Text,List,++,int,Unity,new,tempSpriteInfor
From: https://blog.51cto.com/u_15911199/5934042

相关文章

  • 【Unity】超级坦克大战(三)登录界面
    更新日期:2020年7月9日。项目源码:在终章发布索引​​本章最佳实践​​​​正式开始​​​​创建UI编辑场景​​​​创建登录界面UI实体​​​​创建登录界面UI逻辑类​​​......
  • Effective Java-2. 当构造方法参数过多时使用builder模式
    背景静态工厂和构造方法不能很好的拓展到很多可选参数的场景,因为参数过多的时候,调用其构造方法不太能知道每个位置参数的含义,容易出bug那么为这个类编写什么样下的构造方......
  • 15、electron globalShortcut注册全局快捷键
    一、知识点:global-shortcut 模块可以便捷的为您设置(注册/注销)各种自定义操作的快捷键.Note:使用此模块注册的快捷键是系统全局的(QQ截图那种),不要在应用模块(appm......
  • 【Unity】超级坦克大战(一)搭建项目、导入框架、前期开发准备
    更新日期:2020年7月9日。项目源码:在终章发布免责声明:超级坦克大战使用的图片、音频等所有素材均有可能来自互联网,本专栏所有文章仅做学习和教程目的,不会将任何素材用于任何......
  • UE4实现闪烁效果
    官网文档链接:​​http://docs.unrealengine.com/latest/CHN/Engine/Rendering/Materials/ExpressionReference/Math/index.html?utm_source=editor&utm_medium=docs&utm_ca......
  • 【Unity】MeshEditor.Effects.Vortex 网格编辑器特效篇之碎化特效
    更新日期:2020年5月13日。Github源码:​​​[点我获取源码]​​索引​​Fragmentization​​​​使用​​​​参数​​​​原理及算法​​​​图像展示​​Fragmentization设......
  • Unity UGUI实现分段式血条
    我们可以看到像英雄联盟等游戏里英雄头顶的血条显示并非是纯色的,而是根据血量的多少而显示一定量的格子,这种方式明显是比较友好、比较美观的,事实上我们的游戏里面也想实现这......
  • secureCRT删除键乱码
    解决方法:先打开Options–>SessionOptions–>Terminal–>Emulation(中文:选项–>回话选项–>终端–>仿真)界面下:1.终端(T):选择linux,默认为VT100.2.ANSI颜色(A)打上勾......
  • CRegSettings - registry helper class
    CRegSettings-registryhelperclassDownloadsourcefiles-2.3KbDownloaddemoproject-5.1KbIntroductionIt'ssotedioustouseWin32APIoreven......
  • Unity Editor 自定义属于你的DefaultHeaderGUI
    DefaultHeaderGUI默认页眉GUI,是Unity编辑器中的所有对象被选中后在Inspector界面显示的页眉GUI,如下图红框区域:在这个区域加点自己的东西。finishedDefaultHeaderGUI只需要......