相关技术:Text、TextMesh、Rigidbody(刚体)、BoxCollider(碰撞体)、TextGenerator、文本网格、文字网格
原理:使用UGUI Text获取其文字的每个字符网格坐标,转世界坐标生成对应的3D文本(TextMesh)并挂上刚体、碰撞体实现掉落。
UGUI Text直接挂Canvas(World Space) 将它挪到镜头前,然后我是调整它的透明度为0的(不会影响网格生成),并挂载Gravity3DText组件,Gravity3DText组件参数拖拽自身Canvas和一个TextMesh物体预制体(3D文本),运行游戏后点击空格生成3D文本
预制体组件情况:
UGUI Text物体组件情况:
地板物体:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Gravity3DText : MonoBehaviour
{
public Canvas canvas;
public GameObject gravity3DTextPrefab;
private Text textMesh;
private List<GameObject> tempTextList;
public class CharData
{
public Vector3 pos;
public Vector2 size;
}
void Start()
{
tempTextList = new List<GameObject>();
textMesh = GetComponent<Text>();
textMesh.GraphicUpdateComplete();
}
public void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
string textStr = textMesh.text;
int textLength = textStr.Length;
TextGenerator textGenerator = new TextGenerator(textLength);
Vector2 size = textMesh.rectTransform.rect.size;
textGenerator.Populate(textStr, textMesh.GetGenerationSettings(size));
List<UIVertex> vertexList = textGenerator.verts as List<UIVertex>;
List<CharData> charDataList = new List<CharData>();
for (int i = 0; i <= vertexList.Count - 4; i += 4)
{
CharData charData = new CharData();
Vector3 pos1 = vertexList[i].position;
Vector3 pos2 = vertexList[i + 1].position;
Vector3 pos3 = vertexList[i + 2].position;
Vector3 pos4 = vertexList[i + 3].position;
Vector3 pos = (pos1 + pos2 + pos3 + pos4) / 4.0f;
pos /= canvas.scaleFactor;
charData.pos = pos;
Vector3 charMinPos = Vector3.Min(pos1, pos2);
charMinPos = Vector3.Min(charMinPos, pos3);
charMinPos = Vector3.Min(charMinPos, pos4);
Vector3 charMaxPos = Vector3.Max(pos1, pos2);
charMaxPos = Vector3.Max(charMaxPos, pos3);
charMaxPos = Vector3.Max(charMaxPos, pos4);
charData.size = new Vector2(charMaxPos.x - charMinPos.x, charMaxPos.y - charMinPos.y);
charDataList.Add(charData);
}
//统一字体大小
float sameY = transform.localPosition.y;
string trimStr = textStr.Replace(" ", "");
Debug.Log("trimStr:" + trimStr);
int subMeshCount = Mathf.Min(textMesh.text.Length, charDataList.Count);
for (int i = 0; i < subMeshCount; i++)
{
CharData charData = charDataList[i];
Vector3 pos = transform.TransformPoint(charData.pos);
pos.y = sameY;
Debug.Log($"第{i + 1}个字,中心点:{pos}, size:{charData.size}, char:{trimStr[i]}");
GameObject tempTextGo = GameObject.Instantiate(gravity3DTextPrefab);
Transform tempTextTrans = tempTextGo.transform;
tempTextTrans.position = pos;
TextMesh tempTextMesh = tempTextGo.GetComponent<TextMesh>();
tempTextMesh.text = trimStr[i].ToString();
tempTextMesh.fontSize = textMesh.fontSize * 5;
tempTextMesh.characterSize = 10 / 5; //minSize;
tempTextList.Add(tempTextGo);
}
}
}
private void OnDestroy()
{
foreach (var v in tempTextList)
{
GameObject.Destroy(v);
}
tempTextList.Clear();
}
}