import { _decorator, CCFloat, CCInteger, CCString, Component, game, Label, Node, randomRangeInt, RealCurve, sp, Sprite, } from 'cc'; import GachaBase from '../Base/GachaBase'; import SpineAnimationHandler from '../Base/SpineAnimationHandler'; import GachaManager, { RewardConfig } from '../Manager/GachaManager'; const { ccclass, property } = _decorator; class RewardCard { public reward: RewardConfig; constructor(reward: RewardConfig) { this.reward = reward; } } @ccclass('RewardDisplay') class RewardDisplay { @property(Sprite) private sprite: Sprite; @property(Label) private label: Label; public setReward(reward: RewardConfig) { this.sprite.spriteFrame = reward.icon; this.label.string = 'x' + reward.quantity; } } @ccclass('LuckyWheel') export default class LuckyWheel extends GachaBase { @property(SpineAnimationHandler) private animationHandler: SpineAnimationHandler; @property(Node) private spineRoot: Node; @property(CCString) private wheelBoneName: string = ''; @property(CCInteger) private speed: number = 1; @property(RealCurve) private spinCurve: RealCurve = new RealCurve(); @property(RewardDisplay) private rewardDisplay: RewardDisplay[] = []; @property(CCFloat) private offsetAngle: number; private _wheel: sp.spine.Bone; private _targetAngle: number = 0; private _spinning: boolean = false; private _timer: number = 0; private _timeSpin: number = 0; private _maxAngle: number = 0; private _allCards: RewardCard[]; private _random: number; protected onLoad(): void { this._wheel = this.animationHandler.findBone(this.wheelBoneName); } protected onEnable(): void { this._random = null; this.spineRoot.setActive(false); this._wheel.rotation = 0; this._wheel.update(); this._spinning = false; } protected update(): void { if (this._spinning) { this._timer += game.deltaTime * this.speed; const angle = this._maxAngle * this.spinCurve.evaluate(this._timer / this._timeSpin); this._wheel.rotation = this._targetAngle + angle; this._wheel.update(); if (this._timer >= this._timeSpin) { this._spinning = false; GachaManager.instance.showFloatingText( this._allCards[this._random].reward.quantity.toString(), this.node.worldPosition, this._allCards[this._random].reward.icon, ); GachaManager.instance.setReward(this._allCards[this._random].reward.id); } } } private setReward() { this._allCards = this.rewardDisplay.map((card, i) => { let rw = GachaManager.instance.rewards[i]; card.setReward(rw); return new RewardCard(rw); }); } public async show(): Promise { this.setReward(); this.spineRoot.setActive(true); await this.animationHandler.setAnimationAsync('appear'); this.animationHandler.addAnimation('idle', { loop: true }); } public async spin() { if (this._spinning) return; this._spinning = true; this._random = this._allCards.getRandomIndex(); this.animationHandler.clearTrack(0); this._targetAngle = -(360 / this.rewardDisplay.length) * this._random + this.offsetAngle; this._timer = 0; this._timeSpin = randomRangeInt(10, 15); this._maxAngle = 360 * this._timeSpin; } }