123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- 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();
- }
- }
|