NGUI丰富的文字特效拓展

原理就是监听UILabel.onPostFill事件,然后修改里面的verts等属性

mLabel = GetComponent();
mLabel.onPostFill += OnPostFillHandle;
void OnPostFillHandle(UIWidget widget, int bufferOffset, BetterList verts, BetterList uvs, BetterList cols){
		int max = mEffects.Count;
		for (int i = 0; i < max; i++) {
			var effectEntry = mEffects [i];
			int start = effectEntry.index * 4;
			int end = start + effectEntry.text.Length * 4;

			if (start > verts.size)
				continue;
			if (end > verts.size)
				continue;
			ApplyEffects (verts, uvs, cols, start, end, effectEntry);
		}
	}

	void ResetEffectValue(){
		wordTempValue.Clear ();
	}

	void ApplyEffects(BetterList verts, BetterList uvs, BetterList cols, int start, int end,EffectEntry effectEntry){
		for (int i = start; i < end; ++i) {
			Vector3 vert = verts [i];
			Color32 color = cols [i];
			byte alpha = color.a;

			string key = effectEntry.key;
			if (key.StartsWith ("{!")) {
				vert.x += angryStrength * (Random.insideUnitCircle * angryJitterStrength).x * (i % 2 == 0 ? 1 : -1);
				vert.y += angryStrength * (Random.insideUnitCircle * angryJitterStrength).y * (i % 2 == 0 ? 1 : -1);
				color = angryColor;
			} else if (key.StartsWith ("{~")) {
				int wordIndex = (int)((float)i / 4f) - start;
				float wordInterval = wordIndex * waveGap;
				float angle = GetWordVar (i, wordInterval) + waveSpeed;
				vert.y += Mathf.Sin (angle) * waveDistance;
				color = waveColor;
				SetWordVar (i, angle);
			}
			else if(key.StartsWith ("{@")){
				float angle = GetWordVar (i) + waveSpeed;
				vert.x += Mathf.Cos(angle) * angryStrength - Mathf.Sin(angle) * angryStrength;
				vert.y += Mathf.Cos(angle) * angryStrength + Mathf.Sin(angle) * angryStrength;
				color = waveColor;
				SetWordVar (i, angle);
			}
			else if(key.StartsWith ("{#")){
				float angle = GetWordVar (i) + happySpeed;
				vert.y += Mathf.Sin (angle) * happyDistance;
				color = happyColor;
				SetWordVar (i, angle);
			}
			color.a = alpha;
			verts [i] = vert;
			cols [i] = color;
		}
	}
效果预览:

NGUI丰富的文字特效拓展_第1张图片

完整代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Text.RegularExpressions;

[RequireComponent(typeof(UILabel))]
public class SmartUILabel : MonoBehaviour {
	public struct EffectEntry
	{
		public int id;
		public int index;
		public string key;
		public string text;
	}
	public struct SplitEntry
	{
		public int id;
		public int index;
		public string left;
		public string right;
		public string total;
		public string value;
	}

	/// 
	/// How many characters will be printed per second.
	/// 
	public int charsPerSecond = 20;
	public bool keepFullDimensions = true;
	public float angryStrength = 2f;
	public float angryJitterStrength = 2f;
	public Color angryColor = Color.red;
	public float waveGap = 0.5f;
	public float waveSpeed = 0.2f;
	public float waveDistance = 5f;
	public Color waveColor=Color.yellow;
	public float happyDistance = 5f;
	public Color happyColor=Color.yellow;
	public float happySpeed = 0.25f;
	public UnityEngine.Events.UnityEvent onFinished;

	UILabel mLabel;
	string mFullText = "";
	int mCurrentOffset = 0;
	float mNextChar = 0f;
	bool mReset = true;
	bool mActive = false;
	int mTempId=0;
	List mEffects=new List();
	List mSplitEntries=new List();

	public bool IsActive { get { return mActive; } }
	void OnEnable () { mReset = true; mActive = true; }
	void OnDisable () { Finish(); }

	public void Replay(){
		mReset = true;
		mActive = true;
		mNextChar = 0f;
		mCurrentOffset = 0;
		Update();
	}

	public void Finish ()
	{
		if (mActive)
		{
			mActive = false;

			if (!mReset)
			{
				mCurrentOffset = mFullText.Length;
				mLabel.text = mFullText;
			}

			onFinished.Invoke ();
		}
	}

