538 lines
16 KiB
TypeScript
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;
|
|
}
|
|
|
|
}
|
|
|