To create a odometer in Unity is not easy. I couldn’t find a better one for my project.
Prepare all possible characters in a spinning roll and then stack them
void Prepare()
{
//keep the orginal text vector for future use
Meter.ForceMeshUpdate();
sourceVertices = (Vector3[])Meter.textInfo.CopyMeshInfoVertexData()[0].vertices.Clone();
Meter.textInfo.Clear();
var templateString = string.Empty;
foreach (var s in SpinStrip)
{
templateString += s + "\n";
}
//Update text to spinning text
Meter.text = templateString;
Meter.ForceMeshUpdate();
cachedMeshInfo = Meter.textInfo.CopyMeshInfoVertexData();
HideSpinCharacters();
Spin(Meter.textInfo.characterInfo[currentValue], centerOfRotation, 0);
Apply();
}
void HideSpinCharacters()
{
for (var i = 0; i < Meter.textInfo.characterCount; i++)
{
var charInfo = Meter.textInfo.characterInfo[i];
if (charInfo.isVisible)
{
Spin(charInfo, centerOfRotation, -90);
}
}
}
Spin each character one by one
...
IEnumerator Spin(Tuple<int, int, float> param)
{
for (var curChar = param.Item1; curChar < param.Item2;curChar += 2)
{
var curCharInfo = Meter.textInfo.characterInfo[curChar];
var nextCharInfo = Meter.textInfo.characterInfo[curChar + 2];
for (float degree = -90; degree <= 0; degree += param.Item3)
{
Spin(curCharInfo, centerOfRotation, (degree + 90) < 90 ? (degree + 90) : 90);
Spin(nextCharInfo, centerOfRotation, degree);
Apply();
yield return null;
}
yield return null;
}
}
void Spin(TMP_CharacterInfo charInfo, Vector3 centerOfRotation, float angleOfRotation)
{
// Get the index of the material used by the current character.
int materialIndex = charInfo.materialReferenceIndex;
// Get the index of the first vertex used by this text element.
int vertexIndex = charInfo.vertexIndex;
// Get the cached vertices of the mesh used by this text element (character or sprite).
// Determine the center point of each character at the baseline.
// Determine the center point of each character.
Vector2 charMidBasline = (sourceVertices[0] + sourceVertices[2]) / 2;
// Need to translate all 4 vertices of each quad to aligned with middle of character / baseline.
// This is needed so the matrix TRS is applied at the origin for each character.
Vector3 offset = charMidBasline;
Vector3[] destinationVertices = Meter.textInfo.meshInfo[materialIndex].vertices;
destinationVertices[vertexIndex + 0] = sourceVertices[0] - offset;
destinationVertices[vertexIndex + 1] = sourceVertices[1] - offset;
destinationVertices[vertexIndex + 2] = sourceVertices[2] - offset;
destinationVertices[vertexIndex + 3] = sourceVertices[3] - offset;
// This should calculate the matrix, which helps to roate odometer
Matrix4x4 translationToCenterPoint = Matrix4x4.Translate(centerOfRotation);
Matrix4x4 rotation = Matrix4x4.Rotate(Quaternion.AngleAxis(angleOfRotation, Vector3.right));
Matrix4x4 translationBackToOrigin = Matrix4x4.Translate(-centerOfRotation);
Matrix4x4 matrix = translationToCenterPoint * rotation * translationBackToOrigin;
destinationVertices[vertexIndex + 0] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 0]);
destinationVertices[vertexIndex + 1] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 1]);
destinationVertices[vertexIndex + 2] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 2]);
destinationVertices[vertexIndex + 3] = matrix.MultiplyPoint3x4(destinationVertices[vertexIndex + 3]);
destinationVertices[vertexIndex + 0] += offset;
destinationVertices[vertexIndex + 1] += offset;
destinationVertices[vertexIndex + 2] += offset;
destinationVertices[vertexIndex + 3] += offset;
}
...
The complete Unity project can be found at my github.