	void Update () {
		if (mActive) {
			if (mReset)
			{
				mReset = false;
				Reset ();
			}

			if (string.IsNullOrEmpty(mFullText)) return;

			while (mCurrentOffset < mFullText.Length && mNextChar <= RealTime.time) {
				int lastOffset = mCurrentOffset;

				char lastChar = mFullText [lastOffset];

				++mCurrentOffset;

				if (mCurrentOffset > mFullText.Length) break;

				char currentChar = (mCurrentOffset <= mFullText.Length - 1) ? mFullText [mCurrentOffset] : '\0';

				float delay = 1f / charsPerSecond;
				if (mNextChar == 0f)
				{
					mNextChar = RealTime.time + delay;
				}
				else mNextChar += delay;

				if (lastChar=='{' && (currentChar == '<' || currentChar=='>')) {
					int keyEndIndex = mFullText.IndexOf ('}', mCurrentOffset);
					if (keyEndIndex != -1) {
						string realKey = mFullText.Substring (lastOffset, keyEndIndex - lastOffset + 1);
						mFullText = mFullText.Remove (lastOffset, keyEndIndex - lastOffset + 1);
						mCurrentOffset -= 1;
						bool isSpeedUp = realKey.IndexOf (">>") != -1;

						Regex reg = new Regex (@"[{}><\s]");
						string k = reg.Replace (realKey,"");
						float realValue = 0f;
						float.TryParse (k, out realValue);
						mNextChar += realValue * (isSpeedUp ? 1f : -1f);
					}
				}

				if (mCurrentOffset >= mFullText.Length) {
					mLabel.text = mFullText;
					onFinished.Invoke ();
					mActive = false;
				} else {
					mLabel.text = keepFullDimensions ?
						mFullText.Substring (0, mCurrentOffset) + "[00]" + mFullText.Substring (mCurrentOffset) :
						mFullText.Substring (0, mCurrentOffset);
				}
			}
		}

		if (HasEffect) {
			mLabel.MarkAsChanged ();
		}
	}

	void SplitValues(){
		SplitValue ("!");
		SplitValue ("~");
		SplitValue ("@");
		SplitValue ("#");

		foreach (var oldEffect in mEffects) {
			Debug.Log ("Key=" + oldEffect.key + "  value:" + oldEffect.text + "  Index:" + oldEffect.index);
		}
	}

	void SplitValue(string matchKey){
		string content=mFullText;
		string splitRegex = "({" + matchKey + @"})(\S*?)({/" + matchKey + "})";

		string newContent = content;

		mSplitEntries.Clear ();
		foreach (Match match in Regex.Matches(content, splitRegex)) {
			string key = matchKey;
			string text = match.Groups [2].Value;
			int index = match.Index;

			string total = match.Value;
			string left = match.Groups [1].Value;
			string right = match.Groups [3].Value;

			SplitEntry splitEntry = new SplitEntry ();
			splitEntry.id = ++mTempId;
			splitEntry.index = index;
			splitEntry.left = left;
			splitEntry.right = right;
			splitEntry.value = text;
			splitEntry.total = total;
			mSplitEntries.Add (splitEntry);
		}

		for (int i = 0; i < mSplitEntries.Count; i++) {
			SplitEntry splitEntry = mSplitEntries [i];

			string total = splitEntry.total;
			string left = splitEntry.left;
			string right = splitEntry.right;
			int rightIndex = total.IndexOf (right);
			total = total.Remove (rightIndex, right.Length);
			int leftIndex = total.IndexOf (left);
			total = total.Remove (leftIndex, left.Length);

			int newRightIndex = splitEntry.index + rightIndex;
			newContent = newContent.Remove (newRightIndex, right.Length);
			if (newRightIndex < splitEntry.index) {
				splitEntry.index -= right.Length;
			}

			int newLeftIndex = splitEntry.index + leftIndex;
			newContent = newContent.Remove (newLeftIndex, left.Length);
			if (newLeftIndex < splitEntry.index ) {
				splitEntry.index  -= left.Length;
			}

			for (int j = 0; j < mSplitEntries.Count; j++) {
				var newSplitEntry = mSplitEntries [j];
				if (newSplitEntry.id.Equals(splitEntry.id))
					continue;
				if (newRightIndex < newSplitEntry.index) {
					newSplitEntry.index -= right.Length;
				}
				if (newLeftIndex < newSplitEntry.index ) {
					newSplitEntry.index  -= left.Length;
				}
				mSplitEntries [j] = newSplitEntry;
			}

			for (int j = 0; j < mEffects.Count; j++) {
				var newEffectEntry = mEffects [j];
				if (newEffectEntry.id.Equals(splitEntry.id))
					continue;
				if (newRightIndex < newEffectEntry.index) {
					newEffectEntry.index -= right.Length;
				}
				if (newLeftIndex < newEffectEntry.index ) {
					newEffectEntry.index  -= left.Length;
				}
				mEffects [j] = newEffectEntry;
			}

			EffectEntry effectEntry = new EffectEntry ();
			effectEntry.id = splitEntry.id;
			effectEntry.index = splitEntry.index;
			effectEntry.key = splitEntry.left;
			effectEntry.text = splitEntry.value;
			mEffects.Add (effectEntry);

			mSplitEntries [i] = splitEntry;
		}

		mFullText = newContent;
	}

