import { _decorator, Component, Mask, Node, Sprite, SpriteFrame, UITransform, v3, Vec3 } from 'cc'; import { IconFactory } from './IconFactory'; import { Roller, ROLLER_STATE } from './Roller'; import { ICON_HEIGHT, ICON_WIDTH, IParsedGameData, ROLLER_COMBINE_EVENT, ROLLER_EVENT } from './Define'; import { AudioManager } from '../../Main/Scripts/managers/AudioManager'; let { ccclass, property, executeInEditMode } = _decorator; // 普通模式下各列起转的间隔(秒) let startScrollStagger = 0.08; @ccclass('RollerManager') @executeInEditMode export class RollerManager extends Component { @property({ tooltip: '图标的宽度' }) iconWidth: number = ICON_WIDTH; @property({ tooltip: '图标的高度' }) iconHeight: number = ICON_HEIGHT; @property({ tooltip: '图标之间的水平距离' }) iconHMerge: number = 0; @property({ type: IconFactory, tooltip: '图标工厂' }) iconFactory: IconFactory = null; // @property(SpriteFrame) // maskSpriteFrame: SpriteFrame = null; rollerMsg: any[] = [ // { row: 1, col: 4, isHorizontal: true }, { id: 0, row: 5, col: 1, isHorizontal: false }, { id: 1, row: 5, col: 1, isHorizontal: false }, { id: 2, row: 5, col: 1, isHorizontal: false }, { id: 3, row: 5, col: 1, isHorizontal: false }, { id: 4, row: 5, col: 1, isHorizontal: false }, { id: 5, row: 5, col: 1, isHorizontal: false }, ]; upLayer: any = null; // 滚轮数组 allRollers: Roller[] = []; // 是否快速旋转 _isFastSpin: boolean = false; // 是否手动停止 _isManualStop: boolean = false; // spinData _parsedData: IParsedGameData = null; /** 分割过的数据,一位数组改为二维数组, 每个元素代表一个滚轮 */ _resultStopData: number[][] = []; // 是否是免费游戏 _isFreeSpin: boolean = false; private _createdRollerCount: number = 0; private _fallenRollerCount: number = 0; private _pendingDeleteCount: number = 0; _scatterStartRollerId: number = 0; @property _format = false; @property({ tooltip: '格式化' }) get format(): boolean { return this._format; } set format(a: boolean) { this._format = a; let maskNode = this.node.getChildByName('mask'); maskNode.removeAllChildren(); // new Node('mask'); // maskNode.addComponent(UITransform); // maskNode.addComponent(Mask); // maskNode.getComponent(Mask).type = 3; // maskNode.getComponent(Mask).alphaThreshold = 0.3; // maskNode.getComponent(Sprite).spriteFrame = this.maskSpriteFrame; // maskNode.getComponent(Mask).inverted = false; maskNode.setPosition(0, 0); // this.node.addChild(maskNode); for (let i = 0; i <= 5; i++) { let rollerId = i; let rollerRow = this.rollerMsg[i].row; let roller = Roller.create(rollerId, rollerRow, this.iconWidth, this.iconHeight, this.iconFactory); maskNode.addChild(roller.node); let rollerPosition = this.getRollerPosition(rollerId); roller.node.setPosition(rollerPosition); // 只在第一次设置format if (!roller.format) { roller.format = true; } this.allRollers.push(roller); } // 按照rollerMsg.id从小到大对allRollers排序 this.allRollers.sort((a, b) => { return a.rollerId - b.rollerId; }); } setUpLayer(upLayer: any) { this.upLayer = upLayer; } // 获取滚轮的坐标 getRollerPosition(id: number): Vec3 { let col = 6; let hMiddle = Math.floor(col / 2); let x = -(col % 2 == 0 ? hMiddle - 0.5 : hMiddle) * (this.iconWidth + this.iconHMerge); let xdis = id * this.iconWidth + id * this.iconHMerge; return v3(x + xdis, 0, 0); } protected onLoad(): void { // this.format = true; this.registerEvent(); this._createdRollerCount = 0; this._fallenRollerCount = 0; } registerEvent() { for (let lx = 0; lx < this.allRollers.length; lx++) { let roller = this.allRollers[lx]; roller.node.on(ROLLER_EVENT.ON_R_ICON_CREATE, this.onRollerRIconCreate, this); roller.node.on(ROLLER_EVENT.LAST_PAGE_CREATE, this.onRollerLastPageCreate, this); roller.node.on(ROLLER_EVENT.ROLLER_BOUNCE, this.onRollerBounce, this); roller.node.on(ROLLER_EVENT.ROLLER_DECELERATE, this.onRollerSlowDown, this); roller.node.on(ROLLER_EVENT.ROLLER_STOP, this.onRollerStop, this); roller.node.on(ROLLER_EVENT.ROLLER_UNIFORM, this.onRollerUniform, this); roller.node.on(ROLLER_EVENT.ICON_DELETED, this.onRollerIconDeleted, this); roller.node.on(ROLLER_EVENT.ICON_CREATE, this.onRollerIconCreate, this); roller.node.on(ROLLER_EVENT.ICON_FALLEN, this.onRollerIconFallen, this); } } setFastSpin(isFastSpin: boolean) { this._isFastSpin = isFastSpin; this.allRollers.forEach(roller => { roller.setFastSpin(isFastSpin); }) } getIsFastSpin(): boolean { return this._isFastSpin; } setIsFreeSpin(isFreeSpin: boolean) { this._isFreeSpin = isFreeSpin; } changeSpeedFast() { // 掉落模式无需调速,保留接口兼容外部调用 } // 随机创建ICON回调 onRollerRIconCreate() { return; } // 最后一页创建的回调 onRollerLastPageCreate(rollerId: number) { } onRollerBounce(rollerId: number) { this.node.emit(ROLLER_COMBINE_EVENT.ROLLER_BOUNCE, rollerId); let stopData = this._resultStopData[rollerId]; let isScatter = stopData.indexOf(0) !== -1; if (!this._isFreeSpin && !this._isManualStop && !this._isFastSpin) { if (isScatter) { AudioManager.instance.playSFX('Appear_Scatter_Sound'); } if (!isScatter) { AudioManager.instance.playSFX('Roller_Down'); } } return; } onRollerSlowDown() { return; } private stopChainRoller(id: number) { let roller = this.allRollers[id]; let stopData = this._resultStopData[id]; AudioManager.instance.playSFX('Ready_Hand_SFX'); roller.setNoBounce(true); roller.stopScroll(stopData, 0); } hasEmitScatterTween: boolean = false; onRollerStop(rollerId: number) { this.node.emit(ROLLER_COMBINE_EVENT.ONE_ROLLER_STOP, rollerId); let allRollerStop = true; for (let i = 0; i < this.allRollers.length; i++) { let roller = this.allRollers[i]; if (roller.isScroll()) allRollerStop = false; } if (allRollerStop) { if (this.hasEmitScatterTween) { this.node.emit(ROLLER_COMBINE_EVENT.START_GAME_END_SCALE_TWEEN); } this.node.emit(ROLLER_COMBINE_EVENT.ALL_ROLLER_STOP); this.hasEmitScatterTween = false; if (this._isFastSpin || this._isManualStop) { let hasScatter = this._parsedData.PanData.indexOf(0) !== -1; if (hasScatter) { AudioManager.instance.playSFX('Appear_Scatter_Sound'); } if (!hasScatter) { AudioManager.instance.playSFX('Roller_Down'); } } } } // 滚轮匀速时候的回调 onRollerUniform() { return; } // 滚轮icon删除的回调 onRollerIconDeleted(rollerId: number) { if (this._pendingDeleteCount > 0) { this._pendingDeleteCount--; if (this._pendingDeleteCount === 0) { this.node.emit(ROLLER_COMBINE_EVENT.ALL_ROLLER_ICONS_DELETED); } } } // 滚轮icon创建的回调 onRollerIconCreate(rollerId: number) { this._createdRollerCount++; if (this._createdRollerCount >= this.allRollers.length) { this._createdRollerCount = 0; this.node.emit(ROLLER_COMBINE_EVENT.ALL_ROLLER_ICONS_CREATED); } } // 滚轮icon掉落的回调 onRollerIconFallen(rollerId: number) { this._fallenRollerCount++; if (this._fallenRollerCount >= this.allRollers.length) { this._fallenRollerCount = 0; this.node.emit(ROLLER_COMBINE_EVENT.ALL_ROLLER_ICONS_FALLEN); } } // 滚轮是否在滚动 isScroll(): boolean { for (let lx = 0; lx < this.allRollers.length; lx++) { let roller = this.allRollers[lx]; if (roller.isScroll()) return true; } return false; } distributeFreeMulMap(freeMulMap: { [pos: number]: number }) { for (let r = 0; r < this.allRollers.length; r++) { let relMap: { [relPos: number]: number } = {}; let base = r * 5; for (let relPos = 0; relPos < 5; relPos++) { let absPos = base + relPos; if (freeMulMap[absPos] != null) { relMap[relPos] = freeMulMap[absPos]; } } this.allRollers[r].setFreeMulMap(relMap); } } // 初始化滚轮数据 initRollerWithIcon(data: IParsedGameData) { this._parsedData = data; let panData = data.PanData; // 分割数据 this._resultStopData = this.splitArray(panData, [5, 5, 5, 5, 5, 5]); this.distributeFreeMulMap(data.FreeMulMap); // 处理n*1符号 for (let i = 0; i < this.allRollers.length; i++) { let roller = this.allRollers[i]; roller.initRollerWithIcon(i, this._resultStopData[i]); } } // 滚轮Icon生成规则 setRollerIconRule(rollerIconRule: number[][]) { for (let i = 0; i < this.allRollers.length; i++) { this.allRollers[i].setRollerIconRule(rollerIconRule[i]); } } getIconNode(pos: number): Node { let lx = this.getLx(pos); let ly = this.getLy(pos); let roller = this.allRollers[lx]; return roller.getIconNode(ly); } getLx(pos: number): number { let currentPos = pos; for (let i = 0; i < this.rollerMsg.length; i++) { let roller = this.rollerMsg[i]; let rollerSize = roller.row * roller.col; if (currentPos < rollerSize) { return i; } currentPos -= rollerSize; } return -1; // 如果位置超出范围,返回-1 } getLy(pos: number): number { let currentPos = pos; // 先找到对应的滚轮 let rollerId = this.getLx(pos); if (rollerId === -1) return -1; // 计算在当前滚轮之前的所有位置数 for (let i = 0; i < rollerId; i++) { let roller = this.rollerMsg[i]; currentPos -= (roller.row * roller.col); } let currentRoller = this.rollerMsg[rollerId]; if (currentRoller.isHorizontal) { // 横向滚轮直接返回列位置 return currentPos; } else { // 纵向滚轮返回行位置 return currentPos % currentRoller.row; } } // 获取第一个可以停止的滚轮id getFirstRollerIndex(): number { return 0; } // 获取下一个可以停止的滚轮id getNextRollerIndex(id: number): number { for (let lx = id + 1; lx < this.allRollers.length; lx++) { return lx; } return -1; } resetInfo() { this.allRollers.forEach(roller => { roller.resetInfo(); }) } getIsManualStop(): boolean { return this._isManualStop; } // 滚轮开始滚动 startScroll() { this._isManualStop = false; this.unscheduleAllCallbacks(); if (this._isFastSpin && !this._isFreeSpin) { for (let i = 0; i < this.allRollers.length; i++) { let roller = this.allRollers[i]; if (roller) { if (this._isManualStop) return; roller.startScroll(true); } } } else { for (let i = 0; i < this.allRollers.length; i++) { let roller = this.allRollers[i]; let delay = i * startScrollStagger; if (roller) { this.scheduleOnce(() => { if (this._isManualStop) return; roller.startScroll(false); }, delay); } } } } // 滚轮停止滚动 stopScroll(data: IParsedGameData) { this._parsedData = data; let panData = data.PanData; this._resultStopData = this.splitArray(panData, [5, 5, 5, 5, 5, 5]); this.distributeFreeMulMap(data.FreeMulMap); if (this._isFastSpin) { // 快速模式:所有列同时掉落 for (let i = 0; i < this.allRollers.length; i++) { const roller = this.allRollers[i]; roller.stopScroll(this._resultStopData[i], 0); } } else { // 普通模式:从左到右依次掉落,每列间隔更紧凑 for (let i = 0; i < this.allRollers.length; i++) { const colDelay = i * 0.09; const roller = this.allRollers[i]; const stopData = this._resultStopData[i]; this.scheduleOnce(() => { if (this._isManualStop) return; roller.stopScroll(stopData, 0); }, colDelay); } } } canManualStop(): boolean { return this.allRollers.every(roller => roller.getState() < ROLLER_STATE.LAST_PAGE_CREATE || roller.getState() == ROLLER_STATE.STOP); } // 对服务器下发的数据进行操作 splitArray(arr: T[], sizes: number[]): T[][] { let result: T[][] = []; let currentIndex = 0; for (let size of sizes) { let subArray = arr.slice(currentIndex, currentIndex + size); result.push(subArray); currentIndex += size; } return result; } getAllRemoveIconsPos(removeData: number[]): number[][] { let group: number[][] = []; for (let i = 0; i < this.allRollers.length; i++) { group[i] = []; } for (let i = 0; i < removeData.length; i++) { let pos = removeData[i]; let lx = this.getLx(pos); group[lx].push(pos); } return group; } deleteIconNode(pos: number) { let lx = this.getLx(pos); let ly = this.getLy(pos); this.allRollers[lx].deleteIconNode([ly]); } createNewIconTop(addtional: any) { this.allRollers.forEach(roller => { roller.createNewIconTop(addtional[roller.rollerId]); }) } iconFallDown() { this.allRollers.forEach(roller => { roller.iconFallDown(); }) } // 获取icon坐标 getIconWorldPosition(pos: number) { let lx = this.getLx(pos); let roller = this.allRollers[lx]; return roller.getIconWorldPosition(this.getLy(pos)); } onDestroy(): void { // 清理事件监听 for (let roller of this.allRollers) { roller.node.off(ROLLER_EVENT.ON_R_ICON_CREATE, this.onRollerRIconCreate, this); roller.node.off(ROLLER_EVENT.LAST_PAGE_CREATE, this.onRollerLastPageCreate, this); roller.node.off(ROLLER_EVENT.ROLLER_BOUNCE, this.onRollerBounce, this); roller.node.off(ROLLER_EVENT.ROLLER_DECELERATE, this.onRollerSlowDown, this); roller.node.off(ROLLER_EVENT.ROLLER_STOP, this.onRollerStop, this); roller.node.off(ROLLER_EVENT.ROLLER_UNIFORM, this.onRollerUniform, this); roller.node.off(ROLLER_EVENT.ICON_DELETED, this.onRollerIconDeleted, this); roller.node.off(ROLLER_EVENT.ICON_CREATE, this.onRollerIconCreate, this); roller.node.off(ROLLER_EVENT.ICON_FALLEN, this.onRollerIconFallen, this); } } // 开始一批删除(声明本轮将有多少次 deleteIconNode 调用) beginDeleteBatch(expected: number) { this._pendingDeleteCount = expected; } getScatterStartRollerId() { let startId = 0; let twoScattterId = this._parsedData.ScatterPos[1]; startId = this.getLx(twoScattterId) + 1; return startId; } hasScatterOnRoller(rollerId: number): boolean { let seg = this._resultStopData[rollerId] || []; return seg.indexOf(1) !== -1; } }