import { _decorator, AudioClip, AudioSource, Component, easing, Label, Node, NodePool, ParticleSystem, Prefab, sp, Sprite, SpriteFrame, Tween, tween, v3 } from 'cc'; import { WIN_TYPE } from './Define'; import { NodePoolManager } from '../../../Loading/scripts/manager/NodePoolManager'; import { gold2cash } from '../../../Loading/scripts/comm'; import { I18nManager } from '../../../Loading/scripts/manager/I18nManager'; import { AudioManager } from '../../../Loading/scripts/manager/AudioManager'; const { ccclass, property } = _decorator; @ccclass('BigWinUI') export class BigWinUI extends Component { @property(Prefab) bigWinUiPre: Prefab = null; @property(AudioSource) bigWinAudio: AudioSource = null; @property([AudioClip]) bigWinAudioClips: AudioClip[] = []; @property([SpriteFrame]) bigWinBgs: SpriteFrame[] = []; bigWinUINode: Node = null; winScore: number = 0; // 最终赢分 winType: WIN_TYPE = WIN_TYPE.BIG_WIN; // 最终赢分类型 endImageIndex: number = 0; // 最终的结果 currentScore: number = 0; // 初始赢分 isScrolling: boolean = true; // 分数是否在滚动 isAnimationFinished: boolean = false; // 动画和数字滚动是否完成 scoreLabel: Label | null = null; // 分数节点 endTime: number = 5; // 动画完成后回收的时间 scrollTime: number = 7; multis: number[] = [35, 50]; // 倍数区间 betAmount: number = 100000; dynamicTargets: number[] = []; onCloseCallBack: (() => void) | null = null; bigwinMainSpine: sp.Skeleton | null = null; megawinMainSpine: sp.Skeleton | null = null; supermegawinMainSpine: sp.Skeleton | null = null; bigwinLabelSprite: Sprite | null = null; megawinLabelSprite: Sprite | null = null; supermegawinLabelSprite: Sprite | null = null; bgSprite: Sprite | null = null; currentWinType: WIN_TYPE = WIN_TYPE.BIG_WIN; // 当前播放的动画类型 //当前正在播的动画 currentSpin = this.bigwinMainSpine // 添加一个标记来区分是否是点击跳过 isSkipByTouch: boolean = false; show(winScore: number, winType: WIN_TYPE, betAmount: number) { this.bigWinUINode = NodePoolManager.instance.getNodeFromPoolStatic('bigWinUI', this.bigWinUiPre); this.scoreLabel = this.bigWinUINode.getChildByName('score').getComponent(Label); this.bigwinMainSpine = this.bigWinUINode.getChildByName('bigwinMain').getComponent(sp.Skeleton); this.megawinMainSpine = this.bigWinUINode.getChildByName('megawinMain').getComponent(sp.Skeleton); this.supermegawinMainSpine = this.bigWinUINode.getChildByName('supermegawinMain').getComponent(sp.Skeleton); this.bigwinLabelSprite = this.bigWinUINode.getChildByName('bigwinLabel').getComponent(Sprite); this.megawinLabelSprite = this.bigWinUINode.getChildByName('megawinLabel').getComponent(Sprite); this.supermegawinLabelSprite = this.bigWinUINode.getChildByName('supermegawinLabel').getComponent(Sprite); this.bgSprite = this.bigWinUINode.getChildByName('bg').getComponent(Sprite); this.resetState(); this.winScore = winScore; this.winType = winType; this.betAmount = betAmount; this.endImageIndex = this.winType - 3; this.currentWinType = WIN_TYPE.BIG_WIN; // test this.scoreLabel.string = '0'; this.calculateDynamicTargets(); this.bigWinUINode.on(Node.EventType.TOUCH_START, this.onTouch, this); this.node.addChild(this.bigWinUINode); this.playSpineByType(WIN_TYPE.BIG_WIN, 'ruchang'); this.startScoreAni(); } calculateDynamicTargets() { this.dynamicTargets = []; // 根据实际获得的 winType 来决定需要播放哪些阶段 switch (this.winType) { case WIN_TYPE.SUPER_MEGA_WIN: this.dynamicTargets.push(this.betAmount * 35); // BIG_WIN 阈值 this.dynamicTargets.push(this.betAmount * 50); // MEGA_WIN 阈值 this.dynamicTargets.push(this.winScore); break; case WIN_TYPE.MEGA_WIN: this.dynamicTargets.push(this.betAmount * 35); // BIG_WIN 阈值 this.dynamicTargets.push(this.winScore); break; case WIN_TYPE.BIG_WIN: this.dynamicTargets.push(this.winScore); break; } } resetState() { this.currentScore = 0; this.isScrolling = true; this.isSkipByTouch = false; this.isAnimationFinished = false; this.imageIndex = 0; this.currentWinType = WIN_TYPE.BIG_WIN; this.scoreLabel.node.scale = v3(1, 1, 1); Tween.stopAllByTarget(this.scoreLabel.node); } imageIndex: number = 0; startScoreAni() { if (this.dynamicTargets.length === 0) return; let targetScore = this.dynamicTargets.shift()!; // 修改这里的滚动逻辑 let startScore = this.currentScore; let startTime = 0; this.isScrolling = true; let updateScore = function (dt: number) { if (!this.isScrolling) return; startTime += dt; let progress = Math.min(startTime / this.scrollTime, 1); let easedProgress = this.easeOutQuad(progress); this.currentScore = startScore + (targetScore - startScore) * easedProgress; this.checkAndPlaySpineAnim(this.currentScore); this.updateScoreLabel(); if (progress >= 1) { this.currentScore = targetScore; // 确保最终数值精确 this.updateScoreLabel(); this.unschedule(updateScore); if (this.dynamicTargets.length > 0) { this.imageIndex++; this.startScoreAni(); } else { this.endAni(); } } }.bind(this); this.schedule(updateScore, 0.01); } // 添加缓动函数 easeOutQuad(t: number): number { return t * (2 - t); } checkAndPlaySpineAnim(score: number) { let newWinType = this.getWinTypeByScore(score); if (newWinType !== this.currentWinType) { this.currentWinType = newWinType; this.playSpineByType(this.currentWinType, 'ruchang'); } } showcurrentSpin() { this.bigwinMainSpine.node.active = false this.megawinMainSpine.node.active = false this.supermegawinMainSpine.node.active = false this.currentSpin.node.active = true } async playSpineByType(winType: WIN_TYPE, state: 'ruchang' | 'chixu' | 'jieshu') { if (!this.bigwinMainSpine) return; if (!this.bigwinLabelSprite) return; let prefix = ''; switch (winType) { case WIN_TYPE.SUPER_MEGA_WIN: prefix = 'super'; this.currentSpin = this.supermegawinMainSpine this.showcurrentSpin() break; case WIN_TYPE.MEGA_WIN: prefix = 'mega'; this.currentSpin = this.megawinMainSpine this.showcurrentSpin() break; default: prefix = 'big'; this.currentSpin = this.bigwinMainSpine this.showcurrentSpin() break; } const animName = `${state}`; if (state === 'ruchang') { if (!this.isSkipByTouch) { // 停止当前音效 this.bigWinAudio.stop(); // 根据类型切换音效 switch (winType) { case WIN_TYPE.SUPER_MEGA_WIN: this.bigWinAudio.clip = this.bigWinAudioClips[2]; break; case WIN_TYPE.MEGA_WIN: this.bigWinAudio.clip = this.bigWinAudioClips[1]; break; case WIN_TYPE.BIG_WIN: this.bigWinAudio.clip = this.bigWinAudioClips[0]; break; } // 播放新音效 if (!AudioManager.instance.getMuted()) { this.bigWinAudio.play(); } } this.currentSpin.setCompleteListener(() => { this.playSpineByType(winType, 'chixu'); }); this.currentSpin.setAnimation(0, animName, false); this.playWinLabelAnimation(prefix, state) // 显示对应类型的特效 // this.showEffectByType(winType); } else if (state === 'chixu') { this.currentSpin.setCompleteListener(null); this.currentSpin.setAnimation(0, animName, true); this.playWinLabelAnimation(prefix, state) } else { this.currentSpin.setCompleteListener(null); this.currentSpin.setAnimation(0, animName, false); this.playWinLabelAnimation(prefix, state) } } getWinTypeByScore(score: number): WIN_TYPE { // 根据分数判断属于哪个区间 if (score >= this.betAmount * 50) { return WIN_TYPE.SUPER_MEGA_WIN; } else if (score >= this.betAmount * 35) { return WIN_TYPE.MEGA_WIN; } else { return WIN_TYPE.BIG_WIN; } } playWinLabelAnimation(prefix, state: string) { if (state == 'ruchang') { switch (prefix) { case 'big': Tween.stopAllByTag(100) this.megawinLabelSprite.node.setScale(0, 0, 1) this.supermegawinLabelSprite.node.setScale(0, 0, 1) this.bgSprite.spriteFrame = this.bigWinBgs[0] tween(this.bigwinLabelSprite.node) .tag(100) .to(0.5, { scale: v3(1.2, 1.2, 1) }) .to(0.2, { scale: v3(1, 1, 1) }) .start() break case 'mega': Tween.stopAllByTag(100) this.bigwinLabelSprite.node.setScale(0, 0, 1) this.supermegawinLabelSprite.node.setScale(0, 0, 1) this.bgSprite.spriteFrame = this.bigWinBgs[1] tween(this.megawinLabelSprite.node) .tag(100) .to(0.5, { scale: v3(1.2, 1.2, 1) }) .to(0.2, { scale: v3(1, 1, 1) }) .start() break case 'super': Tween.stopAllByTag(100) this.megawinLabelSprite.node.setScale(0, 0, 1) this.bigwinLabelSprite.node.setScale(0, 0, 1) this.bgSprite.spriteFrame = this.bigWinBgs[2] tween(this.supermegawinLabelSprite.node) .tag(100) .to(0.5, { scale: v3(1.2, 1.2, 1) }) .to(0.2, { scale: v3(1, 1, 1) }) .start() break } } else if (state == 'chixu') { switch (prefix) { case 'big': Tween.stopAllByTag(100) let bigWinTween = tween(this.bigwinLabelSprite.node) .to(0.5, { scale: v3(1.1, 1.1, 1) }) .to(0.5, { scale: v3(1, 1, 1) }) tween(this.bigwinLabelSprite.node) .tag(100) .repeatForever(bigWinTween) .start() break case 'mega': Tween.stopAllByTag(100) let megaWinTween = tween(this.megawinLabelSprite.node) .to(0.5, { scale: v3(1.1, 1.1, 1) }) .to(0.5, { scale: v3(1, 1, 1) }) tween(this.megawinLabelSprite.node) .tag(100) .repeatForever(megaWinTween) .start() break case 'super': Tween.stopAllByTag(100) let superMegaWinTween = tween(this.supermegawinLabelSprite.node) .to(0.5, { scale: v3(1.1, 1.1, 1) }) .to(0.5, { scale: v3(1, 1, 1) }) tween(this.supermegawinLabelSprite.node) .tag(100) .repeatForever(superMegaWinTween) .start() break } } else { switch (prefix) { case 'big': Tween.stopAllByTag(100) tween(this.bigwinLabelSprite.node) .tag(100) .to(0.5, { scale: v3(1.3, 1.3, 1) }) .to(0.5, { scale: v3(0, 0, 1) }) .start() break case 'mega': Tween.stopAllByTag(100) tween(this.megawinLabelSprite.node) .tag(100) .to(0.5, { scale: v3(1.3, 1.3, 1) }) .to(0.5, { scale: v3(0, 0, 1) }) .start() break case 'super': Tween.stopAllByTag(100) tween(this.supermegawinLabelSprite.node) .tag(100) .to(0.5, { scale: v3(1.3, 1.3, 1) }) .to(0.5, { scale: v3(0, 0, 1) }) .start() break } } } updateScoreLabel() { if (this.scoreLabel) this.scoreLabel.string = gold2cash(this.currentScore); } async onTouch() { if (!this.bigWinUINode) return; // 添加节点存在检查 if (this.isScrolling) { this.isSkipByTouch = true; // 如果当前index已经是最终index,就不需要重复播放 if (this.imageIndex === this.endImageIndex) { this.isScrolling = false; this.unscheduleAllCallbacks(); this.currentScore = this.winScore; this.updateScoreLabel(); this.bigWinAudio.stop(); this.bigWinAudio.clip = this.bigWinAudioClips[3]; if (!AudioManager.instance.getMuted()) { this.bigWinAudio.play(); } this.endAni(); return; } // 立即完成当前动画 this.isScrolling = false; this.unscheduleAllCallbacks(); // 直接设置为最终分数 this.currentScore = this.winScore; this.updateScoreLabel(); // 直接播放最终类型的start动画,完成后自动切换到loop this.playSpineByType(this.winType, 'ruchang'); // 直接切换到最终特效 // this.showEffectByType(this.winType); this.bigWinAudio.stop(); this.bigWinAudio.clip = this.bigWinAudioClips[3]; if (!AudioManager.instance.getMuted()) { this.bigWinAudio.play(); } this.endAni(); } else if (this.isAnimationFinished) { this.unscheduleAllCallbacks(); // 取消自动关闭定时器 this.autoClose(); // 复用自动关闭逻辑 } } endAni() { this.isScrolling = false; let scoreNode = this.scoreLabel.node; // 只有在非点击跳过的情况下才播放结算音效 if (!this.isSkipByTouch && this.imageIndex === this.endImageIndex) { this.bigWinAudio.stop(); this.bigWinAudio.clip = this.bigWinAudioClips[3]; if (!AudioManager.instance.getMuted()) { this.bigWinAudio.play(); } } tween(scoreNode) .to(0.25, { scale: v3(1.3, 1.3, 1.3) }) .to(0.25, { scale: v3(1, 1, 1) }) .call(() => { this.isAnimationFinished = true; // 在动画完成时启动5秒倒计时 this.scheduleOnce(this.autoClose.bind(this), 5); }) .start(); } private autoClose() { if (this.isAnimationFinished) { // 确保还没被点击关闭 this.isAnimationFinished = false; this.bigWinAudio.stop(); Tween.stopAllByTarget(this.scoreLabel.node); tween(this.scoreLabel.node) .to(0.2, { scale: v3(1.3, 1.3, 1.3) }) .to(0.3, { scale: v3(0, 0, 0) }) .start(); this.playSpineByType(this.winType, 'jieshu'); this.currentSpin.setCompleteListener(() => { this.closeImmediately(); }); } } closeImmediately() { if (this.onCloseCallBack) { this.onCloseCallBack(); } this.unscheduleAllCallbacks(); // 清理spine监听器 if (this.bigwinMainSpine) { this.bigwinMainSpine.setCompleteListener(null); } if (this.megawinMainSpine) { this.megawinMainSpine.setCompleteListener(null); } if (this.supermegawinMainSpine) { this.supermegawinMainSpine.setCompleteListener(null); } this.bigWinUINode.off(Node.EventType.TOUCH_START, this.onTouch, this); this.hide(); } hide() { NodePoolManager.instance.putNodeToPool('bigWinUI', this.bigWinUINode); this.bigWinUINode = null; } public setCloseCallBack(call: () => void) { this.onCloseCallBack = call; } }