Coder Social home page Coder Social logo

textinlinesprite's Introduction

2020-01-27

  1. 支持unity2019+
  2. unity2019的文本的模型数据有所改动,具体的计算代码在c++代码底层,没有追踪到具体的信息,暂时测试出来的信息,如果Text文本,长度足够自动换行,模型顶点的数据信息跟unity2017一样,如果长度保持在一行以内或者手动换行,unity2019会不再计算富文本标签的顶点信息,所以需要手动替换富文本标签
  3. 替换富文本示例(InlineText :429):
//换掉富文本
private string ReplaceRichText(string str)
{
    str = Regex.Replace(str, @"<color=(.+?)>", "");
    str = str.Replace("</color>", "");
    str = str.Replace("<b>", "");
    str = str.Replace("</b>", "");
    str = str.Replace("<i>", "");
    str = str.Replace("</i>", "");
    str = str.Replace("\n", "");
    str = str.Replace("\t", "");
    str = str.Replace("\r", "");
    str = str.Replace(" ", "");

    return str;
}
  1. 如果使用中,有多余的富文本标签,建议自己在上述代码中添加/修改。
  2. unity2019的底层更改,增加了此插件不少必要的计算,导致维护难度上升不少,尽是一些吃力不讨好的事,坐等下次大更新。

新增功能

  1. 重写了配置文件编辑工具,可快速生成表情配置文件
  2. 使用shader渲染表情动画,取消了在update中循环更新模型数据
  3. 支持在编辑器中直接预览(支持不完全)
  4. 在编辑中增加了线框辅助调试
  5. 利用了对象池对部分比较明显的GC问题进行了优化
  6. 重新更换了坐标系转换的计算,更好的支持Canvas Render Mode的切换
  7. 精简整理了代码
  8. 简单优化了编辑器的操作

强行解释

  1. 性能优化会在后面持续进行
  2. 利用shader渲染表情动画,可以更好的利用设备的性能。一开始是准备利用UGUI的Mesh支持uv0-uv3,存下多个数据,来做表情动画。在使用了uv移动来做动画后,感觉uv0-uv3四层不够用,于是坚持老方法。
  3. 在选择使用uv移动来做动画,对表情图集有一定的要求:建议每个表情的规格一致,动态表情需要放成一排。具体参考demo自带图集。
  4. 现在所有的参数都已经在配置文件中, 请根据需求自行调整。
  5. 之前也提过,写这个插件并没有实际的使用机会,难免考虑不周,收集的意见,大部分都有自己的想法,比较杂乱,所以建议如果能直接使用,那是最好的。如果跟自己的需求有偏差,希望能作个参考,自己更改,欢迎提交pr。然后我会再尽力写成通用的。
  6. 提交的pr,改动小,我会检查合并,如果改动太大,我会单独新建分支留存,以便有需要的人查看。

