rp_11009/assets/Game/Scripts/RollerManager.ts
2026-04-10 10:40:03 +08:00

558 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, 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;
// 帧到启动ID映射按帧序
let frameOrder = [
{ frame: 1, ids: [0] },
{ frame: 5, ids: [1] },
{ frame: 8, ids: [2] },
{ frame: 11, ids: [3] },
{ frame: 14, ids: [4] },
{ frame: 17, ids: [5] },
];
let fps = 30;
@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 isWild = stopData.indexOf(0) !== -1;
let isScatter = stopData.indexOf(1) !== -1;
if (!this._isFreeSpin && !this._isManualStop && !this._isFastSpin) {
if (isWild && !isScatter) {
AudioManager.instance.playSFX('Appear_Wild_Sound');
}
if (isScatter) {
AudioManager.instance.playSFX('Appear_Scatter_Sound');
}
if (!isWild && !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(1) !== -1;
let hasWild = this._parsedData.PanData.indexOf(0) !== -1;
if (hasWild && !hasScatter) {
AudioManager.instance.playSFX('Appear_Wild_Sound');
}
if (hasScatter) {
AudioManager.instance.playSFX('Appear_Scatter_Sound');
}
if (!hasWild && !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 {
frameOrder.forEach(({ frame, ids }) => {
let delay = Math.max(0, (frame - 1) / fps);
ids.forEach(id => {
let roller = this.allRollers[id];
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 {
// 普通模式:从左到右依次掉落,每列间隔 0.12s
for (let i = 0; i < this.allRollers.length; i++) {
const colDelay = i * 0.12;
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;
}
}