import { _decorator, Component, Node, Prefab, sp, Sprite, UITransform, Vec3, v3, EventTarget, Label, tween, UIOpacity, instantiate, SpriteFrame, Tween } from 'cc'; import { ICON_STATE, ICON_WIDTH } from './Define'; import { GameDataManager } from 'db://assets/Loading/scripts/manager/GameDataManager'; import { NodePoolManager } from 'db://assets/Loading/scripts/manager/NodePoolManager'; import { SlotGame } from '../SlotGame'; import { AudioManager } from 'db://assets/Loading/scripts/manager/AudioManager'; const { ccclass, property } = _decorator; // 声明一个全局事件总线 export const IconEventBus = new EventTarget(); // 高度映射表 - 减少重复计算 let HEIGHT_MAP = { 1: 174, 2: 174 * 2, 3: 174 * 3, 4: 174 * 4 }; let BTN_HEIGHT_MAP = { 1: 180, 2: 180 * 2, 3: 180 * 3, 4: 180 * 4 }; // 静态共享的Vec3对象 - 减少GC压力 let SHARED_VEC3 = v3(0, 0, 0); @ccclass('Icon') export class Icon extends Component { // /** Icon的资源 */ @property(sp.Skeleton) iconSpine: sp.Skeleton = null; @property(Node) bgNode: Node = null; // 倍数图片 @property([SpriteFrame]) multiSprite: Array = new Array // 模糊倍数图片 @property([SpriteFrame]) multiBlurSprite: Array = new Array //倍数框 @property([SpriteFrame]) multiFrameSprite: Array = new Array //模糊倍数框 @property([SpriteFrame]) multiBlurFrameSprite: Array = new Array // @property(Sprite) // blurFrame: Sprite = null; @property(Prefab) winSpinePrefab: Prefab = null; // 节点引用 private _normalNode: Node = null; private _fastNode: Node = null; private _btn: Node = null; // private _frameNode: Node = null; // private _fastFrameNode: Node = null; private _normalSpriteNode: Node = null; private _fastSpriteNode: Node = null; // 组件缓存 - 提高性能 private _transform: UITransform = null; // private _frameTransform: UITransform = null; private _bgTransform: UITransform = null; // private _fastFrameTransform: UITransform = null; private _btnTransform: UITransform = null; // 基础属性 private _iconId: number = 99; private _lheight: number = 1; // 图标的高度倍数,默认1*1 private _state = ICON_STATE.ACTIVATE; private _iconKey: string = ''; // private _frameType: number = 0; private _rollerIndex: number = 0; private _multi: number = 0; // 缓存的向量对象,避免重复创建 private readonly _position = new Vec3(); // 组件状态标志 private _isInitialized: boolean = false; private _isFastMode: boolean = false; private _isWildOrScatter: boolean = false; private _isMulti: boolean = false; // 动画相关 private _iconChangeCallback: Function = null; private _changeSprite: Sprite = null; // 用于切换动画的新Sprite // getter/setter set index(id: number) { this._iconId = id; this._isWildOrScatter = id === 0 || id === 1; this._isMulti = id == 2; } get index(): number { return this._iconId; } set lHeight(height: number) { this._lheight = height; } get lHeight(): number { return this._lheight; } set iconKey(key: string) { this._iconKey = key; } get iconKey(): string { return this._iconKey; } set rollerIndex(index: number) { this._rollerIndex = index; } get rollerIndex(): number { return this._rollerIndex; } get startPos(): number { // 检查是否有有效的图标key if (!this._iconKey || this._iconKey.length === 0) { return 0; } const parts = this._iconKey.split('_'); return parseInt(parts[1]); } // set frameType(type: number) { // if (this._frameType === type) return; // 避免重复设置 // this._frameType = type; // this.updateFrames(); // } /** * 获取icon框类型 * @returns 0:普通框 1:银框 2:金框 3:百搭框 */ // get frameType(): number { // return this._frameType; // } // 生命周期:组件加载时 onLoad() { // 缓存常用组件引用 this._transform = this.node.getComponent(UITransform) || this.node.addComponent(UITransform); this.initializeComponents(); } onIconClick() { IconEventBus.emit('ICON_CLICKED', this); } /** * 获取图标的世界坐标 * @returns 图标在世界空间中的位置 */ getWorldPosition(): Vec3 { // 获取当前图标的世界坐标 if (this._transform) { // 使用缓存的向量对象来减少内存分配 return this._transform.convertToWorldSpaceAR(v3(0, 0, 0)); } return null; } // 生命周期:组件启用时 onEnable() { if (!this._isInitialized) { this.initializeComponents(); } } // 更新框架精灵 // updateFrames() { // if (!this.Frame || !this.blurFrame) return; // const manager = GameDataManager.instance; // let frameName, blurFrameName; // switch (this._frameType) { // case 0: // frameName = 'fr01_IronFrame'; // blurFrameName = 'fr01_IronFrame_blur'; // break; // case 1: // frameName = 'fr02_SilverFrame'; // blurFrameName = 'fr02_SilverFrame_blur'; // break; // case 2: // frameName = 'fr03_GoldFrame'; // blurFrameName = 'fr03_GoldFrame_blur'; // break; // default: // frameName = 'fr01_IronFrame'; // blurFrameName = 'fr01_IronFrame_blur'; // } // this.Frame.spriteFrame = manager.getFrameTypeCache(frameName); // this.blurFrame.spriteFrame = manager.getFrameTypeCache(blurFrameName); // } // 初始化所有组件引用 private initializeComponents() { if (this._isInitialized) return; // 获取节点引用 this._normalNode = this.node.getChildByName('normal'); if (this._normalNode) { this._normalSpriteNode = this._normalNode.getChildByName('sprite'); // this._frameNode = this._normalNode.getChildByName('frame'); // 缓存组件 // if (this._frameNode) { // this._frameTransform = this._frameNode.getComponent(UITransform); // } } //适配 // this._normalSpriteNode.setScale(0.9, 0.9, 1) // this._normalNode.getComponent(UITransform).setContentSize(170, 174) this._btn = this.node.getChildByName('btn'); if (this._btn) { this._btnTransform = this._btn.getComponent(UITransform); this._btn.on(Node.EventType.TOUCH_END, this.onIconClick, this); } this._fastNode = this.node.getChildByName('fast'); this._fastSpriteNode = this._fastNode.getChildByName('sp_fast'); // if (this._fastNode) { // this._fastFrameNode = this._fastNode.getChildByName('frame'); // // 缓存组件 // if (this._fastFrameNode) { // this._fastFrameTransform = this._fastFrameNode.getComponent(UITransform); // } // } // 缓存背景节点组件 if (this.bgNode) { this._bgTransform = this.bgNode.getComponent(UITransform); } // 设置初始状态 if (this._normalNode) this._normalNode.active = true; // if (this._frameNode) this._frameNode.active = true; if (this._normalSpriteNode) this._normalSpriteNode.active = true; if (this._fastNode) this._fastNode.active = false; // if (this._fastFrameNode) this._fastFrameNode.active = false; this._isInitialized = true; } // 初始化图标 initIcon(id: number, lHeight: number = 1, IconKey: string = '', frameType: number = 0, rollerIndex: number = 0, multi: number = 0) { // 确保组件已初始化 if (!this._isInitialized) { this.initializeComponents(); } // 设置基本属性 this.index = id; this.lHeight = lHeight; this.iconKey = IconKey; // this.frameType = frameType; this.rollerIndex = rollerIndex; // 设置尺寸 if (this._transform) { this._transform.width = ICON_WIDTH; this._transform.height = HEIGHT_MAP[lHeight] || HEIGHT_MAP[1]; } else { this.node.getComponent(UITransform).width = ICON_WIDTH; this.updateHeightForLheight(lHeight, this.node); } // 批量更新子节点尺寸 let height = HEIGHT_MAP[lHeight] || HEIGHT_MAP[1]; // 使用缓存的UITransform组件 if (this._bgTransform) this._bgTransform.height = height; else this.updateHeightForLheight(lHeight, this.bgNode); // if (this._frameTransform) this._frameTransform.height = height; // else this.updateHeightForLheight(lHeight, this._frameNode); // if (this._fastFrameTransform) this._fastFrameTransform.height = height; // else this.updateHeightForLheight(lHeight, this._fastFrameNode); if (this._btnTransform) { this._btnTransform.height = BTN_HEIGHT_MAP[lHeight] || BTN_HEIGHT_MAP[1]; this._btnTransform.width = ICON_WIDTH; } else { if (!this._btn) return; let transform = this._btn.getComponent(UITransform); if (!transform) return; // 使用映射表而不是多个if判断 transform.height = BTN_HEIGHT_MAP[lHeight] || BTN_HEIGHT_MAP[1]; transform.width = ICON_WIDTH; } if (id == 2 && multi > 1) { this._multi = multi this._normalSpriteNode.getComponent(Sprite).spriteFrame = this.multiSprite[multi] this._fastSpriteNode.getComponent(Sprite).spriteFrame = this.multiBlurSprite[multi] Tween.stopAllByTarget(this._normalSpriteNode) let loopTween = tween(this._normalSpriteNode) .to(0.5, { scale: new Vec3(1.1, 1.1, 1) }) .to(0.5, { scale: new Vec3(1, 1, 1) }) tween(this._normalSpriteNode) .repeatForever(loopTween) .start() switch (true) { case multi < 4: this._normalNode.children[0].active = true this._normalNode.children[1].active = false this._normalNode.children[2].active = false break case multi >= 7: this._normalNode.children[0].active = false this._normalNode.children[1].active = false this._normalNode.children[2].active = true break default: this._normalNode.children[0].active = false this._normalNode.children[1].active = true this._normalNode.children[2].active = false break } } // 重置状态 this.resetState(); } // 重置状态 private resetState() { this._isFastMode = false; this.node.active = true; // 批量设置节点状态 if (this._normalNode) this._normalNode.active = true; if (this._fastNode) this._fastNode.active = false; // 根据图标类型设置显示 if (this._isWildOrScatter) { if (this.iconSpine && this.iconSpine.node) this.iconSpine.node.active = true; if (this._normalSpriteNode) this._normalSpriteNode.active = false; } else { if (this.iconSpine && this.iconSpine.node) this.iconSpine.node.active = false; if (this._normalSpriteNode) this._normalSpriteNode.active = true; } if (this._isMulti) { if (this.iconSpine && this.iconSpine.node) this.iconSpine.node.active = true; if (this._normalSpriteNode) this._normalSpriteNode.active = true; } this._state = ICON_STATE.IDLE; if (!this._isMulti) return this._normalSpriteNode.getComponent(UIOpacity).opacity = 255 } updateHeightForLheight(lheight: number, node: Node) { if (!node) return; let transform = node.getComponent(UITransform); if (!transform) return; // 使用映射表而不是多个if判断 transform.height = HEIGHT_MAP[lheight] || HEIGHT_MAP[1]; } // 更新位置 setPosition(x: number, y: number, z: number = 0) { this._position.set(x, y, z); this.node.setPosition(this._position); } // 更新缩放 setScale(x: number, y: number, z: number = 1) { this.node.setScale(x, y, z); } // 改变图标状态 changeIconState(iconState: ICON_STATE) { if (this._state === iconState) return; // 避免重复设置状态 switch (iconState) { case ICON_STATE.ACTIVATE: this.node.active = true; break; case ICON_STATE.IDLE: this.showFastIcon(false); break; case ICON_STATE.ROTATE: // 可以添加旋转相关逻辑 break; case ICON_STATE.FAST: this.showFastIcon(true); break; case ICON_STATE.WIN: this.showFastIcon(false); if (this._isMulti) { break } if (this._isWildOrScatter) { if (this.iconSpine && this.iconSpine.node) { this.iconSpine.node.active = true; this._normalSpriteNode && (this._normalSpriteNode.active = false); this.iconSpine.clearTracks(); this.iconSpine.setCompleteListener(null); if (this._iconId == 0) { this.iconSpine.setAnimation(0, 'win', false); } else if (this._iconId == 1) { this.iconSpine.setAnimation(0, 'win_1', false); } } } else if (this.iconSpine && this.iconSpine.node) { // this.iconSpine.node.active = true; // this._normalSpriteNode && (this._normalSpriteNode.active = false); // this.iconSpine.clearTracks(); // this.iconSpine.setCompleteListener(null); // this.iconSpine.setAnimation(0, 'win', false); } if (this.iconSpine) { this.iconSpine.setCompleteListener(() => { this.iconSpine.setCompleteListener(null); if (this._isWildOrScatter) { if (this._iconId == 0) { this.iconSpine.setAnimation(0, 'idle', true); } else if (this._iconId == 1) { this.iconSpine.setAnimation(0, 'idle_1', true); } } else { this.iconSpine.clearTracks(); this.iconSpine.node.active = false; this._normalSpriteNode && (this._normalSpriteNode.active = true); } }); } break; case ICON_STATE.HIDE: this.node.active = false; break; } this._state = iconState; } playSpawnAni() { if (!this.iconSpine || !this.iconSpine.node || this._isMulti) return; if (this._isWildOrScatter) { this.iconSpine.node.active = true; this._normalSpriteNode && (this._normalSpriteNode.active = false); } else if (this._isMulti) { this.iconSpine.node.active = true; this._normalSpriteNode && (this._normalSpriteNode.active = true); } else { this.iconSpine.node.active = false; this._normalSpriteNode && (this._normalSpriteNode.active = true); } this.iconSpine.clearTracks(); // 使用计时器回调而不是匿名函数,减少闭包 this.playSpawnAnimation() } playNormalMultiMove(XnInfo) { if (this._iconId != 2) return if (XnInfo.AddN == 0) { return } let slotGame = this.node.parent.parent.parent.parent.parent.parent this._normalSpriteNode.getComponent(UIOpacity).opacity = 150 Tween.stopAllByTarget(this._normalSpriteNode) let multiMoveNode = instantiate(slotGame.getChildByName('multiMove')) let bigMultiNode = slotGame.parent.getChildByName('showMulti') let bigMultiLabel = bigMultiNode.getChildByName('multi') let isFreeSpin = slotGame.getComponent(SlotGame).isInfreeSpin let isHasScore = XnInfo.Win != "" let multiMovePos = -550 if (isFreeSpin && !isHasScore) { multiMovePos = -400 } multiMoveNode.parent = slotGame multiMoveNode.setWorldPosition(this.node.getWorldPosition()) multiMoveNode.getComponent(Sprite).spriteFrame = this.multiSprite[this._multi] AudioManager.instance.playSFX('Multi_show'); tween(multiMoveNode) .delay(0.3) .to(1, { scale: new Vec3(1.2, 1.2, 1) }) .start() tween(multiMoveNode.getComponent(UIOpacity)) .delay(0.3) .to(1, { opacity: 80 }) .start() tween(multiMoveNode) .to(0.3, { scale: new Vec3(1.5, 1.5, 1) }) .to(1, { position: new Vec3(0, 200, 0) }) .call(() => { multiMoveNode.destroy() AudioManager.instance.playSFX('Multi_merge'); if (bigMultiNode.active) return bigMultiLabel.getComponent(Label).string = 'x' + XnInfo.NowN bigMultiNode.active = true bigMultiNode.getComponent(sp.Skeleton).setAnimation(0, 'animation', false) tween(bigMultiLabel.getComponent(UIOpacity)) .to(0.3, { opacity: 255 }) .delay(0.7) .to(0.2, { opacity: 0 }) .start() tween(bigMultiLabel) .to(0.3, { scale: new Vec3(0.24, 0.24, 1) }) .to(0.3, { scale: new Vec3(0.2, 0.2, 1) }) .to(0.4, { position: new Vec3(0, multiMovePos, 0) }) .to(0.2, { scale: new Vec3(0.3, 0.3, 1) }) .call(() => { bigMultiLabel.setPosition(0, 100, 0) bigMultiLabel.setScale(0.2, 0.2, 1) bigMultiNode.active = false }) .start() }) .start() } hideNormalSprite() { if (this._normalSpriteNode) this._normalSpriteNode.active = false; if (this._fastNode) this._fastNode.active = false; } hideNormalSpine() { if (this.iconSpine) this.iconSpine.node.active = false; } private playSpawnAnimation() { if (!this.iconSpine) return; if (this._isWildOrScatter) { // this.iconSpine.setAnimation(0, 'spawn_1', false); // this.iconSpine.setCompleteListener(() => { // this.iconSpine.node.active = true; if (!this.iconSpine) return; if (this._iconId == 0) { this.iconSpine.setAnimation(0, 'idle', true); } else if (this._iconId == 1) { this.iconSpine.setAnimation(0, 'idle_1', true); } this.iconSpine.setCompleteListener(null); // }); } else { // this.iconSpine.setAnimation(0, "spawn", false); } } // 显示/隐藏快速图标 showFastIcon(show: boolean) { if (this._isFastMode === show) return; // 避免重复设置 this._isFastMode = show; // 批量设置节点状态 if (this._normalNode) this._normalNode.active = !show; if (this._fastNode) this._fastNode.active = show; if (!show && !this._isWildOrScatter) { if (this._isWildOrScatter && this.iconSpine) { this.iconSpine.node.active = true; this._normalSpriteNode && (this._normalSpriteNode.active = false); this.iconSpine.clearTracks(); this.iconSpine.setCompleteListener(null); if (this._iconId == 0) { this.iconSpine.setAnimation(0, 'idle', false); } else if (this._iconId == 1) { this.iconSpine.setAnimation(0, 'idle_1', false); } } else if (this.iconSpine) { this.iconSpine.node.active = false; this.iconSpine.clearTracks(); this.iconSpine.setCompleteListener(null); this._normalSpriteNode && (this._normalSpriteNode.active = true); } } } // 播放获胜动画 playWinAni(show: boolean) { this.changeIconState(show ? ICON_STATE.WIN : ICON_STATE.IDLE); } // 1.2s playDeleteAni() { // 从对象池获取或重用winSpine节点 // let winSpine = NodePoolManager.instance.getNodeFromPoolStatic('winSpine', this.winSpinePrefab); let winSpine = instantiate(this.winSpinePrefab) winSpine.setParent(this.node); winSpine.setPosition(0, 0, 0); winSpine.setScale(1, 1, 1); let ascendWin = winSpine.getChildByName('ascend_win'); ascendWin.active = true; let skeleton = ascendWin.getComponent(sp.Skeleton); skeleton.setAnimation(0, `anim${this.lHeight}`, false); this.schedule(() => { skeleton.setCompleteListener(null); skeleton.clearTracks() ascendWin.active = false; // 隐藏所有子节点 let children = winSpine.children; for (let i = 0; i < children.length; i++) { children[i].active = false; } winSpine.removeFromParent(); // NodePoolManager.instance.putNodeToPool('winSpine', winSpine); }, 1.2) // skeleton.setCompleteListener(() => { // skeleton.setCompleteListener(null); // skeleton.clearTracks() // ascendWin.active = false; // // 隐藏所有子节点 // let children = winSpine.children; // for (let i = 0; i < children.length; i++) { // children[i].active = false; // } // winSpine.removeFromParent(); // // NodePoolManager.instance.putNodeToPool('winSpine', winSpine); // }) } // playChangeAni(isChange: boolean) { // if (isChange) { // let winSpine = NodePoolManager.instance.getNodeFromPoolStatic('winSpine', this.winSpinePrefab); // winSpine.setParent(this.node); // winSpine.setPosition(0, 0, 0); // winSpine.setScale(1, 1, 1); // let ascendWin = winSpine.getChildByName('ascend_win'); // let skeleton = ascendWin.getComponent(sp.Skeleton); // ascendWin.active = true; // skeleton.setAnimation(0, `anim${this.lHeight}`, false); // skeleton.setCompleteListener(() => { // skeleton.setCompleteListener(null); // skeleton.clearTracks() // ascendWin.active = false; // this.playChangeSprite(true); // }) // } else { // // 清理winSpine节点 // let winSpine = this.node.getChildByName('winSpine'); // if (winSpine) { // // 停用所有子节点 // let children = winSpine.children; // for (let i = 0; i < children.length; i++) { // children[i].active = false; // } // // 回收节点 // winSpine.removeFromParent(); // NodePoolManager.instance.putNodeToPool('winSpine', winSpine); // } // // 停止精灵切换动画 // this.playChangeSprite(false); // } // } // playChangeSprite(isChange: boolean) { // // 先清理之前的回调 // if (this._iconChangeCallback) { // this.unschedule(this._iconChangeCallback); // this._iconChangeCallback = null; // } // if (isChange) { // // 隐藏原始节点 // if (this._normalSpriteNode) { // this._normalSpriteNode.active = false; // } // // 复用现有changeNode或创建新的 // let changeNode = this.node.getChildByName('ChangeSprite'); // if (!changeNode) { // changeNode = new Node('ChangeSprite'); // changeNode.setParent(this.node); // } // if (this._normalSpriteNode) { // changeNode.setPosition(this._normalSpriteNode.position); // changeNode.setScale(this._normalSpriteNode.scale); // } // // 获取或添加Sprite组件 // this._changeSprite = changeNode.getComponent(Sprite) || changeNode.addComponent(Sprite); // // 复制原始Sprite的属性 // if (this._normalSpriteNode) { // let originalSprite = this._normalSpriteNode.getComponent(Sprite); // if (originalSprite && originalSprite.spriteFrame) { // this._changeSprite.spriteFrame = originalSprite.spriteFrame; // this._changeSprite.sizeMode = originalSprite.sizeMode; // this._changeSprite.trim = originalSprite.trim; // } // } // this._iconChangeCallback = this.updateChangeSpriteFrame; // this.schedule(this._iconChangeCallback, 0.1); // } else { // // 停止动画并清理 // if (this._iconChangeCallback) { // this.unschedule(this._iconChangeCallback); // this._iconChangeCallback = null; // } // // 移除切换动画节点 // if (this._changeSprite && this._changeSprite.node) { // this._changeSprite.node.destroy(); // this._changeSprite = null; // } // } // } // updateChangeSpriteFrame = () => { // if (this._changeSprite) { // this._changeSprite.spriteFrame = GameDataManager.instance.getRandomSymbol(); // } // } // 获取精灵帧 getSkeData(): sp.SkeletonData { return this.iconSpine ? this.iconSpine.skeletonData : null; } // 生命周期:组件禁用时 onDisable() { // 移除切换动画节点 if (this._changeSprite && this._changeSprite.node) { this._changeSprite.node.destroy(); this._changeSprite = null; } } protected onDestroy(): void { this.node.off(Node.EventType.TOUCH_END, this.onIconClick, this); } }