rp_11001/assets/Game/scripts/game/BigWinUI.ts
TJH f466306084
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 1m19s
代码整理
2025-12-22 16:17:40 +08:00

480 lines
17 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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[] = [];
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;
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.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)
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)
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)
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.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;
}
}