import { _decorator, Component, Node, Vec3, tween, find, Sprite, Color, Tween } from 'cc'; const { ccclass, property } = _decorator; /** * SkillButtonAnimator * 负责技能按钮的缩放 / 移动动画和星星闪烁效果。 * 提供 playShrink 接口供外部调用。 */ @ccclass('SkillButtonAnimator') export class SkillButtonAnimator extends Component { @property({ type: [Node], tooltip: '星星节点数组 (xx-1 到 xx-5)' }) starNodes: Node[] = []; private _origScale: Vec3 = new Vec3(); private _origPos: Vec3 = new Vec3(); private _blinkTween: Tween | null = null; private _blinkTweenTarget: Node | null = null; private _origStarScale: Vec3 | null = null; // 星星颜色配置 private readonly STAR_ACTIVE_COLOR = new Color(255, 255, 255, 255); // 亮起的星星 private readonly STAR_INACTIVE_COLOR = new Color(58, 37, 37, 255); // 未亮起的星星 (3A2525) onLoad() { // 记录初始位置、缩放,用于恢复 this._origScale.set(this.node.scale); this._origPos.set(this.node.position); } /** * 设置技能等级并更新星星显示 * @param currentLevel 当前等级 (0-5) */ public setSkillLevel(currentLevel: number) { // 停止之前的闪烁动画 this.stopBlinkAnimation(); // 更新星星显示 this.starNodes.forEach((starNode, index) => { const sprite = starNode.getComponent(Sprite); if (sprite) { if (index < currentLevel) { // 已获得等级的星星 - 常亮 sprite.color = this.STAR_ACTIVE_COLOR; } else if (index === currentLevel && currentLevel < 5) { // 下一等级的星星 - 设置为未亮起状态,稍后开始闪烁 sprite.color = this.STAR_INACTIVE_COLOR; } else { // 剩余星星 - 不亮 sprite.color = this.STAR_INACTIVE_COLOR; } } }); // 如果当前等级小于最大等级,开始闪烁下一颗星星(即将获得的等级) if (currentLevel < 5) { this.startBlinkAnimation(currentLevel); } } /** * 开始星星闪烁动画 * @param nextStarIndex 下一颗要闪烁的星星索引 (0-4) */ private startBlinkAnimation(nextStarIndex: number) { if (nextStarIndex >= this.starNodes.length) return; const nextStar = this.starNodes[nextStarIndex]; const sprite = nextStar.getComponent(Sprite); if (!sprite) return; // 直接使用补间动画控制星星缩放闪烁(不依赖组件) if (this._blinkTween) { this._blinkTween.stop(); this._blinkTween = null; } const origScale = nextStar.scale.clone(); const targetScale = new Vec3(origScale.x * 1.3, origScale.y * 1.3, origScale.z); this._blinkTweenTarget = nextStar; this._origStarScale = origScale.clone(); this._blinkTween = tween(nextStar) .to(0.15, { scale: targetScale }, { easing: 'sineOut' }) .to(0.15, { scale: origScale }, { easing: 'sineIn' }) .union() .repeatForever() .start(); } /** * 停止星星闪烁动画 */ private stopBlinkAnimation() { if (this._blinkTween) { this._blinkTween.stop(); this._blinkTween = null; } // 恢复被闪烁星星的原始缩放 if (this._blinkTweenTarget && this._blinkTweenTarget.isValid && this._origStarScale) { this._blinkTweenTarget.setScale(this._origStarScale); } this._blinkTweenTarget = null; this._origStarScale = null; } /** * 播放缩小并(可选)移动到指定目标位置的动画。 * @param duration 动画时长(秒) * @param targetPos 目标位置(节点本地坐标系),不传则保持原位置 * @param onComplete 完成回调 */ public playShrink(duration: number = 0.3, targetPos?: Vec3, onComplete?: () => void) { // 停止闪烁动画 this.stopBlinkAnimation(); // 若目标位置存在,则先 tween 到该位置;否则只缩放 const props: any = { scale: new Vec3(0, 0, 0) }; if (targetPos) { props.position = targetPos; } tween(this.node) .to(duration, props, { easing: 'quadIn' }) .call(() => { // 动画结束后隐藏节点,但允许后续 resetState 恢复 this.node.active = false; if (onComplete) onComplete(); }) .start(); this.node.setPosition(this._origPos); } public resetState() { // 停止闪烁动画 this.stopBlinkAnimation(); // Reset scale, position, opacity, etc. as needed this.node.setScale(Vec3.ONE); this.node.active = true; this.node.setPosition(this._origPos); // 重置星星显示为0级状态 this.setSkillLevel(0); } onDestroy() { // 清理闪烁动画 this.stopBlinkAnimation(); } } export default SkillButtonAnimator;