rp_11009/assets/Game/Scripts/RollerManager.ts
2026-04-10 11:23:16 +08:00

538 lines
16 KiB
TypeScript

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) {
for (let i = 0; i < this.allRollers.length; i++) {
let roller = this.allRollers[i];
if (roller) {
if (this._isManualStop) return;
roller.startScroll();
}
}
} 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();
}, 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<T>(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;
}
}