Text文本打字效果,TextMeshPro可以对应参考,差距不大,改改参数名就能用。改脚本原本被我集成到其他的程序集中,现在已经分离。
效果
实现功能
1.能够设置每行能够容纳的字数和允许的冗余
2.打字效果
3.每行打完上移
4.开头进入,结束弹出
5.行居中
脚本使用
属性 | 解释 |
---|---|
TypingSpeed | 打字速度(.s 每过多少时间打一个) |
RowShowMax | 一行显示的最大值 |
AllowRedundancy | 每行能够允许的冗余 |
IsUpdateText | 更新文本,默认不启动,勾选点击运行就更新 |
Text | 挂载text文本 |
OffsetY | 对每行上移的补偿 |
SaveMarqueeoriginPosition | 保存字幕整体的初始位置 |
TextCloseDelayTime | 字幕消失的时间(Obsolete) |
BottomShow | 需要挂载下方显示的整体 |
函数 | 功能 |
---|---|
UpdateText | 更新文本,需要再Update中调用 |
OnFinish | 更新完成,更新文本完成后调用的函数 |
OnTextUpdate(string) | 文本更新,在打字过程中如果发生文本更新需要调用的方法 |
OnTextReset | 文本重置 |
设置
** 1.物体设置 **
** 2.text文本设置 **
1.需要文字的size(如果有外描边的话)来计算字占据的行宽,来决定每行上移的距离
2.文本每行居中,但定格显示
代码
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;
namespace YBZ {
public class TypewriterEffect : MonoBehaviour
{
// 测试文本
private readonly string text_test = "SVN中我需要维护的东西Scene; Scripts/Engine/WSC SteamingAsset/2DPivots.json Editor/WSCPivotEditor.cs \n 下方提示";
[Header("文本显示"), Space(10)]
public float typingSpeed = 0.2f; // 打字速度
public int rowShowMax = 25; // 一行最大显示数量
public int allowRedundancy = 6; // 允许的冗余数量
public bool isUpdateText = false; // 是否播放
public Text text; // 底部字幕
[Range(-25, 25), Space(5)]
public int offsetY = -3; // 第一行Y轴补偿
public Vector3 saveMarqueeOriginPostion = new Vector3(0, -63, 0); // 下方字幕的原初位置
private float textTimeCount = 0; // 更新用的计时器
private string word = ""; //保存字幕
private int currentPos = 0; // 打字字符索引
private int LineBreakCount = 0; // 换行符计数
private Vector3 saveTextLocatePostion; // 用于保存TextUI位置
private bool isOriginPosition = true;
void Update() {
UpdateText();
if (Input.GetMouseButtonDown(0)) {
OnTextUpdate(text_test);
}
}
// 文本更新
private void UpdateText() {
if (!isUpdateText) {
return;
}
// 检查字幕是否位于原初位置
if (isOriginPosition) {
isOriginPosition = !isOriginPosition;
BottomShow.transform.DOLocalMove(Vector3.zero, 1.0f);
}
BottomShow.SetActive(true);
if (saveTextLocatePostion == Vector3.zero) {
saveTextLocatePostion = text.rectTransform.localPosition;
}
if (word == "") {
word = text.text;
}
textTimeCount += Time.deltaTime;
if (textTimeCount > typingSpeed) {
textTimeCount = 0;
currentPos++;
if (currentPos >= word.Length) {
Debug.Log("播放完成");
OnFinish();
return;
}
text.text = word[..currentPos];//刷新文本显示内容
if (word[currentPos - 1] == '\n') {
Debug.Log("发现换行符");
LineBreakCount++;
// 每次遇到一个换行符就上移25个单位
if (LineBreakCount == 1) {
text.rectTransform.DOLocalMoveY(text.rectTransform.localPosition.y + 25 + offsetY, 1f);
} else if (LineBreakCount != 1) {
text.rectTransform.DOLocalMoveY(text.rectTransform.localPosition.y + 25, 1f);
}
}
// 每次处理行超限
int lineCount;
if (LineBreakCount == 0) {
lineCount = text.text.Length;
} else {
lineCount = text.text[text.text.LastIndexOf('\n')..].Length;
}
// 行超限
if (lineCount > rowShowMax + allowRedundancy) {
word = text.text + '\n' + word[text.text.Length..];
}
}
}
[Header("下方显示延迟消失的所需要的时间")]
public float textCloseDelayTime = 2.0f;
/// <summary>
/// 下方提示游戏物体,在使用前预加载
/// </summary>
public GameObject BottomShow;
public IEnumerator IE_TextCloseDelayTime(float time) {
yield return new WaitForSeconds(time);
BottomShow.SetActive(false);
Debug.Log("下方显示已关闭");
}
public IEnumerator IE_OnTextReset(float time) {
yield return new WaitForSeconds(time);
OnTextReset();
Debug.Log("文本恢复默认");
isOriginPosition = true;
BottomShow.transform.DOLocalMove(saveMarqueeOriginPostion, 1.0f);
}
// 文本更新完成 , 一旦确认关闭就不要再更新文本, 否侧会出现逻辑错误,如若在播放完毕后更新文本一定要在下方显示关闭后, 字幕回滚的时候不能更新文本.
private void OnFinish() {
isUpdateText = false;
// 完成之后下方显示 延迟关闭, 位置回调
// StartCoroutine(IE_TextCloseDelayTime(textCloseDelayTime));
// 延迟文本重置位置
StartCoroutine(IE_OnTextReset(textCloseDelayTime));
text.rectTransform.DOLocalMove(saveTextLocatePostion + new Vector3(0, offsetY, 0), textCloseDelayTime);
}
// 文本更新, 一旦更新就是确定要开始播放(╯‵□′)╯︵┻━┻(你更新不是为了播放?)
private void OnTextUpdate(string newtext) {
text ??= GameObject.Find("字幕文字").gameObject.GetComponent<Text>();
OnTextReset();
word = newtext;
// StartCoroutine(IE_OnTextReset(0.5f));
BottomShow.SetActive(true);
isUpdateText = true;
}
// 文本恢復默认: 索引为0, 换行符统计为0, LocalPostion恢复, 文本置空
private void OnTextReset() {
if (saveTextLocatePostion == Vector3.zero) {
saveTextLocatePostion = text.rectTransform.localPosition;
}
text.rectTransform.localPosition = saveTextLocatePostion;
text.text = "";
LineBreakCount = 0;
currentPos = 0;
}
// 初始化
public void Init() {
Debug.Log("文本更新初始化完成");
}
public void UnInit() {
Debug.Log("文本控制结束");
}
private void OnDestroy() {
UnInit();
}
}
}