1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > Unity表情聊天(NGUI图文混排)

Unity表情聊天(NGUI图文混排)

时间:2021-05-06 17:30:13

相关推荐

Unity表情聊天(NGUI图文混排)

图文混排

从字面意思来理解:就是图片和文字混合在一起。不知道这样的的定义是否正确,起码我是这样理解的,在游戏开发过程中,如果单单从业务逻辑去看的话,图文混排算是比较复杂的。个人感觉也是必须会的技能。

原理

我们期待在文本的合适地方插入我们需要显示的表情。所以我们要取插入表情的位置,但是一条聊天的信息是一段文本的字符串,是一个整体,每一个字符都不是单个对象,所以要在文本字符串中取合适的位置就不能用平时的方法(ps:UILabe的本质是一张面片),好在NGUI底层给我们提供了顶点信息的集合。

/// <summary>/// Widget's vertices (before they get transformed)./// </summary>public BetterList<Vector3> verts = new BetterList<Vector3>();

现在我们已经找到突破口,verts保存的是位置信息,那么只有我们算出表情在第几个字后面就可以取得位置信息了。具体步骤如下:

1 定义表情的数据格式,

2 在写入字符串时候,加上特效的标记,然后用正则表达去匹配和替换字符。3 遍历整个文本,把之前标记的位置记录下来。并且使用空格去替换标记的内容。4 创建表情对象,把第三步取到的位置信息赋值给刚刚创建的表情对象

核心代码

