精华内容
下载资源
问答
  • 实现在Text文本中添加图片表情功能
  • unity ugui 图文混排

    2017-10-13 11:11:38
    unity ugui 图文混排
  • unity 图文混排方案

    千次阅读 2020-03-05 20:44:08
    在我们工作中,可能经常有这样的需求,就是需要图文混排,因为这个对于原生或web都是比较容易的事情。但是我们用unity的话,首先unity最开始只想做纯游戏侧的引擎,一开始甚至还没有一个商业化的ui工具,后面才结合...

    在我们工作中,可能经常有这样的需求,就是需要图文混排,因为这个对于原生或web都是比较容易的事情。但是我们用unity的话,首先unity最开始只想做纯游戏侧的引擎,一开始甚至还没有一个商业化的ui工具,后面才结合了ngui成为ugui,当然现在也出现了uielement。但要做到图文混排一开始还是不容易的,需要四处找插件,甚至需要自己想办法文字和图片自己做结合来实现。

    经过了一段时间后unity出现了textmesh,他可以实现图文混排,他图文混排的方式相当于是多一个材质,然后再语法上用类似<quad material=1>来实现。实际上他也能实现图文混排的方式,只需要打个图集,把图集放到材质上,材质放到textmesh的第二个材质上就好了。

    这个图集材质是长这样的:

    实现的效果是:

    看上去没问题,能实现效果。但是他有几个问题:

    第一就是他的设置图片的方式:<quad material=1 x=0.001953125 y=0.244140625 width=0.25 height=0.125/>

    注意这里的x,y,width,height都是0到1的,也就是你需要自己把图片的位置和图片的宽高通过图集的宽高换算出来(实际上就是算偏移)。

    比如x=250;图集的宽是1024;那么真正的x就是250/1024。

    这里如果你的表情多,就会有很多这种除法运算,整体来说效率不高。

    第二就是你用在输入框或者表情列表下的话你可能就很难做了。

    因为输入框我们如果用ugui的话,他已经帮我们关联好相关输入的信息,我们貌似没办法给他增加TextMesh方式来实现图文混排的效果(如果这个不重要用标记代替也行)

    但是致命的是你可能没办法再一个drawcall下用TextMesh来实现表情列表。因为ugui里面的材质都不支持多材质。

    当然如果你说不用ugui或者自己改造,用mesh自己实现也是可以的。但是你就要做很多适配的工作了。

     

    也就衍生出以下说的一种比较适合上面我说的情况的,需要图文混排,需要文字输入中带图片,需要列表只有一个drawcall。

    那就是TextMeshPro了。

    这个是后面unity引进来的TextMesh的升级版。unity甚至把他接入到了各种text里面。

    用Tmp实现图文混排就简单了。

    我们用的是spriteasset的方式。

    使用<sprite="DefaultSprites" name="Unity">的方式显示一个表情, sprite是textmeshpro集的命,name是具体的图片,也可以用index。

    另外textmeshpro集要放在“TextMesh Pro\Resources\Sprite Assets”下(除非你改了他的路径),改路径的地方是

    如果我们要支持中文或其他语言,我们就修改下fontasset的字体就好:

    点击:

    选择这个fontasset,然后修改下面这里:

    一般不需要自己做字体,除非你有特殊字体。

     

    但是我们现在只有默认的表情

    我们当然像要自己的表情,那就需要自己来制作一下表情图集了。

    我用的是TexturePacker来把图集打出来。但是要注意不要让他支持旋转,让他正常排列就好。

    然后在图集上选择sprite和spritemode选择multiple,这样才能编辑图片

    选择sprite editor

    这里注意锚点一定要放在左下角,然后保存。

     

    然后需要制作具体的fontasset了,右键这个图集:

    制作好的图集放在我们设置的spriteasset的目录下:

    放到这里就可以在项目中用这些表情。

    最终展示效果

    这个文本时这样出来的:

    然后其他的展示效果如下:

    这里说以下表情列表需要更改下他们的render queue,让相同的材质在一个queue下,不同的不要在一个queue下,这样才能让他们合批。以下时其中一个示例

    好了,对比下一排和两排的效果,可以看到他们没有drawcall的增加,我们的需求解决了。

    下面是两排的示例:

     

    但是这里要注意的是不支持gif,gif图片可以用序列帧的方式来播放。建议发gif动画就单发,不要连着文字一起发,也就是点击gif的表情就发出去把,不让他带文字了。

     

     

     

     

     

     

     

    展开全文
  • Unity图文混排的几种方式

    千次阅读 2019-09-11 15:10:25
    -TextMesh是Unity原生的支持图文混排的方式。 - 使用方法 在GameObject下挂上TextMesh,会自动追加上MeshRender,之后在Materials里追加对应的图片材质球,即可通过<quadmaterial=1>来使用图片,还可以通过...

    方法一:TextMesh  

    - TextMesh是Unity原生的支持图文混排的方式。  

    - 使用方法  

        在GameObject下挂上TextMesh,会自动追加上MeshRender,之后在Materials里追加对应的图片材质球,即可通过<quad material=1>来使用图片,还可以通过size、x、y、width、height来设置图片属性。   

            各个属性的含义  

            material=1 选择的材质下标为1  

            size=20 图像高度为20像素  

            x=0.5 y=0.7 显示图像的矩形区域的起点为x=0.5 y=0.7  

            width = 1 height = 0.5 显示图像的矩形宽度为1,高度为0.5  

    - 优化空间:将所有需要图文混排的图片打成一张图集,并制作成一个统一的材质球,通过x、y、width、height去设置图片偏移来渲染不同的图片  

    - 效果图  

     

    方法二:TextMeshPro  

    - TextMeshPro原本是一个第三方插件,后被Unity收购后并入Unity,现在可以免费使用,对于Unity2018及以后的版本,可以从菜单栏Window > Package Manager中安装TextMesh Pro。

    - 使用方法

        1. 将所需要的图文混排图片资源的属性设置为Sprite(2D and UI),SpriteMode设置为Multiple    

        

        2. 打开SpriteEditor,将图片切割好,可通过Slice快速切割成多张图片,再根据所需慢慢调整  

        

        3. 选中图片资源,通过Assets-Create-TextMeshPro-SpriteAsset,或者直接右键图片资源Create-TextMeshPro-SpriteAsset创建出对应的图片Asset  

        4. 在TextMeshPro组件中设置对应的SpriteAsset,然后通过<sprite=9>或者<sprite name="Grinning face">来渲染对应的图片,其中sprite=9代表Asset中的Index=9,"Grinning face"代表Asset中的Name="Grinning face"

        5. 如果遇到要使用多个图片Asset资源的情况,需要将图片Asset放在Editor-ProjectSettings-TextMeshPro-Setting里的defaultSpriteAsset所设置的目录下,该目录的起始位置在Assets/TextMesh Pro/Rescources。之后使用<sprite="DefaultSprites" index=0>或者<sprite="DefaultSprites" name="Unity">来使用对应的图片,其中"DefaultSprites"是该图片Asset的名字,index=0代表Asset中的Index=0,name="Unity"代表Asset中的name="Unity"

        

    - 效果图  

     

    方法三:Layout Group  

    - Unity自带的Layout Group的作用是让在这个脚本Go下的子物体根据Layout Group所设置的进行自动对齐排序,这种方法不需要使用富文本,只要设置好正确的对齐方式即可。

    - 效果图

    展开全文
  • Unity图文混排实现

    2020-03-03 10:15:38
    实现在文本中插入图片,图片替换符使用如下格式 //XML: &lt;quad index=0 size=60&gt; 代码中<quad index=0 size=60> using System.Collections;...using System.Collections.Generic;...

    实现在文本中插入图片,图片替换符使用如下格式 //XML: &lt;quad index=0 size=60&gt;   代码中<quad index=0 size=60>

    using System.Collections;
    using System.Collections.Generic;
    using System.Text.RegularExpressions;
    using UnityEngine;
    using UnityEngine.UI;
    
    [RequireComponent(typeof(Text))]
    public class TextTagHook : BaseMeshEffect
    {
        public class SpriteTagInfo
        {
            public int index;
            public int stringIndex;
            public Vector2 size;
            public bool isVisible = true;
        }
    
        //in XML:  &lt;quad index=0 size=60&gt;   <quad index=0 size=60>
        private static readonly Regex spriteTagRegex = new Regex(@"<quad\s+index=(\d+)\s+size=(\d*\.?\d+%?)(\s+width=(\d*\.?\d+%?))?\s*>", RegexOptions.Singleline);
        private static readonly Regex spriteTagReplacementRegex = new Regex(@"{}", RegexOptions.Singleline);
        private static readonly Regex tagRegex = new Regex(@"<.*?>", RegexOptions.Singleline);
        private static readonly Regex whitespaceRegex = new Regex(@"\s+", RegexOptions.Singleline);
    
        public RectTransform[] tagObjects = new RectTransform[] { };
    
        private Text _text;
        public Text text
        {
            get
            {
                if (_text == null)
                {
                    _text = GetComponent<Text>();
                }
    
                return _text;
            }
        }
    
        private List<SpriteTagInfo> spriteTags = new List<SpriteTagInfo>();
    
        private string lastContent;
        private bool lastBestFit;
        private int lastVertexCount;
        private bool isContentDirty
        {
            get
            {
                return true;
            }
        }
    
        private bool isValid;
        
        public override void ModifyMesh(VertexHelper vh)
        {
            if (!IsActive()) return;
    
            if (isContentDirty)
            {
                lastContent = text.text;
                lastBestFit = text.resizeTextForBestFit;
                lastVertexCount = text.cachedTextGenerator.vertexCount;
    
                spriteTags.Clear();
                try
                {
                    foreach (Match match in spriteTagRegex.Matches(lastContent))
                    {
                        SpriteTagInfo spriteTag = new SpriteTagInfo();
                        spriteTag.index = int.Parse(match.Groups[1].Value);
                        spriteTag.stringIndex = match.Index;
                        spriteTag.size = new Vector2(float.Parse(match.Groups[2].Value), float.Parse(match.Groups[2].Value));
                        if (match.Groups[4].Success)
                        {
                            spriteTag.size.x *= float.Parse(match.Groups[4].Value);
                        }
                        spriteTag.isVisible = text.cachedTextGenerator.vertexCount / 4 > spriteTag.stringIndex;
                        spriteTags.Add(spriteTag);
                    }
    
                    if (text.cachedTextGenerator.vertexCount / 4 != text.cachedTextGenerator.characterCount)
                    {
                        string toGenerateContent = spriteTagRegex.Replace(lastContent, "{}");
                        toGenerateContent = tagRegex.Replace(toGenerateContent, string.Empty);
                        toGenerateContent = whitespaceRegex.Replace(toGenerateContent, string.Empty);
                        int index = 0;
                        foreach (Match match in spriteTagReplacementRegex.Matches(toGenerateContent))
                        {
                            spriteTags[index].stringIndex = match.Index - index;
                            spriteTags[index].isVisible = true;
                            index++;
                        }
                    }
                    isValid = true;
                }
                catch (System.Exception e)
                {
                    isValid = false;
                }
            }
    
            for (int i = 0; i < tagObjects.Length; i++)
            {
                if (tagObjects[i] != null)
                {
                    tagObjects[i].localScale = Vector3.zero;
                }
            }
    
            if (isValid)
            {
                for (int i = 0; i < spriteTags.Count; i++)
                {
                    SpriteTagInfo spriteTag = spriteTags[i];
    
                    if (tagObjects.Length > spriteTag.index)
                    {
                        var target = tagObjects[spriteTag.index];
                        if (target == null) continue;
    
                        if (spriteTag.isVisible)
                        {
                            float unitsPerPixel = 1 / text.pixelsPerUnit;
                            var verts = text.cachedTextGenerator.verts;
    
                            Vector2 roundingOffset = new Vector2(verts[0].position.x, verts[0].position.y) * unitsPerPixel;
                            roundingOffset = text.PixelAdjustPoint(roundingOffset) - roundingOffset;
    
                            Vector3 pox1 = verts[spriteTag.stringIndex * 4 + 3].position;
                            Vector3 pox2 = verts[spriteTag.stringIndex * 4 + 2].position;
                            if (roundingOffset != Vector2.zero)
                            {
                                pox1 *= unitsPerPixel;
                                pox1.x += roundingOffset.x;
                                pox1.y += roundingOffset.y;
                                pox2 *= unitsPerPixel;
                                pox2.x += roundingOffset.x;
                                pox2.y += roundingOffset.y;
                            }
                            else
                            {
                                pox1 *= unitsPerPixel;
                                pox2 *= unitsPerPixel;
                            }
    
                            target.localPosition = pox1;
                            target.localScale = Vector3.one * (pox2.x - pox1.x) / spriteTag.size.x;
                        }
                    }
                }
    
                List<UIVertex> vertexList = new List<UIVertex>();
                vh.GetUIVertexStream(vertexList);
    
                for (int i = 0; i < spriteTags.Count; i++)
                {
                    if (!spriteTags[i].isVisible) continue;
    
                    //UGUIText不支持<quad/>标签,表现为乱码,这里将他的uv全设置为0,清除乱码
                    for (int m = spriteTags[i].stringIndex * 6; m < spriteTags[i].stringIndex * 6 + 6; m++)
                    {
                        UIVertex tempVertex = vertexList[m];
                        tempVertex.uv0 = Vector2.zero;
                        tempVertex.uv1 = Vector2.zero;
                        tempVertex.uv2 = Vector2.zero;
                        tempVertex.uv3 = Vector2.zero;
                        tempVertex.color = Color.clear;
                        vertexList[m] = tempVertex;
                    }
                }
    
                vh.Clear();
                vh.AddUIVertexTriangleStream(vertexList);
            }
        }
    }
    

    将脚本挂到Text上,如下图,可以通过调整icon1和icon2的位置来调整图片显示的位置。

    展开全文
  • Unity 图文混排和超链接

    千次阅读 2020-01-16 16:50:39
    最近无意中找到的,UGUI表情系统解决方案 作者通过重写Text的OnPopulateMesh,重新生成网格,把代表表情的编号"[XXX]"替换为%%,把%%在转为表情网格,最终通过UIVertex.uv1计算传值给shader绘制出来. ...

    最近无意中找到的,UGUI表情系统解决方案

    作者通过重写Text的OnPopulateMesh,重新生成网格,把代表表情的编号"[XXX]"替换为%%,把%%在转为表情网格,最终通过UIVertex.uv1计算传值给shader绘制出来.

    我试了下Emoji没什么问题,后来想加个超链接功能,在原有基础上做了修改,计算%%的占位老是出错,于是我把%%直接换成了一个汉字,这样就方便多了.

     /// <summary>
     /// 表情使用汉字为占位符
     /// </summary>
     private readonly static char s_SpecialCharacters = '圞';

    如果用其他汉字,文本里出现的概率会很大,所以这里用了特殊的汉字.

    在Text的OnPopulateMesh中计算数据,需要继承 Text, IPointerClickHandler

    详细逻辑如下

      protected override void OnPopulateMesh(VertexHelper toFill)
        {
            Debug.Log("OnPopulateMesh");
            string orignText = m_Text;
            if (font == null)
                return;
            if (s_EmojiIndex == null)
            {
                s_EmojiIndex = new Dictionary<string, EmojiInfo>();
                // load emoji data, and you can overwrite this segment code base on your project.
                TextAsset emojiContent = Resources.Load<TextAsset>("emoji");
                string[] lines = emojiContent.text.Split('\n');
                for (int i = 1; i < lines.Length; i++)
                {
                    if (!string.IsNullOrEmpty(lines[i]))
                    {
                        string[] strs = lines[i].Split('\t');
                        EmojiInfo info;
                        info.x = float.Parse(strs[3]);
                        info.y = float.Parse(strs[4]);
                        info.size = float.Parse(strs[5]);
                        s_EmojiIndex.Add(strs[1], info);
                    }
                }
            }
            // 支持富文本
            if (supportRichText)
            {
                m_TempEmoji.Clear();
                m_ShowEmojiData.Clear();
                s_TextBuilder.Length = 0;
                int lastSubIndex = 0;
                //data里面已经吧[0]换成了{0},这里把所有表情代码替换成特殊汉字,存到容器里
                foreach (Match match in Regex.Matches(text, "\\{[a-z0-9A-Z]+\\}"))
                {
                    EmojiInfo info;
                    if (s_EmojiIndex.TryGetValue(match.Value, out info))
                    {
                        if (lastSubIndex != match.Index)
                        {
                            s_TextBuilder.Append(text.Substring(lastSubIndex, match.Index - lastSubIndex));
                        }
                        m_TempEmoji.Add(info);
                        s_TextBuilder.Append(s_SpecialCharacters);
                        lastSubIndex = match.Index + match.Length;
                    }
                }
                if (lastSubIndex != text.Length - 3)
                {
                    s_TextBuilder.Append(text.Substring(lastSubIndex));
                }
                //在把代表超链接标签转为<color={0}></color>
                m_EmojiText = GetOutputText(s_TextBuilder.ToString());
                s_TextBuilder.Length = 0;
                s_TextBuilder.Append(m_EmojiText);
                int index = 0;
                //记录下表情所在下标,最终渲染需要用到
                for (int i = 0; i < s_TextBuilder.Length; i++)
                {
                    if (s_TextBuilder[i].Equals(s_SpecialCharacters) && index < m_TempEmoji.Count)
                    {
                        m_ShowEmojiData.Add(i, m_TempEmoji[index++]);
                    }
                }
            }
            else
            {
                m_EmojiText = text;
            }
            m_DisableFontTextureRebuiltCallback = true;
            Vector2 extents = rectTransform.rect.size;
            var settings = GetGenerationSettings(extents);
            cachedTextGenerator.Populate(m_EmojiText, settings);
            Rect inputRect = rectTransform.rect;
            // 获取text的alignment anchor 
            Vector2 textAnchorPivot = GetTextAnchorPivot(alignment);
            Vector2 refPoint = Vector2.zero;
            refPoint.x = Mathf.Lerp(inputRect.xMin, inputRect.xMax, textAnchorPivot.x);
            refPoint.y = Mathf.Lerp(inputRect.yMin, inputRect.yMax, textAnchorPivot.y);
            // 确定要偏移网格的像素。
            Vector2 roundingOffset = PixelAdjustPoint(refPoint) - refPoint;
            // 将偏移应用于顶点
            IList<UIVertex> verts = cachedTextGenerator.verts;
            float unitsPerPixel = 1 / pixelsPerUnit;
            //最后4节总是一条新的线
            int vertCount = verts.Count - 4;
            toFill.Clear();
            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)
                {
                    EmojiInfo info;
                    int index = i / 4;
                    if (m_ShowEmojiData.TryGetValue(index, out info))
                    {
                        int tempVertsIndex = i & 3;
                        m_TempVerts[tempVertsIndex] = verts[i];
                        m_TempVerts[tempVertsIndex].position *= unitsPerPixel;
                        if (tempVertsIndex == 3)
                        {
                            //可动态设置offset值对表情大小进行控制 
                            float offset = 4;
                            m_TempVerts[0].position = m_TempVerts[0].position + new Vector3(-offset, offset);
                            m_TempVerts[1].position = m_TempVerts[1].position + new Vector3(offset, offset);
                            m_TempVerts[2].position = m_TempVerts[2].position + new Vector3(offset, -offset);
                            m_TempVerts[3].position = m_TempVerts[3].position + new Vector3(-offset, -offset);
                            m_TempVerts[0].uv1 = new Vector2(info.x, info.y + info.size);
                            m_TempVerts[1].uv1 = new Vector2(info.x + info.size, info.y + info.size);
                            m_TempVerts[2].uv1 = new Vector2(info.x + info.size, info.y);
                            m_TempVerts[3].uv1 = new Vector2(info.x, info.y);
                            toFill.AddUIVertexQuad(m_TempVerts);
                        }
                    }
                    else
                    {
                        int tempVertsIndex = i & 3;
                        m_TempVerts[tempVertsIndex] = verts[i];
                        m_TempVerts[tempVertsIndex].position *= unitsPerPixel;
                        if (tempVertsIndex == 3)
                            toFill.AddUIVertexQuad(m_TempVerts);
                    }
                }
    
            }
            m_Text = orignText;
    
            // 超链接包围框
            foreach (var hrefInfo in m_HrefInfos)
            {
                hrefInfo.boxes.Clear();
                if (hrefInfo.startIndex >= toFill.currentVertCount)
                {
                    continue;
                }
                // 将超链接里面的文本顶点索引坐标加入到包围框
                toFill.PopulateUIVertex(ref m_TempBoxVert, hrefInfo.startIndex);
                var pos = m_TempBoxVert.position;
                var bounds = new Bounds(pos, Vector3.zero);
                for (int i = hrefInfo.startIndex, m = hrefInfo.endIndex; i < m; i++)
                {
                    if (i >= toFill.currentVertCount)
                    {
                        break;
                    }
                    toFill.PopulateUIVertex(ref m_TempBoxVert, i);
                    pos = m_TempBoxVert.position;
                    if (pos.x < bounds.min.x) // 换行重新添加包围框
                    {
                        hrefInfo.boxes.Add(new Rect(bounds.min, bounds.size));
                        bounds = new Bounds(pos, Vector3.zero);
                    }
                    else
                    {
                        bounds.Encapsulate(pos); // 扩展包围框
                    }
                }
                hrefInfo.boxes.Add(new Rect(bounds.min, bounds.size));
            }
            m_DisableFontTextureRebuiltCallback = false;
        }
    
        /// <summary>
        /// 点击事件检测是否点击到超链接文本
        /// </summary>
        /// <param name="eventData"></param>
        public void OnPointerClick(PointerEventData eventData)
        {
            Vector2 lp;
            RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, eventData.position, eventData.pressEventCamera, out lp);
            foreach (var hrefInfo in m_HrefInfos)
            {
                var boxes = hrefInfo.boxes;
                for (var i = 0; i < boxes.Count; ++i)
                {
                    if (boxes[i].Contains(lp))
                    {
                        m_OnHrefClick.Invoke(hrefInfo.name);
                        return;
                    }
                }
            }
        }
    
        /// <summary>
        /// 获取超链接解析后的最后输出文本
        /// </summary>
        /// <returns></returns>
        protected string GetOutputText(string text)
        {
            s_TextBuilder.Length = 0;
            m_HrefInfos.Clear();
            int indexText = 0;
            foreach (Match match in s_HrefRegex.Matches(text))
            {
                s_TextBuilder.Append(text.Substring(indexText, match.Index - indexText));
                Debug.Log(m_HyperlinkColor12);
                s_TextBuilder.AppendFormat("<color={0}>", m_HyperlinkColor12);  // 超链接颜色
                var group = match.Groups[1];
                HrefInfo hrefInfo = new HrefInfo
                {
                    startIndex = s_TextBuilder.Length * 4, // 超链接里的文本起始顶点索引
                    endIndex = (s_TextBuilder.Length + match.Groups[2].Length - 1) * 4 + 3,
                    name = group.Value
                };
                m_HrefInfos.Add(hrefInfo);
    
                s_TextBuilder.Append(match.Groups[2].Value);
                s_TextBuilder.Append("</color>");
                indexText = match.Index + match.Length;
            }
            s_TextBuilder.Append(text.Substring(indexText, text.Length - indexText));
            return s_TextBuilder.ToString();
        }
    
    
    

    超链接标签格式:<a href=name>[show]</a>

    文本内容为:

    {0}这是一个支持表情系统{1}的EmojiText{2},运行时支持动态表情。
    {3}<a href=12>[前往]</a>{4}{5}{6}{7}{8}{9}{10}{11}{12}{13}{14}{15}{16}{17}{18}{19}{20}{21}{22}{23}{24}{25}{26}{27}口
    <a href=qw>[前往]</a>

    最终效果为:2个Text也只会占用一个batches

    展开全文
  • Unity图文混排

    2020-01-12 14:03:30
    将生成的json文件与图集放入项目中(如果使用其他地方也需要用图集就生成Unity类型的) 需要注意的是图集最好打成正方形的 否则会被拉伸成正方形 二.生成asset文件 1)Json格式的打开SpriteImporter 将生成的...
  • 文本内超链接(附下划线),文本内插入图片
  • Unity 图文混排超链接图片均可点击

    千次阅读 2018-03-12 16:04:50
    1.在其他博主的基础上,增加了图片可以点击的功能,因为我临时遇到了这个需求,这应该是图文混排的终极版本了吧,如果以后图文混排相关功能还有增加的话,我再临时更新此篇文章吧!希望可以帮到拥有同样需求的你们,...
  • Unity UGUI实现图文混排组件——EmojiText(支持图标,动态表情,按钮,超链接)
  • Unity UGUI图文混排源码(二)

    万次阅读 热门讨论 2016-04-10 12:55:08
    为了方便整理,申请了一个专栏,链接:Unity UGUI图文混排专栏
  • Unity UGUI实现图文混排

    万次阅读 多人点赞 2016-03-28 20:05:38
    目前在unity实现图文混排的好像都是通过自定义字体然后在文本获取字符的位置,用图片替换掉图片标签,这样对于支持英文来说,并没有什么影响。然后对于中文来说就是一个相当麻烦的事了,毕竟图文混排多用于游戏聊天...
  • 最近想把过去做过的一些技术梳理一下,于是首先想到的就是UGUI的图文混排。 UGUI的图文混排主要用于实现游戏中的聊天系统,它主要包含表情系统和超连接系统两大块 表情系统和超连接这两大块的实现方式都是基于对...
  • 最近Unity2018发布了,在这个版本里Unity做了很多插件让开发更容易,这些插件不是依赖工程的,也就是说不用再往项目里导入package包了。而是通过unity本身的PackageManager导入。在Project面板是看不到任何文件或者...
  • Unity UGUI图文混排源码(一)

    万次阅读 2016-04-10 12:54:15
    Unity UGUI图文混排源码(一):http://blog.csdn.net/qq992817263/article/details/51112304 Unity UGUI图文混排源码(二):http://blog.csdn.net/qq992817263/article/details/51112311 我从一开始想到的图文混排的...
  • #if UNITY_EDITOR using UnityEditor; #endif namespace UnityEngine.UI { /// /// Emoji Text组件 /// /// 用法用例: /// 图片 (NodeImage): /// 按钮 (NodeButton): /// Emoji表情 (NodeEmoji): /// 超链接 ...
  • 主要记录一下,万一自己忘记了别人博客删除了。 好记性不如烂笔头! 制作中文字体: 1....TextMeshPro里面打开Font Asset Creator ... 2.Source Font File中添加支持...1.图集制作:导入需要用于制作图片到unity中,将...
  • unity TextMeshPro 图文混排 切换图集

    千次阅读 2020-12-05 18:31:32
    unity TextMeshPro 图文混排 切换图集 本文仅做实现 暂无讲解 如有错误 还望指出 TextMeshPro组件 新建项目 创建TextMeshPro 尝试输入 汉字显示失败 需制作字体文件 打开Windows-》TextMeshPro-》...
  • 文章目录一、前言二、最终效果...我们在Unity中如何实现这种图文混排的效果呢?今天就来介绍下Unity UGUI Text图文混排的实现吧。 二、最终效果 本文Demo工程已上传到CodeChina,感兴趣的同学可自行下载学习。 地址:h
  • UGUI图文混排插件Text Mesh Pro

    千次阅读 2018-10-24 14:19:00
    https://github.com/UnityTechnologies/Test_ShaderGraphBlog 插件在线文档: http://digitalnativestudios.com/textmeshpro/docs/ 使用效果 See the &lt;link="ID_01"&gt;&lt;u&gt;&...
  • 继上一篇说的更新了一张图集对应多个Text的功能,为了节省资源嘛 这里,但是也没有舍弃之前的一个Text一个图集,因为我感觉应该两个都有用,于是我重新写了一个脚本 1.其实大体跟前面的都没变,解析标签,获取表情...
  • unity聊天系统 图文混排

    千次阅读 2018-04-27 14:37:32
    使用unity3d也有两年时间了,最近比较闲,有功夫梳理一下去年一年来学到以及用到的知识,分享给大家,顺便方便自己查阅。如有错误以及不当的地方,欢迎各位指正。谢谢。 去年五月份的时候,刚加入项目不久,老大...
  • 在网上原有的继承于UGUI的Text基础上根据正则表达式找出表情标记文本替换为表情图片并实现序列帧动画的基础上扩展了下划线和超链接功能,跟UGUI的下划线和超链接功能一样
  • unity2019的文本的模型数据有所改进,具体的计算代码在c ++代码重叠,没有追踪到具体的信息,暂时测试出来的信息,如果文本文本,长度足够自动换行,模型顶部的数据信息跟unity2017同样,如果长度保持在一行以内...
  • HubUI优化 问题点: 不管是使用NGUI还是UGUI,控件的刷新都会导致面板的重绘制。... 一次绘制传入多个纹理 (图片、表情、文字) 为文字图片制作动态图集 在一个Shader和一个Material中进行图文混排绘制
  • 感觉使用Unity之后总能看到各种各样解决混排的方案,只能说明Unity不够体恤下情啊。这篇文章主要讲一下个人在使用过程中方案选择和优化过程,已做记录。顺便提下,开源很多意味着坑,还是要开实际需求。 1. ...
  • 图文混排 从字面意思来理解:就是图片和文字混合在一起。不知道这样的的定义是否正确,起码我是这样理解的,在游戏开发过程中,如果单单从业务逻辑去看的话,图文混排算是比较复杂的。个人感觉也是必须会的技能。 ...

空空如也

空空如也

1 2 3 4 5 ... 14
收藏数 280
精华内容 112
关键字:

unity图文混排