import { _decorator, Component, Node, Label, Sprite, RichText, tween, Vec3 } from 'cc'; const { ccclass, property } = _decorator; @ccclass('DialogueBox') export class DialogueBox extends Component { @property(Label) nameLabel: Label; @property(RichText) textRichText: RichText; @property(Sprite) nameBg: Sprite; @property(Node) continueIndicator: Node; private currentText: string = ''; private currentSpeaker: string = ''; private typingInterval: number = null; private onCompleteCallback: () => void = null; private typingSpeed: number = 30; // 毫秒每个字符 onLoad() { this.nameBg = this.nameLabel.node.parent.getComponent(Sprite); } start() { // 默认隐藏 this.node.active = false; } /** * 显示对话 */ show(speaker: string | undefined, text: string, onComplete?: () => void) { this.node.active = true; this.currentText = text; this.currentSpeaker = speaker || ''; this.onCompleteCallback = onComplete || null; // 设置角色名 if (this.currentSpeaker) { this.nameLabel.string = this.currentSpeaker; this.nameBg.node.active = true; } else { this.nameBg.node.active = false; } // 隐藏继续提示 if (this.continueIndicator) { this.continueIndicator.active = false; } // 开始打字机效果 this.typewriterEffect(text); } /** * 打字机效果 */ private typewriterEffect(text: string) { // 清除之前的定时器 if (this.typingInterval) { clearInterval(this.typingInterval); } let index = 0; this.textRichText.string = ''; this.typingInterval = window.setInterval(() => { if (index < text.length) { // 使用 RichText 来支持富文本 this.textRichText.string = this.escapeXml(text.substring(0, index + 1)); index++; } else { this.finishTyping(); } }, this.typingSpeed); } /** * 完成打字(立即显示完整文本) */ finishTyping() { if (this.typingInterval) { clearInterval(this.typingInterval); this.typingInterval = null; } this.textRichText.string = this.escapeXml(this.currentText); // 显示继续提示 if (this.continueIndicator) { this.continueIndicator.active = true; this.playContinueIndicatorAnim(); } // 回调 if (this.onCompleteCallback) { this.onCompleteCallback(); } } /** * 播放继续提示动画 */ private playContinueIndicatorAnim() { if (!this.continueIndicator) return; // 简单的上下浮动动画 tween(this.continueIndicator) .repeatForever( tween() .to(0.5, { position: new Vec3(0, 10, 0) }) .to(0.5, { position: new Vec3(0, 0, 0) }) ) .start(); } /** * 隐藏对话框 */ hide() { this.node.active = false; if (this.typingInterval) { clearInterval(this.typingInterval); this.typingInterval = null; } } /** * 重置 */ reset() { this.nameLabel.string = ''; this.textRichText.string = ''; this.nameBg.node.active = false; if (this.continueIndicator) { this.continueIndicator.active = false; } } /** * 转义 XML 特殊字符(用于 RichText) */ private escapeXml(text: string): string { return text .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } /** * 设置打字速度 */ setTypingSpeed(speed: number) { this.typingSpeed = speed; } /** * 获取当前说话者 */ getCurrentSpeaker(): string { return this.currentSpeaker; } /** * 获取当前文本 */ getCurrentText(): string { return this.currentText; } }