功能介绍

  1. 此插件是基于UGUI所做的图文混排功能,常用于聊天系统的表情嵌入;
  2. 可支持静/动态表情,支持超链接;
  3. 实现原理,是基于UGUI的富文本,使用quad标签进行占位;
  4. 使用了Asset文件来存储本地的表情信息;
  5. Text根据正则表达式,解析文本,读取相应的表情信息,并在相应位置绘制相应的Sprite;
  6. 正则表达式为[图集ID#表情标签],图集ID为-ID时,表示此标签为超链接,如-1,图集ID为 0时,可省略不写;
  7. 有同学提过想支持移动端系统自带的表情,我这里只提一个简单的实现思路,集成不看自己的实际需求了,自己备好系统表情的图集,再解析一下当前系统输入表情的正则表达式,然后跟插件一样的嵌入到Text中(这算是正常的集成实现思路么?);

使用步骤

  1. 选择一张表情图片,导入在unity里,为了支持透明通道,记得在图片属性中勾选Alpha Is Transparent
  2. 右键选择图片,点击Create/Sprite Asset,打开资源窗口编辑器,点击Save来保存配置文件
  3. 在保存配置文件后,首先为图集设置一个唯一Id,然后设置图集表情的行列数,来自动切分表情,动态表情会自动将一排的Sprite自动归纳为一个表情,最后为每个表情设置一个可读的Tag,后续提供给Text调用。
  4. 配置文件创建完成后,在编辑器中,也可以预览,操作与资源窗口编辑器类型,并且点击Open Asset Window也可以打开编辑器窗口
  5. 文字使用方式,参考demo场景'Text',输入NewText[1#rock]即可显示表情

截图展示

 标签对应表情
聊天示例
更新后,功能展示

textinlinesprite's People

Contributors

coding2233 avatar lizijie avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

textinlinesprite's Issues

换行排版有问题

偶然发现当换行时,有个图标位置不准确image
image

当把文本"Textsssss"增加多一个字母后,就正确了
image

缺少 VertexHelper

Assets/TextInlineSprite/Script/InlieSpriteText.cs(126,44): error CS0246: The type or namespace name `VertexHelper' could not be found. Are you missing a using directive or an assembly reference?

兄弟你代码没上传完把。

text.preferredHeight 并不正确

在纯文本的情况下是正确,但是当有图片和链接的时候,就不正确了。
图片连接数量多的时候(比如长度达到10行),可以非常明显的看到问题。

优化请求

希望能把SpriteGraphic脚本下的CellAmount和Speed,两个值集成在SpriteAsset里面
这样在多表情的时候用一个图集即可以实现,方便管理,提升性能。
我尝试阅读代码,但无奈水平有限,无从下手。
如果您能提供下思路,我将不胜感激!谢谢。

5.5上面错误

在5.5里面打开直接报错 InlieText脚本167行和 461行以及327行

Unity5.5.x,在楼主帮助下解决了一些问题后,然后在TextDemo.unity 在测试出来的问题

问题:文字展示内容超出文本框高度很容易出现错误(数组越界)的问题?

ArgumentOutOfRangeException: Argument is out of range.
Parameter name: index
System.Collections.Generic.List`1[UnityEngine.UIVertex].get_Item (Int32 index) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Collections.Generic/List.cs:633)
InlieText.OnPopulateMesh (UnityEngine.UI.VertexHelper toFill) (at Assets/TextInlineSprite/Script/InlieText.cs:171)
UnityEngine.UI.Graphic.DoMeshGeneration () (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Graphic.cs:384)
UnityEngine.UI.Graphic.UpdateGeometry () (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Graphic.cs:378)
UnityEngine.UI.Text.UpdateGeometry () (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Text.cs:378)
UnityEngine.UI.Graphic.Rebuild (CanvasUpdate update) (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Graphic.cs:338)
UnityEngine.UI.CanvasUpdateRegistry.PerformUpdate () (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/CanvasUpdateRegistry.cs:149)
UnityEngine.Canvas:SendWillRenderCanvases()

没有超链接?

下载的主干最新版,HrefParser没有实现,InlineManager里面也将atlasID<0的tag给略过了?再哪里实现的超链接?还是新版去掉了?

unity2019支持问题

以前在unity2018上用的很好,2019出现严重问题:
2019的unity中,OnPopulateMesh(VertexHelper toFill)方法的toFill内容发生变化。

2018中,toFill里vertex的个数是原始字符串的4倍,例如,原始字符串是123,vertex就有104个。
2019中,vertex只有4
4个,也就是“翻译”后实际的顶点个数
而目前quad位置的对应算法是:tempIndex = _textBuilder.Length * 4;
是按原始字符串长度算了。
这导致后续的顶点处理都出现了错误。

图文没有居中对齐

设计好UI结构如下图:

1
设置Text的Alignment为居中对齐。
如果不修改表情图片Asset的大小,使用作者的默认值24,是能够保证居中对齐的,但是我的表情原图是64*64,我想尽量保证显示原图大小的表情这时候就出现问题了:
如果只是输入文字或者只是输入表情图片,是正确居中对齐的。但是同时输入表情和文字后发现文字并没有居中对齐。
3
4
2

Canvas的RenderMode为ScreeSpace-Camera,但是我发现这个问题好像跟Canvas的模式没多大关系!

InlineText在列表划动过快时,表情容易位置偏移

渲染一个表情在v3.0的实现里,流程大致如下:
【流程一】 InlineText.OnPopulateMesh转换表情顶点至全局坐标,InlineManager.UpdateTextInfo再将全局坐标转换到SpriteGraphic下的局部坐标。
【流程二】 InlineManager.Update合批相同表情ID的Mesh,转输到SpriteGraphic.OnPopulateMesh作最终渲染。

因为InlineManager.Update合批Mesh,所以这两个流程相差1帧。如果InlineText的坐标在这帧变动了(如列表划动),因为没其它逻辑去强刷缓存在InlineManager的EmojiText.Taurus.MeshInfo坐标,所以SpriteGraphic.OnPopulateMesh使用的是不正确的坐标。结果显示上表情位置偏移了。

像ChatTest样例中,监听ScrollRect.onValueChanged事件,修复SpriteGraphic坐标并未解决以上问题。因为它是与 【流程一】 同帧进行。依然与 【流程二】 相差了1帧。

private void OnSrcollViewChanged(Vector2 pos)
{
    _spriteRect.anchoredPosition = _scrollView.content.anchoredPosition;
}

测试代码如下:

public class Test : MonoBehaviour
{
    public InlineText inText = null;
    public SpriteGraphic graphic = null;

    void Start()
    {
        inText.text = "NewText[#emoji_0]";

		// 模拟在【流程一】与【流程二】中间1帧,修改了InlineText坐标
        graphic.RegisterDirtyVerticesCallback(() =>
        {
            inText.transform.localPosition = new Vector3(200, 200, 0);
        });
    }
}

执行结果如下
image

关于下划线部分的修改

原来的代码,下划线部分,如果超链接需要换行,下划线,就出现BUG了
image
然后我基于InlieSpriteText.cs来修改代码,解决了拉伸和换行的BUG问题,现在效果是:
image

代价是下划线要画很多条:
image

这个方案其实也是治标不治本,只是在原基础代码上,更快速去实现效果
希望有更好的解决方案

具体代码为:
新增一个list变量

List<Vector3> unLineVertsPos = new List<Vector3>();		//下划线使用 X坐标,Y坐标, Z长度

然后在OnPopulateMesh方法中新增

int lineheight = cachedTextGenerator.lines[0].height;
IList<UICharInfo> charinfos = cachedTextGenerator.characters;
for(int i = 0 ; i < charinfos.Count ; i++) {
    if(charinfos[i].charWidth != 0) {
	unLineVertsPos.Add(new Vector3(charinfos[i].cursorPos.x , charinfos[i].cursorPos.y - lineheight , charinfos[i].charWidth));
    }
}
#region 处理超链接的下划线--拉伸实现
...
Vector3 _StartBoxPos = new Vector3(unLineVertsPos[i].x, unLineVertsPos[i].y, 0.0f);
Vector3 _EndBoxPos = _StartBoxPos + new Vector3(unLineVertsPos[i].z, 0.0f, 0.0f);
#endregion

AddUnderlineQuad方法修改一下片面长度

#region 添加下划线
void AddUnderlineQuad(VertexHelper _VToFill, IList<UIVertex> _VTUT, Vector3 _VStartPos, Vector3 _VEndPos)
{
        Vector3[] _TUnderlinePos = new Vector3[4];
	_TUnderlinePos[0] = _VStartPos + new Vector3(-2 , 0 , 0);
	_TUnderlinePos[1] = _VEndPos + new Vector3(2 , 0 , 0);
        _TUnderlinePos[2] = _VEndPos + new Vector3(2, fontSize * 0.1f , 0);
        _TUnderlinePos[3] = _VStartPos + new Vector3(-2, fontSize * 0.1f , 0);

......
}
#endregion

关于下划线的修改

感谢分享!!!项目中用到了下划线和图文混排,刚好找到了这个插件能满足项目!
研究后发现:下划线左右两边出现渐变的原因是:下划线的贴图是字体的“_”字符的uv坐标处的颜色。
改变获取算法如下:
TextGenerator _UnderlineText = new TextGenerator();
_UnderlineText.Populate("▁", settings);
IList _TUT = _UnderlineText.verts;
var uiCenterPos = Vector2.zero;
var count = 0;
for (int i = 0; i < _TUT.Count; i++)
{
var uiVertex = _TUT[i];
if (uiVertex.uv0.magnitude > 0)
{
uiCenterPos += uiVertex.uv0;
count++;
}
}
if (count > 0)
{
uiCenterPos /= count;
for (int i = 0; i < _TUT.Count; i++)
{
var uiVertex = _TUT[i];
if (uiVertex.uv0.magnitude > 0)
{
uiVertex.color = Color.white;
uiVertex.uv0 = uiCenterPos;
_TUT[i] = uiVertex;
}
}
}
原理是:找个中心是有颜色的字,然后找到这个字的中心UV坐标,然后把这些点的坐标全设置为中心坐标。

关于版权问题

您写的这个东西非常好,我想用在一个项目上,可能会有商业用途,我需要给您交付版权费用吗

悲剧

本来用自带textpro做表情,但是每次都需要创建中文字库;然后找到这个代码,下载下来发觉不太好用,创建一个text,会附加一堆其他sprite看起来有点乱,花了一个下午优化整理,然后创建的text简洁方便多了,基本自动化。准备使用的时候突然发现表情不能缩放,也不能随字体大小变化。这个怎么办

回收EmojiText.Taurus.MeshInfo:Release对象时报错

image
这4行代码某些情况下出现错误Internal error. Trying to destroy object that is already released to pool.

Internal error. Trying to destroy object that is already released to pool.
UnityEngine.Debug:LogError(Object)
EmojiText.Taurus.ObjectPool`1:Release(List`1) (at Assets/Plugins/ThirdPart/EmojiText/Scripts/Pool.cs:45)
EmojiText.Taurus.ListPool`1:Release(List`1) (at Assets/Plugins/ThirdPart/EmojiText/Scripts/Pool.cs:67)
EmojiText.Taurus.MeshInfo:Release() (at Assets/Plugins/ThirdPart/EmojiText/Scripts/InlineManager.cs:196)
EmojiText.Taurus.InlineManager:UpdateTextInfo(InlineText, Int32, List`1, Boolean) (at Assets/Plugins/ThirdPart/EmojiText/Scripts/InlineManager.cs:103)
EmojiText.Taurus.InlineText:UpdateDrawSprite(Boolean) (at Assets/Plugins/ThirdPart/EmojiText/Scripts/InlineText.cs:344)
EmojiText.Taurus.InlineText:OnPopulateMesh(VertexHelper) (at Assets/Plugins/ThirdPart/EmojiText/Scripts/InlineText.cs:124)
UnityEngine.Canvas:SendWillRenderCanvases()

遗憾的是~!抓摸不到重现该问题的办法。

不过,代码上来看。当EmojiText.Taurus.MeshInfo对执行Release后,依然保留着Vertices、UVs、Colors和Triangles这4个List的引用 。下次再从对象池取MeshInfo对象时,它所引用的4个List是一个“脏对象”,有必要再重新Get这4个List

UnityEngine.UI.VertexHelper内部也有类似的操作(如下图),我尝试按它的方式,修改EmojiText.Taurus.MeshInfo。

如果一段时间内没有重现上面错误,到时我向你提个pr

public class VertexHelper : IDisposable
    {
        private List<Vector3> m_Positions;
        private List<Color32> m_Colors;
        private List<Vector2> m_Uv0S;
        private List<Vector2> m_Uv1S;
        private List<Vector2> m_Uv2S;
        private List<Vector2> m_Uv3S;
        private List<Vector3> m_Normals;
        private List<Vector4> m_Tangents;
        private List<int> m_Indices;

        private bool m_ListsInitalized = false;



        private void InitializeListIfRequired()
        {
            if (!m_ListsInitalized)
            {
                m_Positions = ListPool<Vector3>.Get();
                m_Colors = ListPool<Color32>.Get();
                m_Uv0S = ListPool<Vector2>.Get();
                m_Uv1S = ListPool<Vector2>.Get();
                m_Uv2S = ListPool<Vector2>.Get();
                m_Uv3S = ListPool<Vector2>.Get();
                m_Normals = ListPool<Vector3>.Get();
                m_Tangents = ListPool<Vector4>.Get();
                m_Indices = ListPool<int>.Get();
                m_ListsInitalized = true;
            }
        }

        /// <summary>
        /// Cleanup allocated memory.
        /// </summary>
        public void Dispose()
        {
            if (m_ListsInitalized)
            {
                ListPool<Vector3>.Release(m_Positions);
                ListPool<Color32>.Release(m_Colors);
                ListPool<Vector2>.Release(m_Uv0S);
                ListPool<Vector2>.Release(m_Uv1S);
                ListPool<Vector2>.Release(m_Uv2S);
                ListPool<Vector2>.Release(m_Uv3S);
                ListPool<Vector3>.Release(m_Normals);
                ListPool<Vector4>.Release(m_Tangents);
                ListPool<int>.Release(m_Indices);

                m_Positions = null;
                m_Colors = null;
                m_Uv0S = null;
                m_Uv1S = null;
                m_Uv2S = null;
                m_Uv3S = null;
                m_Normals = null;
                m_Tangents = null;
                m_Indices = null;

                m_ListsInitalized = false;
            }
        }

        /// <summary>
        /// Clear all vertices from the stream.
        /// </summary>
        public void Clear()
        {
            // Only clear if we have our lists created.
            if (m_ListsInitalized)
            {
                m_Positions.Clear();
                m_Colors.Clear();
                m_Uv0S.Clear();
                m_Uv1S.Clear();
                m_Uv2S.Clear();
                m_Uv3S.Clear();
                m_Normals.Clear();
                m_Tangents.Clear();
                m_Indices.Clear();
            }
        }

文本Text的宽度计算似乎有问题 sizeDelta在某些时候并不表示文本宽高

有个疑问,为什么用sizeDelta 来计算文本宽度,这个矢量计算在锚点(0.5,0.5,0.5,0.5)可以正确表示文本宽高,但是在其他情况下计算出来的是边距向量,这时候文本宽高就计算出错了,还可能出现负值。
稍作修改似乎就没问题了但是这么做是否有其他的一些地方没考虑到的 修改位置是下面Modify
public override float preferredWidth
{
get
{
var settings = GetGenerationSettings(Vector2.zero);
float width = cachedTextGeneratorForLayout.GetPreferredWidth(m_Text, settings) / pixelsPerUnit;
return width < rectTransform.rect.width || horizontalOverflow == HorizontalWrapMode.Overflow ? width : rectTransform.rect.width; //Modify
}
}
public override float preferredHeight
{
get
{
var settings = GetGenerationSettings(new Vector2(rectTransform.rect.size.x, 0.0f));
float height = cachedTextGeneratorForLayout.GetPreferredHeight(m_Text, settings) / pixelsPerUnit;
return height < rectTransform.rect.height || verticalOverflow == VerticalWrapMode.Overflow ? height : rectTransform.rect.height ;//Modify
}
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.