All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 1m19s
480 lines
17 KiB
TypeScript
480 lines
17 KiB
TypeScript
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;
|
||
}
|
||
}
|
||
|