本方案仅供参考
从需求出发
游戏类型:微信小游戏
帧数限定:60
已知的几种方案:
1:场上只存在一个mesh,每帧把所有字绘制到一个mesh。
优点:每帧都重绘,高度定制化,可以随意添加、删除。
缺点:每帧重绘速度慢、且会导致大量GC(字体的texture会很离谱的产生大量gc,并且无解(绝了))
NGUI中如何减少CacheFontForText耗时_font cachefontfortext-CSDN博客
且不支持动画系统的动效。
2:单纯使用对象池,网上很多这种,但是这种跟没说一样,对象池有用我还用找其他的?
3:场上存在多个mesh,每次把前5帧的字统计起来(使用队列),统一绘制到一张mesh上。如果游戏锁定帧数为60帧,在使用对象池的情况下,每秒最多有13个mesh生成。这个经过测试是完全可以容忍的(100个mesh每个mesh100个字,能跑120帧)。
优点:不需要每帧重绘,只需要每隔一段时间检查一下是否有新的飘字即可。而且动效只需要在
缺点:分类比较难搞。不支持行为种类过多的飘字(每一个类需要的mesh两就会多一组(13个),超过60个不如普通对象池)。3种以内。依赖对象池。
3多个mesh的方式:
这个性能更好,支持15000个飘字同屏飘,100帧以上。
说白了就是把同一帧、同一类的字绘制在同一个mesh上,然后用同一个动画管理。
上代码:
using UnityEngine;
[RequireComponent(typeof(CanvasRenderer))]
public class UGUIFloatingTextBatch : MonoBehaviour
{
public Font font; // 字体
public Material fontMaterial; // 字体的材质
public Color color = Color.white; // 文本颜色
public float floatSpeed = 50f; // 基础飘动速度
public float fadeDuration = 10f; // 淡出时长
public int numberOfTexts = 1000; // 生成的文本数量
public int currentNum = 1;
private Mesh mesh;
private CanvasRenderer canvasRenderer;
private float timer = 0;
private string helloText = "Hello";
// 每个字符的独立行为
private Vector3[] positions;
private Color[] colors;
private float[] alphas; // 用于控制每个字符的透明度
int totalCharacters ;
Vector3[] vertices ; // 每个字符4个顶点
Vector2[] uvs ;
int[] triangles; // 每个字符2个三角形
Color[] meshColors ;
Vector3 org;
void Start()
{
org = transform.position;
// 为每个 "Hello" 生成网格信息
totalCharacters = helloText.Length * numberOfTexts;
vertices = new Vector3[totalCharacters * 4]; // 每个字符4个顶点
uvs = new Vector2[vertices.Length];
triangles = new int[totalCharacters * 6]; // 每个字符2个三角形
meshColors = new Color[vertices.Length];
// 初始化位置和颜色数据
positions = new Vector3[numberOfTexts];
colors = new Color[numberOfTexts];
alphas = new float[numberOfTexts];
for (int i = 0; i < numberOfTexts; i++)
{
// 随机初始位置
positions[i] = new Vector3(Random.Range(-500, 500), Random.Range(-300, 300), 0);
colors[i] = color; // 初始化颜色为全白
alphas[i] = 1f; // 初始透明度为1(不透明)
}
// 获取CanvasRenderer组件
canvasRenderer = GetComponent<CanvasRenderer>();
// 生成初始的字体网格
GenerateMesh();
// 设置材质:如果没有指定字体材质,使用字体自带的默认材质
if (fontMaterial != null)
{
canvasRenderer.SetMaterial(fontMaterial, null);
}
else
{
fontMaterial = font.material;
canvasRenderer.SetMaterial(fontMaterial, null);
}
}
void Update()
{
transform.position+= Vector3.up * floatSpeed * Time.deltaTime ;
timer += Time.deltaTime;
如果时间超过淡出时长,销毁物体
if (timer >= fadeDuration)
{
transform.position = org;
timer= 0;
}
if (Input.GetMouseButtonDown(0)) // 0 代表鼠标左键
{
Debug.Log("重绘");
GenerateMesh();
}
}
//重绘
void GenerateMesh()
{
if (mesh == null)
{
mesh = new Mesh();
}
float xOffset = 0f;
int vertexOffset = 0;
int triangleOffset = 0;
for (int i = 0; i < currentNum; i++)
{
// 为每个 "Hello" 设置网格
Vector3 startPosition = positions[i];
for (int j = 0; j < helloText.Length; j++)
{
char c = helloText[j];
font.RequestCharactersInTexture(c.ToString(), font.fontSize, FontStyle.Normal);
font.GetCharacterInfo(c, out CharacterInfo characterInfo, font.fontSize);
// 设置每个字符的顶点
float xMin = startPosition.x + xOffset + characterInfo.minX;
float xMax = startPosition.x + xOffset + characterInfo.maxX;
float yMin = startPosition.y + characterInfo.minY;
float yMax = startPosition.y + characterInfo.maxY;
vertices[vertexOffset] = new Vector3(xMin, yMin, 0);
vertices[vertexOffset + 1] = new Vector3(xMin, yMax, 0);
vertices[vertexOffset + 2] = new Vector3(xMax, yMax, 0);
vertices[vertexOffset + 3] = new Vector3(xMax, yMin, 0);
// 设置UV坐标
uvs[vertexOffset] = characterInfo.uvBottomLeft;
uvs[vertexOffset + 1] = characterInfo.uvTopLeft;
uvs[vertexOffset + 2] = characterInfo.uvTopRight;
uvs[vertexOffset + 3] = characterInfo.uvBottomRight;
// 设置初始颜色
meshColors[vertexOffset] = colors[i];
meshColors[vertexOffset + 1] = colors[i];
meshColors[vertexOffset + 2] = colors[i];
meshColors[vertexOffset + 3] = colors[i];
// 设置三角形
triangles[triangleOffset] = vertexOffset;
triangles[triangleOffset + 1] = vertexOffset + 1;
triangles[triangleOffset + 2] = vertexOffset + 2;
triangles[triangleOffset + 3] = vertexOffset;
triangles[triangleOffset + 4] = vertexOffset + 2;
triangles[triangleOffset + 5] = vertexOffset + 3;
vertexOffset += 4;
triangleOffset += 6;
xOffset += characterInfo.advance; // 下一个字符的X偏移量
}
// 重置 xOffset,开始下一组 "Hello"
xOffset = 0f;
}
// 将生成的顶点、UV坐标、三角形和颜色赋值给网格
mesh.vertices = vertices;
mesh.uv = uvs;
mesh.triangles = triangles;
mesh.colors = meshColors;
// 使用CanvasRenderer将网格设置为UI元素
canvasRenderer.SetMesh(mesh);
}
//刷新,暂时不用
void UpdateMesh()
{
Vector3[] vertices = mesh.vertices;
Color[] meshColors = mesh.colors;
float xOffset = 0f;
int vertexOffset = 0;
for (int i = 0; i < numberOfTexts; i++)
{
Vector3 startPosition = positions[i];
for (int j = 0; j < helloText.Length; j++)
{
font.GetCharacterInfo(helloText[j], out CharacterInfo characterInfo, font.fontSize);
float xMin = startPosition.x + xOffset + characterInfo.minX;
float xMax = startPosition.x + xOffset + characterInfo.maxX;
float yMin = startPosition.y + characterInfo.minY;
float yMax = startPosition.y + characterInfo.maxY;
vertices[vertexOffset] = new Vector3(xMin, yMin, 0);
vertices[vertexOffset + 1] = new Vector3(xMin, yMax, 0);
vertices[vertexOffset + 2] = new Vector3(xMax, yMax, 0);
vertices[vertexOffset + 3] = new Vector3(xMax, yMin, 0);
// 更新颜色
meshColors[vertexOffset] = colors[i];
meshColors[vertexOffset + 1] = colors[i];
meshColors[vertexOffset + 2] = colors[i];
meshColors[vertexOffset + 3] = colors[i];
vertexOffset += 4;
xOffset += characterInfo.advance;
}
// 重置 xOffset
xOffset = 0f;
}
// 更新网格的顶点和颜色
mesh.vertices = vertices;
mesh.colors = meshColors;
// 更新CanvasRenderer
canvasRenderer.SetMesh(mesh);
}
}
这么配置,然后创建很多个mesh就行
然后绘制就ok。
缺点:不支持每个字单独飘。每个mesh行为统一。
就给个思路。有什么问题留言讨论下,作者本人也比较菜,多多指正。
随便改变大小