	void Reset(){
		if (mLabel != null) {
			mLabel.onPostFill -= OnPostFillHandle;
		}
		ResetEffectValue ();
		mEffects.Clear ();
		mSplitEntries.Clear ();
		mCurrentOffset = 0;
		mTempId = 0;
		mLabel = GetComponent();
		mLabel.onPostFill += OnPostFillHandle;
		mFullText = mLabel.processedText;

		SplitValues ();
	}

	void OnPostFillHandle(UIWidget widget, int bufferOffset, BetterList verts, BetterList uvs, BetterList cols){
		int max = mEffects.Count;
		for (int i = 0; i < max; i++) {
			var effectEntry = mEffects [i];
			int start = effectEntry.index * 4;
			int end = start + effectEntry.text.Length * 4;

			if (start > verts.size)
				continue;
			if (end > verts.size)
				continue;
			ApplyEffects (verts, uvs, cols, start, end, effectEntry);
		}
	}

	void ResetEffectValue(){
		wordTempValue.Clear ();
	}

	void ApplyEffects(BetterList verts, BetterList uvs, BetterList cols, int start, int end,EffectEntry effectEntry){
		for (int i = start; i < end; ++i) {
			Vector3 vert = verts [i];
			Color32 color = cols [i];
			byte alpha = color.a;

			string key = effectEntry.key;
			if (key.StartsWith ("{!")) {
				vert.x += angryStrength * (Random.insideUnitCircle * angryJitterStrength).x * (i % 2 == 0 ? 1 : -1);
				vert.y += angryStrength * (Random.insideUnitCircle * angryJitterStrength).y * (i % 2 == 0 ? 1 : -1);
				color = angryColor;
			} else if (key.StartsWith ("{~")) {
				int wordIndex = (int)((float)i / 4f) - start;
				float wordInterval = wordIndex * waveGap;
				float angle = GetWordVar (i, wordInterval) + waveSpeed;
				vert.y += Mathf.Sin (angle) * waveDistance;
				color = waveColor;
				SetWordVar (i, angle);
			}
			else if(key.StartsWith ("{@")){
				float angle = GetWordVar (i) + waveSpeed;
				vert.x += Mathf.Cos(angle) * angryStrength - Mathf.Sin(angle) * angryStrength;
				vert.y += Mathf.Cos(angle) * angryStrength + Mathf.Sin(angle) * angryStrength;
				color = waveColor;
				SetWordVar (i, angle);
			}
			else if(key.StartsWith ("{#")){
				float angle = GetWordVar (i) + happySpeed;
				vert.y += Mathf.Sin (angle) * happyDistance;
				color = happyColor;
				SetWordVar (i, angle);
			}
			color.a = alpha;
			verts [i] = vert;
			cols [i] = color;
		}
	}

	Dictionary wordTempValue=new Dictionary();

	float GetWordVar(int index){
		return GetWordVar (index, 0f);
	}
	float GetWordVar(int index,float defaultValue){
		if (!wordTempValue.ContainsKey (index)) {
			wordTempValue.Add (index, defaultValue);
		}
		return wordTempValue [index];
	}

	void SetWordVar(int index,float value){
		if (!wordTempValue.ContainsKey (index)) {
			wordTempValue.Add (index, 0f);
		}
		wordTempValue [index] = value;
	}

	bool HasEffect{
		get{ 
			return mEffects.Count > 0;
		}
	}
}

你可能感兴趣的:(unity3d,Unity拓展,开发,unity小技巧,NGUI,游戏开发踩坑记录)