Project_WL/Assets/ThirdParty/NGUI/Scripts/Tweening/TweenLetters.cs

284 lines
7.6 KiB
C#
Raw Permalink Normal View History

2024-12-15 01:39:39 +00:00
//-------------------------------------------------
// NGUI: Next-Gen UI kit
// Copyright © 2011-2019 Tasharen Entertainment Inc
//-------------------------------------------------
using UnityEngine;
using System.Collections.Generic;
/// <summary>
/// Attaching this script to a label will make the label's letters animate.
/// </summary>
public class TweenLetters : UITweener
{
[DoNotObfuscateNGUI] public enum AnimationLetterOrder { Forward, Reverse, Random }
class LetterProperties
{
public float start;
public float duration; // if RandomDurations is set, these will all be different.
public Vector2 offset;
}
[System.Serializable]
public class AnimationProperties
{
public AnimationLetterOrder animationOrder = AnimationLetterOrder.Random;
[Range(0f, 1f)]
public float overlap = 0.5f;
public bool randomDurations = false;
[MinMaxRange(0f, 1f)]
public Vector2 randomness = new Vector2(0.25f, 0.75f);
public Vector2 offsetRange = Vector2.zero;
public Vector3 pos = Vector3.zero;
public Vector3 rot = Vector3.zero;
public Vector3 scale = Vector3.one;
public float alpha = 1f;
}
public AnimationProperties hoverOver;
public AnimationProperties hoverOut;
UILabel mLabel;
int mVertexCount = -1;
int[] mLetterOrder;
LetterProperties[] mLetter;
AnimationProperties mCurrent;
void OnEnable ()
{
mVertexCount = -1;
mLabel.onPostFill += OnPostFill;
}
void OnDisable ()
{
mLabel.onPostFill -= OnPostFill;
}
void Awake ()
{
mLabel = GetComponent<UILabel>();
mCurrent = hoverOver;
}
public override void Play (bool forward)
{
mCurrent = (forward) ? hoverOver : hoverOut;
base.Play(forward);
}
void OnPostFill (UIWidget widget, int bufferOffset, List<Vector3> verts, List<Vector2> uvs, List<Color> cols)
{
if (verts == null) return;
var vertexCount = verts.Count;
if (verts == null || vertexCount == 0) return;
if (mLabel == null) return;
#if !UNITY_EDITOR
try {
#endif
var quads = mLabel.quadsPerCharacter;
const int quadVerts = 4;
var characterCount = vertexCount / quads / quadVerts;
var pt = mLabel.printedText;
if (mVertexCount != vertexCount)
{
mVertexCount = vertexCount;
SetLetterOrder(characterCount);
GetLetterDuration(characterCount);
}
var mtx = Matrix4x4.identity;
var lerpPos = Vector3.zero;
var lerpRot = Quaternion.identity;
var lerpScale = Vector3.one;
var lerpAlpha = 1f;
int firstVert, letter;
float letterStart, t; // The individual letters tweenFactor
var letterCenter = Vector3.zero;
var qRot = Quaternion.Euler(mCurrent.rot);
var vert = Vector3.zero;
var c = Color.clear;
var timeIntoAnimation = tweenFactor * duration;
for (int q = 0; q < quads; ++q)
{
for (int i = 0; i < characterCount; ++i)
{
letter = mLetterOrder[i]; // Choose which letter to animate.
firstVert = q * characterCount * quadVerts + letter * quadVerts;
if (firstVert >= vertexCount)
{
#if UNITY_EDITOR
Debug.LogError("TweenLetters encountered an unhandled case trying to modify a vertex " + firstVert + ". Vertex Count: " + vertexCount + " Pass: " + q + "\nText: " + pt);
#endif
continue;
}
letterStart = mLetter[letter].start;
t = Mathf.Clamp(timeIntoAnimation - letterStart, 0f, mLetter[letter].duration) / mLetter[letter].duration;
t = animationCurve.Evaluate(t);
letterCenter = GetCenter(verts, firstVert, quadVerts);
var v = mLetter[letter].offset;
#if UNITY_4_7
lerpPos = LerpUnclamped(mCurrent.pos + new Vector3(v.x, v.y, 0f), Vector3.zero, t);
lerpRot = Quaternion.Slerp(qRot, Quaternion.identity, t);
lerpScale = LerpUnclamped(mCurrent.scale, Vector3.one, t);
lerpAlpha = LerpUnclamped(mCurrent.alpha, 1f, t);
#else
lerpPos = Vector3.LerpUnclamped(mCurrent.pos + new Vector3(v.x, v.y, 0f), Vector3.zero, t);
lerpRot = Quaternion.SlerpUnclamped(qRot, Quaternion.identity, t);
lerpScale = Vector3.LerpUnclamped(mCurrent.scale, Vector3.one, t);
lerpAlpha = Mathf.LerpUnclamped(mCurrent.alpha, 1f, t);
#endif
mtx.SetTRS(lerpPos, lerpRot, lerpScale);
for (int iv = firstVert; iv < firstVert + quadVerts; ++iv)
{
vert = verts[iv];
vert -= letterCenter;
vert = mtx.MultiplyPoint3x4(vert);
vert += letterCenter;
verts[iv] = vert;
c = cols[iv];
c.a *= lerpAlpha;
cols[iv] = c;
}
}
}
#if !UNITY_EDITOR
} catch (System.Exception) { enabled = false; }
#endif
}
#if UNITY_4_7
static Vector3 LerpUnclamped (Vector3 a, Vector3 b, float f)
{
a.x = a.x + (b.x - a.x) * f;
a.y = a.y + (b.y - a.y) * f;
a.z = a.z + (b.z - a.z) * f;
return a;
}
static float LerpUnclamped (float a, float b, float f) { return a + (b - a) * f; }
#endif
/// <summary>
/// Check every frame to see if the text has changed and mark the label as having been updated.
/// </summary>
protected override void OnUpdate (float factor, bool isFinished)
{
mLabel.MarkAsChanged();
}
/// <summary>
/// Sets the sequence that the letters are animated in.
/// </summary>
void SetLetterOrder (int letterCount)
{
if (letterCount == 0)
{
mLetter = null;
mLetterOrder = null;
return;
}
mLetterOrder = new int[letterCount];
mLetter = new LetterProperties[letterCount];
for (int i = 0; i < letterCount; ++i)
{
mLetterOrder[i] = (mCurrent.animationOrder == AnimationLetterOrder.Reverse) ? letterCount - 1 - i : i;
int current = mLetterOrder[i];
mLetter[current] = new LetterProperties();
mLetter[current].offset = new Vector2(Random.Range(-mCurrent.offsetRange.x, mCurrent.offsetRange.x), Random.Range(-mCurrent.offsetRange.y, mCurrent.offsetRange.y));
}
if (mCurrent.animationOrder == AnimationLetterOrder.Random)
{
// Shuffle the numbers in the array.
var rng = new System.Random();
int n = letterCount;
while (n > 1)
{
int k = rng.Next(--n + 1);
int tmp = mLetterOrder[k];
mLetterOrder[k] = mLetterOrder[n];
mLetterOrder[n] = tmp;
}
}
}
/// <summary>
/// Returns how long each letter has to animate based on the overall duration requested and how much they overlap.
/// </summary>
void GetLetterDuration (int letterCount)
{
if (mCurrent.randomDurations)
{
for (int i = 0; i < mLetter.Length; ++i)
{
mLetter[i].start = Random.Range(0f, mCurrent.randomness.x * duration);
float end = Random.Range(mCurrent.randomness.y * duration, duration);
mLetter[i].duration = end - mLetter[i].start;
}
}
else
{
// Calculate how long each letter will take to fade in.
float lengthPerLetter = duration / letterCount;
float flippedOverlap = 1f - mCurrent.overlap;
// Figure out how long the animation will be taking into account overlapping letters.
float totalDuration = lengthPerLetter * letterCount * flippedOverlap;
// Scale the smaller total running time back up to the requested animation time.
float letterDuration = ScaleRange(lengthPerLetter, totalDuration + lengthPerLetter * mCurrent.overlap, duration);
float offset = 0;
for (int i = 0; i < mLetter.Length; ++i)
{
int letter = mLetterOrder[i];
mLetter[letter].start = offset;
mLetter[letter].duration = letterDuration;
offset += mLetter[letter].duration * flippedOverlap;
}
}
}
/// <summary>
/// Simplified Scale range function that assumes a minimum of 0 for both ranges.
/// </summary>
float ScaleRange (float value, float baseMax, float limitMax)
{
return (limitMax * value / baseMax);
}
/// <summary>
/// Finds the center point of a series of verts.
/// </summary>
static Vector3 GetCenter (List<Vector3> verts, int firstVert, int length)
{
Vector3 center = verts[firstVert];
for (int v = firstVert + 1; v < firstVert + length; ++v) center += verts[v];
return center / length;
}
}