版本:2.4.4
一 功能需求
游戏中有剧情对话时会用到打字机效果
功能需求
1 对话字符串需要逐字显示,那么就得用计时器来获取字符进行显示。
2 关键字需要高亮显示,所以要用到富文本cc.RichText。
3 需要主动换行,在字符串里加入 \n 就可以换行了,不需要额外处理。
4 点击屏幕空白处,文字会一次性全部显示出来,让急性子玩家快速过剧情。
5 打字结束后需要监听结束事件,以便处理其它事情。
二 打字机实现
1. 用cc.director.getScheduler做计时器,逐字显示。
2. 富文本只支持一层<color></color>,不能嵌套<color><color></color></color>。chatAt来检查当前字符是否是标签开头"<",如果是则跳过显示标签收尾">"的后一个文字。
3. finishNow()让文字一次性全部显示出来。
4. isFinish()可以检查文字打印效果是否完成。
5. 继承cc.EventTarget,这样class PringEffect才能派发和监听事件,监听PrintEffect.FINISH事件可以在打字结束后处理其它事件。
PrintEffect.ts
const { ccclass, property } = cc._decorator; /** * 打字机效果 * @author chenkai 2022.8.31 */ @ccclass export default class PrintEffect extends cc.EventTarget { /**打字效果播放完成 */ public static FINISH: string = "PrintEffect_FINISH"; /**消息文本 cc.Label或cc.RichText*/ private msgLab: any; /**需要显示的消息,支持一层richText <color=#ffffffff>xxx</color> */ private msg: string; /**当前显示的消息字符串位置 */ private curMsgIndex: number; /**打字机效果是否已播放完成 */ private bFinish: boolean = false; /**文字显示速度 单位s */ private textSpeed: number = 0.05; /**是否需要增加</color>符号 */ private bNeedFlag: boolean = false; /** * 播放打字机效果 * @param msgLab 消息文本 cc.Label或cc.RichText * @param msg 消息 支持一层richText <color=#ffffffff>xxx</color> * @param textSpeed 打印速度 */ public play(msgLab: any, msg: string, textSpeed: number = 0.05) { this.bFinish = false; this.bNeedFlag = false; this.msgLab = msgLab; this.msg = msg; this.curMsgIndex = 0; this.msgLab.string = ""; this.textSpeed = textSpeed; let sch = cc.director.getScheduler(); sch.enableForTarget(this); sch.schedule(this.onSchedule, this, this.textSpeed); } /**定时处理 */ private onSchedule() { //如果是"<"标签开头,将curMsgIndex移动到<>标签的后一位。 if (this.msg.charAt(this.curMsgIndex) == "<") { //如果bNeedFlag=false不需要增加符号,则表示当前是开头标签<>,将bNeedFlag取反为true,后面的文字需要增加符号<>。 //如果bNeedFlag=true需要增加符号,则表示当前是收尾标签<>,将bNeedFlag取反为false,后面的文字不需要增加符号<>。 this.bNeedFlag = !this.bNeedFlag; for (let i = this.curMsgIndex; i < this.msg.length; i++) { //显示位置移动1位 this.curMsgIndex++; //检查是否是">",如果是,则将标签移动1位,显示标签">"后的文字 if (this.msg.charAt(this.curMsgIndex) == ">") { this.curMsgIndex++; break; } } } //显示字符串 this.curMsgIndex++; if (this.bNeedFlag) { this.msgLab.string = this.msg.substr(0, this.curMsgIndex) + "</color>"; } else { this.msgLab.string = this.msg.substr(0, this.curMsgIndex); } //结束 if (this.curMsgIndex >= this.msg.length) { let sch = cc.director.getScheduler(); sch.unschedule(this.onSchedule, this); this.bFinish = true; this.emit(PrintEffect.FINISH); } } /** * 检查是否打印动画播放完成 * @returns true完成 false未完成 */ public isFinish() { return this.bFinish; } /**立即结束,并显示全部消息 */ public finishNow() { let sch = cc.director.getScheduler(); sch.enableForTarget(this); sch.unschedule(this.onSchedule, this); this.msgLab && (this.msgLab.string = this.msg); this.bFinish = true; this.emit(PrintEffect.FINISH); } /**停止并清理文本 */ public clear() { let sch = cc.director.getScheduler(); sch.enableForTarget(this); sch.unschedule(this.onSchedule, this); this.msgLab && (this.msgLab.string = ""); this.bFinish = true; } }
三 使用打字机
MainScene.ts:
const { ccclass, property } = cc._decorator; /** * 打字机效果 * @author chenkai 2022.8.31 */ @ccclass export default class PrintEffectDemo extends cc.Component { @property({ type: cc.RichText, tooltip: "消息文本" }) msgLab: cc.RichText = null; onLoad() { let str = "打字机效果<color=#0fffff>打字机效果打字机</color>打字机效果打字机效果\n打字机效果<color=#0fffff>打字机效果打字机</color>效果打字机效果打字机效果\n打字机效果"; let printEffect: PrintEffect = new PrintEffect(); //清理打印效果 printEffect.clear(); //检查是否打印完成 console.log("是否打印完成:", printEffect.isFinish()); //监听打印完成事件 printEffect.on(PrintEffect.FINISH, () => { console.log("监听到打印完成事件"); }, this); //点击屏幕,立即结束打印效果 this.node.on(cc.Node.EventType.TOUCH_END, () => { printEffect.finishNow(); }, this); //开始打印 printEffect.play(this.msgLab, str, 0.2); } }
显示效果