import { _decorator, Component, Node, Label, tween, Vec3, UIOpacity, Tween } from 'cc'; import { Tips } from './Tips'; const { ccclass, property } = _decorator; @ccclass('TipItem') export class TipItem extends Component { @property(Label) contentLabel: Label = null!; private isInUse: boolean = false; onLoad() { // 查找子节点中的Label组件 if (!this.contentLabel) { const contentNode = this.node.getChildByName('contentLabel'); if (contentNode) { this.contentLabel = contentNode.getComponent(Label); } } } /** * 初始化提示项 */ public init(content: string, startPos: Vec3): void { this.isInUse = true; // 设置文字内容 if (this.contentLabel) { this.contentLabel.string = content; } // 设置初始位置和透明度 this.node.setPosition(startPos); this.node.active = true; // 重置透明度 const uiOpacity = this.node.getComponent(UIOpacity); if (uiOpacity) { uiOpacity.opacity = 255; } // 重置缩放 this.node.setScale(Vec3.ONE); // 开始动画 this.playAnimation(); } /** * 播放飘字动画 */ private playAnimation(): void { const duration = 2.0; // 总动画时长 const moveDistance = 100; // 向上移动距离 // 获取当前位置 const startPos = this.node.getPosition(); const endPos = new Vec3(startPos.x, startPos.y + moveDistance, startPos.z); // 确保节点有UIOpacity组件 let uiOpacity = this.node.getComponent(UIOpacity); if (!uiOpacity) { uiOpacity = this.node.addComponent(UIOpacity); } // 创建动画序列 tween(this.node) .parallel( // 位置动画:向上移动 tween().to(duration, { position: endPos }, { easing: 'quartOut' }), // 缩放动画:先放大再缩小 tween().delay(duration * 0.1).to(duration * 0.3, { scale: new Vec3(1.1, 1.1, 1) }).to(duration * 0.6, { scale: new Vec3(0.9, 0.9, 1) }), // 透明度渐变 tween().delay(duration * 0.5).call(() => { if (uiOpacity && uiOpacity.isValid) { tween(uiOpacity) .to(duration * 0.5, { opacity: 0 }) .start(); } }) ) .call(() => { // 动画结束,回收到对象池 this.recycle(); }) .start(); } /** * 回收到对象池 */ private recycle(): void { this.isInUse = false; this.node.active = false; // 停止所有相关的tween动画 Tween.stopAllByTarget(this.node); // 重置节点状态,确保下次复用时状态正确 // 注意:不重置位置,因为新的位置会在init时设置 this.node.setScale(Vec3.ONE); // 重置透明度 const uiOpacity = this.node.getComponent(UIOpacity); if (uiOpacity) { Tween.stopAllByTarget(uiOpacity); uiOpacity.opacity = 255; } // 清空文字内容 if (this.contentLabel) { this.contentLabel.string = ''; } Tips.ins.recycleTipItem(this.node); } /** * 检查是否正在使用 */ public getIsInUse(): boolean { return this.isInUse; } /** * 强制停止动画并回收 */ public forceRecycle(): void { Tween.stopAllByTarget(this.node); this.recycle(); } }