825 lines
25 KiB
TypeScript
825 lines
25 KiB
TypeScript
/**
|
||
* 负责单个滚轮的创建、滚动、停止等逻辑
|
||
*/
|
||
import {
|
||
_decorator,
|
||
Node,
|
||
UITransform,
|
||
Vec2,
|
||
v2,
|
||
Vec3,
|
||
v3,
|
||
tween,
|
||
Tween,
|
||
Mask,
|
||
} from 'cc';
|
||
import { IconFactory } from './IconFactory';
|
||
import { Icon } from './Icon';
|
||
import { BaseRoller, ROLLER_STATE } from './BaseRoller';
|
||
import { ROLLER_EVENT } from './Define';
|
||
import { callGameApi } from 'db://assets/Loading/scripts/comm';
|
||
|
||
let { ccclass, property, executeInEditMode } = _decorator;
|
||
|
||
/**
|
||
* 滚轮组件类
|
||
*/
|
||
@ccclass('HRoller')
|
||
@executeInEditMode
|
||
export class HRoller extends BaseRoller {
|
||
|
||
// 编辑器属性
|
||
@property({ tooltip: '列数' })
|
||
col: number = 3;
|
||
|
||
// 本地格式化相关
|
||
// @property
|
||
// _format = false;
|
||
// @property({ tooltip: '本地格式化' })
|
||
// get format(): boolean {
|
||
// return this._format;
|
||
// }
|
||
// set format(b: boolean) {
|
||
// this._format = b;
|
||
// this.resizeContentSize();
|
||
|
||
// if (!this.iconFactory) {
|
||
// console.error('IconFactory没有设置');
|
||
// return;
|
||
// }
|
||
|
||
// // 重新创建图标
|
||
// this._content.removeAllChildren();
|
||
// this._info.icons = [];
|
||
// this._allIcons.clear();
|
||
// this._posToIconKey.clear();
|
||
// // 清除位置缓存 - 添加这一行
|
||
// this._positionCache.clear();
|
||
|
||
// for (let i = 0; i < this.col; i++) {
|
||
// let randomIndex = Math.floor(Math.random() * this.iconFactory.getIconNum());
|
||
// this.createNormalIcon(i, randomIndex);
|
||
// }
|
||
// }
|
||
|
||
_cachedContentWidth: number = 0;
|
||
_cachedAnchorX: number = 0;
|
||
|
||
/**
|
||
* 创建滚轮实例
|
||
* @param id 滚轮ID
|
||
* @param row 行数
|
||
* @param iconWidth 图标宽度
|
||
* @param iconHeight 图标高度
|
||
* @param iconFactory 图标工厂实例
|
||
* @param anchor 锚点位置
|
||
* @returns 新创建的滚轮实例
|
||
*/
|
||
static create(
|
||
id: number,
|
||
col: number,
|
||
iconWidth: number,
|
||
iconHeight: number,
|
||
iconFactory: IconFactory,
|
||
anchor: Vec2 = v2(0.5, 0.5)
|
||
): HRoller {
|
||
let rollerNode = new Node(`Roller${id}`);
|
||
rollerNode.addComponent(UITransform);
|
||
|
||
let roller = rollerNode.addComponent(HRoller);
|
||
roller._rollerId = id;
|
||
roller.col = col;
|
||
roller.iconWidth = iconWidth;
|
||
roller.iconHeight = iconHeight;
|
||
roller.iconFactory = iconFactory;
|
||
|
||
rollerNode.getComponent(UITransform).setAnchorPoint(anchor);
|
||
roller.resizeContentSize();
|
||
roller.initRoller(id);
|
||
return roller;
|
||
}
|
||
|
||
/**
|
||
* 设置节点尺寸和位置
|
||
*/
|
||
setupNodesSizeAndPosition() {
|
||
let totalWidth = this.iconWidth * this.col;
|
||
let anchorPoint = this.node.getComponent(UITransform).anchorPoint;
|
||
|
||
// 设置主节点尺寸
|
||
this.node.getComponent(UITransform).setContentSize(totalWidth, this.iconHeight);
|
||
|
||
// 设置view节点
|
||
this._view.setPosition(0, 0);
|
||
this._view.getComponent(UITransform).setContentSize(totalWidth, this.iconHeight);
|
||
this._view.getComponent(UITransform).setAnchorPoint(anchorPoint);
|
||
this._view.getComponent(UITransform).height *= 2;
|
||
|
||
// 设置content节点
|
||
this._content.setPosition(0, 0);
|
||
this._content.getComponent(UITransform).setContentSize(totalWidth, this.iconHeight);
|
||
this._content.getComponent(UITransform).setAnchorPoint(anchorPoint);
|
||
this._content.removeAllChildren();
|
||
}
|
||
|
||
/**
|
||
* 获取图标的实际坐标
|
||
* @param pos 图标位置索引
|
||
* @param height 图标高度
|
||
* @returns 图标的世界坐标
|
||
*/
|
||
getIconPosition(pos: number, size: number = 1): Vec3 {
|
||
// 创建缓存键
|
||
let cacheKey = size > 1 ? (pos + 1) * 1000 + size : pos;
|
||
|
||
if (this._positionCache.has(cacheKey)) {
|
||
return this._positionCache.get(cacheKey).clone();
|
||
}
|
||
|
||
// 确保缓存数据已初始化
|
||
if (!this._cachedContentWidth) {
|
||
this._cachedContentWidth = this._content.getComponent(UITransform).width;
|
||
this._cachedAnchorX = this._content.getComponent(UITransform).anchorX;
|
||
}
|
||
|
||
// 计算基准位置
|
||
let contentWidth = this._cachedContentWidth;
|
||
let anchorX = this._cachedAnchorX;
|
||
|
||
// 计算最左边位置
|
||
let leftX = -contentWidth * (1 - anchorX);
|
||
|
||
// 计算第一个位置的中心x坐标
|
||
let firstCenterX = leftX + this.iconWidth / 2;
|
||
|
||
// 计算当前位置的中心X坐标
|
||
let centerX = firstCenterX + pos * this.iconWidth;
|
||
|
||
// 对于大图标,需要调整位置
|
||
let finalX = centerX;
|
||
if (size > 1) {
|
||
// 大图标的中心点应该下移,使其顶部对齐格子
|
||
// 对于高度为3的图标,中心点应该下移1个格子高度
|
||
finalX = centerX + (size - 1) * this.iconWidth / 2;
|
||
}
|
||
|
||
// 创建最终位置
|
||
let position = v3(finalX, 0, 0);
|
||
|
||
// 缓存结果
|
||
this._positionCache.set(cacheKey, position.clone());
|
||
return position;
|
||
}
|
||
|
||
/**
|
||
* 初始化性能优化相关的缓存
|
||
*/
|
||
initCache() {
|
||
this._cachedUITransform = this._content.getComponent(UITransform);
|
||
this._cachedContentWidth = this._cachedUITransform.width;
|
||
this._cachedAnchorX = this._cachedUITransform.anchorX;
|
||
}
|
||
|
||
/**
|
||
* 收集现有图标
|
||
*/
|
||
collectExistingIcons() {
|
||
for (let i = 0; i < this.col; i++) {
|
||
let icon = this._allIcons.get(this._posToIconKey.get(i));
|
||
if (icon) {
|
||
this._allIcons.delete(this._posToIconKey.get(i));
|
||
this._posToIconKey.delete(i);
|
||
this._info.icons.push(icon);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 手动停止滚动
|
||
* @param data 停止时的图标数据
|
||
*/
|
||
async manualStopScroll(data: number[], XnInfo: any) {
|
||
if (this._info.isManualStop ||
|
||
this._info.state === ROLLER_STATE.STOP) {
|
||
return;
|
||
}
|
||
|
||
this.changeState(ROLLER_STATE.STOP);
|
||
this._info.resetLxInfo();
|
||
this._stopData = data;
|
||
this._info.isManualStop = true;
|
||
Tween.stopAllByTarget(this._info.speedNode);
|
||
|
||
// 直接回收所有动态图标
|
||
while (this._info.icons.length > 0) {
|
||
let icon = this._info.icons.pop();
|
||
this.iconFactory.recycleIcon(icon);
|
||
}
|
||
|
||
// 回收固定位置图标
|
||
for (let i = 0; i < this.col; i++) {
|
||
let icon = this._allIcons.get(this._posToIconKey.get(i));
|
||
if (icon) {
|
||
this._allIcons.delete(this._posToIconKey.get(i));
|
||
this._posToIconKey.delete(i);
|
||
this.iconFactory.recycleIcon(icon);
|
||
}
|
||
}
|
||
this._allIcons.clear();
|
||
this._posToIconKey.clear();
|
||
|
||
this.createInitIcons(data, XnInfo, true);
|
||
// 为所有创建的图标播放动画
|
||
for (let icon of this._allIcons.values()) {
|
||
icon.getComponent(Icon).playSpawnAni();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 创建最后一页图标
|
||
*/
|
||
createLastPage(XnInfo) {
|
||
let data = this._stopData;
|
||
if (!data) return;
|
||
|
||
// 计算最右边icon基准位置
|
||
let rightX = this.getIconPosition(this.col - 1).x;
|
||
let icons = this._info.icons;
|
||
if (icons.length > 0) {
|
||
rightX = Math.max(rightX, this.findHighestIconXorY(icons));
|
||
}
|
||
|
||
// 清除已有的位置映射,准备重新创建
|
||
this._allIcons.clear();
|
||
this._posToIconKey.clear();
|
||
|
||
// 从左到右依次创建图标(从位置0开始)
|
||
for (let i = 0; i < data.length; i++) {
|
||
// 如果当前位置已被特殊图标占用,跳过
|
||
if (this._posToIconKey.has(i)) continue;
|
||
|
||
// 生成图标ID
|
||
let pos = i;
|
||
let iconIndex = data[i];
|
||
let iconKey = this.generateIconKey(pos, 1, pos);
|
||
let multi = 0
|
||
if (XnInfo.Top) {
|
||
for (let i = 0; i < XnInfo.Top.length; i++) {
|
||
if (XnInfo.Top[i].StartIndex == pos) {
|
||
multi = XnInfo.Top[i].N
|
||
}
|
||
}
|
||
}
|
||
|
||
// 创建图标节点
|
||
let icon = this.iconFactory.icfactoryCreateIcon(iconIndex);
|
||
icon.getComponent(Icon).initIcon(iconIndex, 1, iconKey, 0, this._rollerId, multi);
|
||
|
||
// 计算位置
|
||
let x = rightX + (pos + 1) * this.iconWidth;
|
||
icon.setPosition(x, 0, 0);
|
||
|
||
this._content.addChild(icon);
|
||
|
||
// 存储图标节点
|
||
this._allIcons.set(iconKey, icon);
|
||
this._posToIconKey.set(pos, iconKey);
|
||
|
||
}
|
||
this.node.emit(ROLLER_EVENT.LAST_PAGE_CREATE, this._rollerId);
|
||
}
|
||
|
||
|
||
/**
|
||
* 检查图标是否超出显示范围
|
||
*/
|
||
checkDeadLine(icon: Node): boolean {
|
||
if (!this._cachedContentWidth) {
|
||
this._cachedContentWidth = this._content.getComponent(UITransform).width;
|
||
this._cachedAnchorX = this._content.getComponent(UITransform).anchorX;
|
||
}
|
||
|
||
let iconComponent = icon.getComponent(Icon);
|
||
let lheight = iconComponent.lHeight;
|
||
let iconBody = (lheight - 1) * this.iconWidth + this.iconWidth / 2;
|
||
let deadLine = -(this._cachedContentWidth * this._cachedAnchorX) - iconBody;
|
||
|
||
return icon.position.x <= deadLine;
|
||
}
|
||
|
||
/**
|
||
* 补充新的图标
|
||
*/
|
||
suppleIcon() {
|
||
let bornLine = this.getIconPosition(this.col - 1).x;
|
||
let icons = this._info.icons;
|
||
|
||
// 找到最右边的的图标X坐标
|
||
let rightX = this.findHighestIconXorY(icons);
|
||
|
||
// 如果最右边的图标低于出生线,创建新图标
|
||
if (rightX < bornLine) {
|
||
this.createRandomIcon();
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* 创建随机图标
|
||
*/
|
||
createRandomIcon() {
|
||
let iconIndex = this.getRandomIconIndex();
|
||
let newX = this.computeNewIconXorY();
|
||
let icon = this.iconFactory.icfactoryCreateIcon(iconIndex);
|
||
|
||
// 设置快速图标效果
|
||
if (this.shouldShowFastIcon()) {
|
||
icon.getComponent(Icon).showFastIcon(true);
|
||
}
|
||
icon.setPosition(newX, 0, 0);
|
||
this._content.addChild(icon);
|
||
|
||
|
||
this._info.icons.push(icon);
|
||
this.node.emit(ROLLER_EVENT.ON_R_ICON_CREATE, this._rollerId, icon);
|
||
}
|
||
|
||
|
||
/**
|
||
* 找到最右边的图标X坐标
|
||
* @param icons 图标数组
|
||
* @returns 最右边的X坐标
|
||
*/
|
||
findHighestIconXorY(icons: Node[]): number {
|
||
return icons.reduce((maxX, icon) => {
|
||
if (!icon || !icon.active) return maxX;
|
||
|
||
let iconComponent = icon.getComponent(Icon);
|
||
if (!iconComponent) return maxX;
|
||
|
||
let lHeight = iconComponent.lHeight || 1;
|
||
let iconX = icon.position.x;
|
||
|
||
// 对于高度大于1的图标,考虑其顶部位置
|
||
if (lHeight > 1) {
|
||
// 计算图标顶部位置:当前位置 + 高度差 * 图标高度 / 2
|
||
return Math.max(maxX, iconX + (lHeight - 1) * this.iconWidth / 2);
|
||
} else {
|
||
return Math.max(maxX, iconX);
|
||
}
|
||
}, -999);
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* 计算新图标的X坐标
|
||
*/
|
||
computeNewIconXorY(): number {
|
||
let icons = this._info.icons;
|
||
|
||
// 如果没有图标,使用初始位置
|
||
if (!icons.length) {
|
||
return this.getIconPosition(this.col - 1).x + this.iconWidth;
|
||
}
|
||
|
||
// 找到最右边的图标X坐标
|
||
let rightX = this.findHighestIconXorY(icons);
|
||
|
||
// 新图标位置 = 最高图标位置 + 图标高度
|
||
return rightX + this.iconWidth;
|
||
}
|
||
|
||
/**
|
||
* 清理资源
|
||
*/
|
||
onDestroy() {
|
||
this._cachedUITransform = null;
|
||
this._cachedContentWidth = 0;
|
||
this._cachedAnchorX = 0;
|
||
this._positionCache.clear();
|
||
}
|
||
|
||
/**
|
||
* 滚轮移动
|
||
* @param dt 时间增量
|
||
*/
|
||
rollerMove(dt: number) {
|
||
// 计算移动向量
|
||
let speed = this._info.speed;
|
||
let move = speed * dt;
|
||
let moveVec = v3(move, 0, 0);
|
||
|
||
|
||
|
||
// 更新动态图标位置
|
||
this._info.icons.forEach(icon => {
|
||
if (!icon || !icon.isValid) return;
|
||
|
||
if (icon.active) {
|
||
let newPosition = icon.position.clone().subtract(moveVec);
|
||
icon.setPosition(newPosition);
|
||
}
|
||
});
|
||
// 获取所有图标
|
||
let allIcons = Array.from(this._allIcons.values());
|
||
allIcons.forEach(icon => {
|
||
if (!icon || !icon.isValid) return;
|
||
let newPosition = icon.position.clone().subtract(moveVec);
|
||
icon.setPosition(newPosition);
|
||
});
|
||
|
||
|
||
}
|
||
|
||
/**
|
||
* 回收滚轮图标
|
||
*/
|
||
recycleRollerIcon() {
|
||
// 回收动态图标
|
||
let icons = this._info.icons;
|
||
for (let i = icons.length - 1; i >= 0; i--) {
|
||
let icon = icons[i];
|
||
if (!icon || !icon.isValid) {
|
||
icons.splice(i, 1);
|
||
continue;
|
||
}
|
||
|
||
if (this.checkDeadLine(icon)) {
|
||
// 从数组中移除
|
||
icons.splice(i, 1);
|
||
// 回收图标
|
||
this.iconFactory.recycleIcon(icon);
|
||
}
|
||
}
|
||
|
||
// 回收固定位置图标(非最后一页创建状态)
|
||
if (this._info.state !== ROLLER_STATE.LAST_PAGE_CREATE) {
|
||
for (let i = 0; i < this.col; i++) {
|
||
let iconKey = this._posToIconKey.get(i);
|
||
if (!iconKey) continue;
|
||
|
||
let icon = this._allIcons.get(iconKey);
|
||
if (!icon || !icon.isValid) {
|
||
this._posToIconKey.delete(i);
|
||
this._allIcons.delete(iconKey);
|
||
continue;
|
||
}
|
||
|
||
if (this.checkDeadLine(icon)) {
|
||
// 从映射中移除
|
||
this._allIcons.delete(iconKey);
|
||
this._posToIconKey.delete(i);
|
||
// 回收图标
|
||
this.iconFactory.recycleIcon(icon);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 处理特殊图标(n*1图标)
|
||
if (this._info.state !== ROLLER_STATE.LAST_PAGE_CREATE) {
|
||
// 获取所有特殊图标的key
|
||
let specialIconKeys = Array.from(this._allIcons.keys())
|
||
.filter(key => key.startsWith('large_'));
|
||
|
||
for (let iconKey of specialIconKeys) {
|
||
let icon = this._allIcons.get(iconKey);
|
||
if (!icon || !icon.isValid) {
|
||
this._allIcons.delete(iconKey);
|
||
continue;
|
||
}
|
||
|
||
if (this.checkDeadLine(icon)) {
|
||
// 从映射中移除
|
||
this._allIcons.delete(iconKey);
|
||
|
||
// 移除所有关联的位置映射
|
||
for (let [pos, key] of this._posToIconKey.entries()) {
|
||
if (key === iconKey) {
|
||
this._posToIconKey.delete(pos);
|
||
}
|
||
}
|
||
|
||
// 回收图标
|
||
this.iconFactory.recycleIcon(icon);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/**
|
||
* 停止处理
|
||
*/
|
||
stopProcess() {
|
||
let rightIcon = this.getIconPosition(this.col - 1);
|
||
let stopline = rightIcon.x - 100; // 偏移量100
|
||
let topX = this.findHighestIconXorY(Array.from(this._allIcons.values()));
|
||
|
||
if (topX <= stopline) {
|
||
this.changeState(ROLLER_STATE.BOUNCE);
|
||
this.playBounceAnimation();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 播放回弹动画
|
||
*/
|
||
playBounceAnimation() {
|
||
let time = 0.1;
|
||
let offset = 50;
|
||
|
||
// 获取所有图标
|
||
let allIcons = Array.from(this._allIcons.values());
|
||
|
||
allIcons.forEach(icon => {
|
||
|
||
if (!icon || !icon.isValid) return;
|
||
|
||
let iconComponent = icon.getComponent(Icon);
|
||
if (!iconComponent) return;
|
||
|
||
// 获取图标的起始位置和高度
|
||
let startPos = iconComponent.startPos;
|
||
let lHeight = iconComponent.lHeight || 1;
|
||
|
||
// 获取图标应该在的位置
|
||
let position = this.getIconPosition(startPos, lHeight);
|
||
|
||
// 设置初始位置(向下偏移)
|
||
// icon.setPosition(position.add(v3(-offset, 0, 0)));
|
||
icon.setPosition(position);
|
||
iconComponent.playSpawnAni();
|
||
|
||
// 创建回弹动画
|
||
// tween(icon)
|
||
// .by(time, { position: v3(offset, 0, 0) })
|
||
// .start();
|
||
});
|
||
|
||
// 延迟切换到停止状态
|
||
this.scheduleOnce(() => {
|
||
this.changeState(ROLLER_STATE.STOP);
|
||
}, time);
|
||
}
|
||
|
||
/**
|
||
* 消除逻辑
|
||
* 一定是在静止状态消除的
|
||
* @param deleteMsg 删除信息
|
||
* */
|
||
deleteIconNode(positions: number[]) {
|
||
// 记录被处理过的图标键
|
||
let processedPos = new Set<number>();
|
||
|
||
// 处理每个位置
|
||
for (let pos of positions) {
|
||
// 如果此图标已处理过,跳过
|
||
if (processedPos.has(pos)) {
|
||
continue;
|
||
}
|
||
let iconKey = this._posToIconKey.get(pos);
|
||
if (!iconKey) {
|
||
console.error('deleteIconNode iconKey is null', pos);
|
||
continue;
|
||
}
|
||
|
||
|
||
|
||
let iconNode = this._allIcons.get(iconKey);
|
||
if (!iconNode || !iconNode.isValid) {
|
||
console.error('deleteIconNode iconNode is null', pos);
|
||
continue;
|
||
}
|
||
|
||
let iconComponent = iconNode.getComponent(Icon);
|
||
if (!iconComponent) {
|
||
console.error('deleteIconNode iconComponent is null', pos);
|
||
continue;
|
||
}
|
||
|
||
|
||
let startPos = iconComponent.startPos;
|
||
// 从allIcons中删除图标
|
||
this._allIcons.delete(iconKey);
|
||
|
||
let height = iconComponent.lHeight || 1;
|
||
// 移除所有关联的位置映射
|
||
if (height > 1) {
|
||
// 对于n*1图标,需要清除所有占用的位置
|
||
for (let i = 0; i < height; i++) {
|
||
this._posToIconKey.delete(startPos + i);
|
||
// 标记此图标已处理
|
||
processedPos.add(startPos + i);
|
||
}
|
||
} else {
|
||
this._posToIconKey.delete(pos);
|
||
// 标记此图标已处理
|
||
processedPos.add(pos);
|
||
|
||
}
|
||
iconComponent.playWinAni(true);
|
||
iconComponent.playDeleteAni();
|
||
this.scheduleOnce(() => {
|
||
this.iconFactory.recycleIcon(iconNode);
|
||
}, 1.5)
|
||
}
|
||
|
||
this.node.emit(ROLLER_EVENT.ICON_DELETED, this._rollerId);
|
||
}
|
||
|
||
showMultiMove(XnInfo) {
|
||
let allIcons = Array.from(this._allIcons.values());
|
||
allIcons.forEach(icon => {
|
||
if (!icon || !icon.isValid) return;
|
||
icon.getComponent(Icon).playNormalMultiMove(XnInfo)
|
||
});
|
||
}
|
||
|
||
playFrameTypeChangeAni(positions: number[]): void {
|
||
for (let pos of positions) {
|
||
|
||
let iconKey = this._posToIconKey.get(pos);
|
||
if (!iconKey) continue;
|
||
|
||
let iconNode = this._allIcons.get(iconKey);
|
||
if (!iconNode || !iconNode.isValid) continue;
|
||
|
||
let iconComponent = iconNode.getComponent(Icon);
|
||
if (!iconComponent) continue;
|
||
|
||
iconComponent.playWinAni(true);
|
||
}
|
||
}
|
||
|
||
chanegeIconAndFrameType(data: any[]): void {
|
||
return;
|
||
}
|
||
|
||
/**
|
||
* 创建新icon
|
||
* @param createMsg 信息
|
||
*/
|
||
createNewIconTop(createDatas: number[], XnInfo: any) {
|
||
// 获取所有图标
|
||
let rightX = this.getIconPosition(this.col - 1, 1).x;
|
||
for (let i = 0; i < createDatas.length; i++) {
|
||
let pos = this.col + i + 1;
|
||
let iconIndex = createDatas[i];
|
||
let iconKey = this.generateIconKey(pos, 1, pos);
|
||
let icon = this.iconFactory.icfactoryCreateIcon(iconIndex);
|
||
let multi = 0
|
||
if (XnInfo.Top && iconIndex == 2) {
|
||
for (let i = 0; i < XnInfo.Top.length; i++) {
|
||
if (XnInfo.Top[i].StartIndex == pos - createDatas.length - 1) {
|
||
multi = XnInfo.Top[i].N
|
||
}
|
||
}
|
||
}
|
||
|
||
icon.getComponent(Icon).initIcon(iconIndex, 1, iconKey, 0, this._rollerId, multi);
|
||
|
||
let x = rightX + (i + 1) * this.iconWidth;
|
||
icon.setPosition(x, 0, 0);
|
||
this._content.addChild(icon);
|
||
|
||
this._allIcons.set(iconKey, icon);
|
||
this._posToIconKey.set(pos, iconKey);
|
||
}
|
||
this.node.emit(ROLLER_EVENT.ICON_CREATE, this._rollerId);
|
||
}
|
||
|
||
|
||
/** icon进行掉落移动 */
|
||
iconFallDown(data: number[], crossSymbols: any) {
|
||
// 更新所有icon的iconKey和posToIconKey
|
||
|
||
let updates = [];
|
||
let sortNewIconStartPos = this.getNewIconsStartPos(data, crossSymbols);
|
||
let sortIcons = this.getSortIcons();
|
||
for (let i = 0; i < sortNewIconStartPos.length; i++) {
|
||
let newStartPos = sortNewIconStartPos[i];
|
||
let oldIcon = sortIcons[i];
|
||
let oldIconStartPos = oldIcon.startPos;
|
||
|
||
|
||
if (oldIconStartPos === newStartPos) {
|
||
continue;
|
||
}
|
||
let oldIconNode = oldIcon.icon;
|
||
let oldIconComponent = oldIcon.component;
|
||
let oldIconkey = oldIconComponent.iconKey;
|
||
let lHeight = oldIconComponent.lHeight || 1;
|
||
let newIconkey = this.generateIconKey(newStartPos, 1, newStartPos);
|
||
let newX = this.getIconPosition(newStartPos, lHeight).x;
|
||
let oldX = oldIconNode.position.x;
|
||
|
||
updates.push({
|
||
node: oldIconNode,
|
||
component: oldIconComponent,
|
||
oldKey: oldIconkey,
|
||
oldStartPos: oldIconStartPos,
|
||
newStartPos: newStartPos,
|
||
newKey: newIconkey,
|
||
height: lHeight
|
||
})
|
||
|
||
|
||
let time = 0.3;
|
||
tween(oldIconNode)
|
||
.to(time, { position: v3(newX, 0, 0) })
|
||
.start();
|
||
}
|
||
|
||
for (let update of updates) {
|
||
this._allIcons.delete(update.oldKey);
|
||
for (let i = 0; i < update.height; i++) {
|
||
this._posToIconKey.delete(update.oldStartPos + i);
|
||
}
|
||
}
|
||
|
||
// 再添加所有新映射
|
||
for (let update of updates) {
|
||
// 添加新的映射
|
||
update.component.iconKey = update.newKey;
|
||
this._allIcons.set(update.newKey, update.node);
|
||
for (let i = 0; i < update.height; i++) {
|
||
this._posToIconKey.set(update.newStartPos + i, update.newKey);
|
||
}
|
||
}
|
||
this.scheduleOnce(() => {
|
||
this.node.emit(ROLLER_EVENT.ICON_FALLEN, this._rollerId);
|
||
}, 0.5)
|
||
}
|
||
|
||
|
||
getSortIcons() {
|
||
let iconInfos: { icon: Node, component: Icon, startPos: number }[] = [];
|
||
|
||
// 收集所有图标信息
|
||
for (let [iconKey, iconNode] of this._allIcons.entries()) {
|
||
if (!iconNode || !iconNode.isValid) continue;
|
||
|
||
let iconComponent = iconNode.getComponent(Icon);
|
||
if (!iconComponent) continue;
|
||
|
||
// 记录图标信息
|
||
iconInfos.push({
|
||
icon: iconNode,
|
||
component: iconComponent,
|
||
startPos: iconComponent.startPos
|
||
});
|
||
}
|
||
|
||
// 按startPos从小到大排序
|
||
iconInfos.sort((a, b) => a.startPos - b.startPos);
|
||
|
||
return iconInfos;
|
||
}
|
||
|
||
|
||
|
||
getNewIconsStartPos(data: number[], crossSymbols: any) {
|
||
// 存储所有图标的startPos
|
||
let startPositions: number[] = [];
|
||
|
||
// 记录已处理的位置
|
||
let processedPositions = new Set<number>();
|
||
// 记录已经处理的pos
|
||
let processedPos = new Set<number>();
|
||
// 首先处理不规则图标(n*1图标)
|
||
if (crossSymbols) {
|
||
for (let pos in crossSymbols) {
|
||
let id = crossSymbols[pos].id;
|
||
if (processedPos.has(id)) continue;
|
||
processedPos.add(id);
|
||
let iconSpecialMsg = crossSymbols[pos];
|
||
let startPos = iconSpecialMsg.startPos;
|
||
let endPos = iconSpecialMsg.endPos;
|
||
|
||
// 添加不规则图标的startPos
|
||
startPositions.push(startPos);
|
||
|
||
// 标记所有被占用的位置
|
||
for (let i = startPos; i <= endPos; i++) {
|
||
processedPositions.add(i);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 然后处理常规图标
|
||
for (let i = 0; i < data.length; i++) {
|
||
// 如果该位置未被处理(不是不规则图标的一部分)
|
||
if (!processedPositions.has(i)) {
|
||
startPositions.push(i);
|
||
}
|
||
}
|
||
|
||
// 从小到大排序
|
||
startPositions.sort((a, b) => a - b);
|
||
return startPositions;
|
||
}
|
||
|
||
}
|