using System;using System.Collections.Generic;using System.Text;using System.Text.RegularExpressions;using UnityEngine;public class UIEmojiWrapper{private bool hasAtlas = false;public UIAtlas mAtlas;private GameObject emojiPrefab;private Dictionary<string, string> emojiName = new Dictionary<string, string>();private List<Expression> listCfgData = new List<Expression>();private Queue<GameObject> freeSprite = new Queue<GameObject>();private List<GameObject> usedSprite = new List<GameObject>();private Vector3 OutOffScreen = new Vector3(10000f, 10000f, 10000f);private static UIEmojiWrapper sInstance;public static UIEmojiWrapper Instance{get{if (sInstance == null){sInstance = new UIEmojiWrapper();}return sInstance;}}public void Init(UIAtlas atlas){if (!hasAtlas){if (atlas == null){Debug.LogError("[UIEmojiWrapper Atlas is null]");return;}mAtlas = atlas;//预分配AddEmojiName();emojiPrefab = new GameObject();emojiPrefab.layer = 8;hasAtlas = true;}}public GameObject EmojiPrefab{get{if (emojiPrefab == null){emojiPrefab = new GameObject();emojiPrefab.layer = 8;}return emojiPrefab;}}//表情字典public void AddEmojiName(){List<Expression> listCfgEmo = SetlistExpression();if (listCfgEmo == null){return;}listCfgData.Clear();listCfgData = listCfgEmo;for (int i = 0; i < listCfgEmo.Count; i++){int m_key = (int)listCfgEmo[i].key;string name = listCfgEmo[i].value;string sprKey = GetConvertedInt32(m_key.ToString());emojiName.Add(sprKey, name);}}public string GetConvertedString(string inputString){string[] converted = inputString.Split('-');for (int j = 0; j < converted.Length; j++){int value = Convert.ToInt32(converted[j], 16);converted[j] = char.ConvertFromUtf32(value);}return string.Join(string.Empty, converted);}public string GetConvertedInt32(string inputString){int value = int.Parse(inputString);string[] converted = new string[1];converted[0] = char.ConvertFromUtf32(value);return string.Join(string.Empty, converted);}//从对象池取对象public string GetEmoji(string encode){string em;if (emojiName.TryGetValue(encode, out em)){return em;}return null;}public bool HasEmoji(string key){// 120000 120001 120002return emojiName.ContainsKey(key);}public List<Expression> GetListCfgData(){return listCfgData;}// 取表情数据Keypublic int GetEmojiKey(string _value){if (listCfgData.Count > 0){for (int i = 0; i < listCfgData.Count; i++){if (_value == listCfgData[i].name){return (int)listCfgData[i].key;}}}return -1;}public void OnPostFill(UIWidget widget, int bufferOffset, BetterList<Vector3> verts, BetterList<Vector2> uvs, BetterList<Color32> cols){if (widget != null){if (!widget.isVisible){UISprite spt = widget as UISprite;if (spt != null){PushEmoji(spt.gameObject);}}}}public GameObject PopEmoji(){if (freeSprite.Count <= 0){if (emojiPrefab == null)return null;GameObject tran = GameObject.Instantiate(emojiPrefab) as GameObject;freeSprite.Enqueue(tran);}GameObject sptRet = freeSprite.Dequeue();if (sptRet != null){usedSprite.Add(sptRet);}return sptRet;}public void PushEmoji(GameObject spt){//spt.transform.localPosition = OutOffScreen;// spt.transform.parent = null;freeSprite.Enqueue(spt);}public void PushEmoji(ref List<GameObject> list){for (int i = 0, cnt = list.Count; i < cnt; i++){PushEmoji(list[i]);}list.Clear();}/// <summary>/// 字符串替换方法/// </summary>/// <param name="myStr">需要替换的字符串</param>/// <param name="displaceA">需要替换的字符</param>/// <param name="displaceB">将替换为</param>/// <returns></returns>public string Displace(string myStr, string displaceA, string displaceB){string[] strArrayA = Regex.Split(myStr, displaceA);for (int i = 0; i < strArrayA.Length - 1; i++){strArrayA[i] += displaceB;}string returnStr = "";foreach (string var in strArrayA){returnStr += var;}return returnStr;}//建议用json或者其他的数据格式public static List<Expression> SetlistExpression(){List<Expression> data = new List<Expression>();data.Add(new Expression(120000, "ziya", 1, "龇牙"));data.Add(new Expression(120001, "zhouma", 1, "咒骂"));data.Add(new Expression(120002, "youxian", 1, "悠闲"));data.Add(new Expression(120003, "weixiao", 1, "微笑"));data.Add(new Expression(120004, "qiaoda", 1, "敲打"));data.Add(new Expression(120005, "nanguo", 1, "难过"));data.Add(new Expression(120006, "daxiao", 1, "大笑"));data.Add(new Expression(120008, "deng", 1, "瞪"));data.Add(new Expression(120009, "dese", 1, "得瑟"));data.Add(new Expression(120010, "dese", 1, "得意"));data.Add(new Expression(120011, "lianhong", 1, "脸红"));data.Add(new Expression(120012, "keai", 1, "可爱"));data.Add(new Expression(120013, "han", 1, "汗"));data.Add(new Expression(120014, "ganga", 1, "尴尬"));data.Add(new Expression(120015, "se", 1, "色"));data.Add(new Expression(120016, "kun", 1, "困"));data.Add(new Expression(120017, "ku", 1, "酷"));data.Add(new Expression(120018, "baiyan", 1, "白眼"));data.Add(new Expression(120019, "baoya", 1, "龅牙"));data.Add(new Expression(120020, "beida", 1, "被打"));return data;}}public class Expression{public uint key;// 16进制编号public string value;// 前缀public uint sin;// 是否序列帧public string name;// 名称public Expression(uint key, string value, uint sin, string name){this.key = key;this.value = value;this.sin = sin;this.name = name;}}

using System;using System.Collections;using System.Collections.Generic;using System.Text;using System.Text.RegularExpressions;using UnityEngine;public class UIEmojiLabel : UILabel{private char emSpace = '\u2001';private List<GameObject> mEmojiList = new List<GameObject>();public UIAtlas emAtlas = null;protected override void Awake(){base.Awake();UIEmojiWrapper.Instance.Init(emAtlas);}protected override void OnStart(){base.OnStart();//表情统一管理器,只初始化一次}//自动转码public override void OnFill(BetterList<Vector3> verts, BetterList<Vector2> uvs, BetterList<Color32> cols){base.OnFill(verts, uvs, cols);// StartCoroutine(SetUITextThatHasEmoji(text));}public void ShowEmojiText(string strText){//strText = "图形测试 (ziya) 呵呵 (youxian)"//找到表情特殊标记()Regex reg = new Regex(@"(?is)(?<=\()[^\)]+(?=\))");MatchCollection mc = reg.Matches(strText);if (mc != null){for (int i = 0; i < mc.Count; i++){string oldStr = string.Format("({0})", mc[i].Value); //旧字符int key = UIEmojiWrapper.Instance.GetEmojiKey(mc[i].Value);if (key > 0){string newStr = UIEmojiWrapper.Instance.GetConvertedInt32(key.ToString()); //薪字符strText = strText.Replace(oldStr, newStr);}}}text = strText;StartCoroutine(SetUITextThatHasEmoji(strText));}private struct PosStringTuple{public int pos;public string emoji;public PosStringTuple(int p, string s){this.pos = p;this.emoji = s;}}private void DestroyEmojiSpr(){if (this.mEmojiList.Count > 0){for (int i = 0; i < this.mEmojiList.Count; i++){Destroy(this.mEmojiList[i]);}this.mEmojiList.Clear();}}public IEnumerator SetUITextThatHasEmoji(string inputString){inputString = inputString.Replace(" ", "&&");inputString = inputString.Replace(" ", "&");List<PosStringTuple> emojiReplacements = new List<PosStringTuple>();StringBuilder sb = new StringBuilder();//先回收DestroyEmojiSpr();int i = 0;while (i < inputString.Length){string singleChar = inputString.Substring(i, 1);string doubleChar = "";string fourChar = "";if (i < (inputString.Length - 1)){doubleChar = inputString.Substring(i, 2);}if (i < (inputString.Length - 3)){fourChar = inputString.Substring(i, 4);}if (UIEmojiWrapper.Instance.HasEmoji(fourChar)){// Check 64 bit emojis firstsb.Append(emSpace);int blankSpaceConut = GetBlankSpaceConut(sb);emojiReplacements.Add(new PosStringTuple(sb.Length - 1, fourChar));i += 4;}else if (UIEmojiWrapper.Instance.HasEmoji(doubleChar)){sb.Append(emSpace);emojiReplacements.Add(new PosStringTuple(sb.Length - 1, doubleChar));i += 2;}else if (UIEmojiWrapper.Instance.HasEmoji(singleChar)){sb.Append(emSpace);emojiReplacements.Add(new PosStringTuple(sb.Length - 1, singleChar));i++;}else{sb.Append(inputString[i]);i++;}}this.text = sb.ToString();yield return null;for (int j = 0; j < emojiReplacements.Count; j++){int emojiIndex = emojiReplacements[j].pos;//表情替换,计算位置,大小GameObject go = GameObject.Instantiate(UIEmojiWrapper.Instance.EmojiPrefab);mEmojiList.Add(go);if (go != null){UISprite spt = go.AddComponent<UISprite>();string emoji = UIEmojiWrapper.Instance.GetEmoji(emojiReplacements[j].emoji);if (!string.IsNullOrEmpty(emoji)){spt.atlas = UIEmojiWrapper.Instance.mAtlas;spt.name = emoji;spt.spriteName = emoji + "_1";spt.width = this.ChatPrintedSize;spt.height = this.ChatPrintedSize;spt.depth = this.depth + 10;spt.transform.parent = this.transform;spt.transform.localScale = Vector3.one;Vector3 pos = new Vector3();try{pos = new Vector3(this.geometry.verts[emojiIndex * 4].x + spt.width / 2, (this.geometry.verts[emojiIndex * 4].y + spt.height / 2) - 8);spt.transform.localPosition = pos;UISpriteAnimation sprAni = go.AddComponent<UISpriteAnimation>();sprAni.namePrefix = emoji + "_";sprAni.framesPerSecond = 3;sprAni.Snap = false;sprAni.Play();isVertsBuff = false;}catch{Debug.LogError("geometry.verts == null");isVertsBuff = true;ShowEmojiText(oldText);}}}}if (!isVertsBuff){this.text = text.Replace("&&", " ");this.text = text.Replace("&", " ");}}}

#if !UNITY_3_5 && !UNITY_FLASH#define DYNAMIC_FONT#endifusing UnityEngine;using UnityEditor;/// <summary>/// Inspector class used to edit UILabels./// </summary>[CanEditMultipleObjects]#if UNITY_3_5[CustomEditor(typeof(UILabel))]#else[CustomEditor(typeof(UILabel), true)]#endifpublic class UIEmojiLabelInspector : UILabelInspector{/// <summary>/// Draw the label's properties./// </summary>protected override bool ShouldDrawProperties(){bool isValid = base.ShouldDrawProperties();EditorGUI.BeginDisabledGroup(!isValid);NGUIEditorTools.DrawProperty("Atlas", serializedObject, "emAtlas");//表情所在的图集AtlasEditorGUI.EndDisabledGroup();return isValid;}}

主要事项

1 上面的代码改了一下部分NGUI的接口,直接拷贝会报错,你可以自己手动加,都是很简单的接口。我也会上传一份dome

2 在Lua层调C#的时候,有机会出现第一次会报verts为空,我还没有找到原因,欢迎大神指点,我现在的解决方法是延迟执行。

如果大佬们有好的方法,也求推荐。

3 看看 最终效果是带动态的哦!!

表情聊天— 图文混排下载

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。