first commit
This commit is contained in:
232
assets/scripts/DragManager.ts
Normal file
232
assets/scripts/DragManager.ts
Normal file
@@ -0,0 +1,232 @@
|
||||
import { Node, Vec3, tween } from "cc";
|
||||
|
||||
export interface DragCell {
|
||||
r: number;
|
||||
c: number;
|
||||
type: number;
|
||||
node: Node;
|
||||
}
|
||||
|
||||
export interface DragGroup {
|
||||
cells: DragCell[];
|
||||
dirR: number;
|
||||
dirC: number;
|
||||
maxSteps: number;
|
||||
}
|
||||
|
||||
export class DragManager {
|
||||
private board: number[][];
|
||||
private blockNodes: (Node | null)[][];
|
||||
private rows: number;
|
||||
private cols: number;
|
||||
private blockSize: number;
|
||||
|
||||
constructor(
|
||||
board: number[][],
|
||||
blockNodes: (Node | null)[][],
|
||||
rows: number,
|
||||
cols: number,
|
||||
blockSize: number,
|
||||
) {
|
||||
this.board = board;
|
||||
this.blockNodes = blockNodes;
|
||||
this.rows = rows;
|
||||
this.cols = cols;
|
||||
this.blockSize = blockSize;
|
||||
}
|
||||
|
||||
/** 查找拖动组(从点击格子 + 方向出发) */
|
||||
findDragGroup(
|
||||
r: number,
|
||||
c: number,
|
||||
dirR: number,
|
||||
dirC: number,
|
||||
): { r: number; c: number }[] {
|
||||
if (this.board[r][c] < 0) return [];
|
||||
|
||||
const group: { r: number; c: number }[] = [];
|
||||
|
||||
// 包含起点
|
||||
group.push({ r, c });
|
||||
|
||||
if (dirR === 0 && dirC === 0) {
|
||||
// 无方向,返回只有自己
|
||||
return group;
|
||||
}
|
||||
|
||||
if (dirR !== 0) {
|
||||
// 垂直方向,向前方向查找
|
||||
// 前面方向就是 dirR 方向(正负决定上或下)
|
||||
|
||||
let rr = r + dirR;
|
||||
while (rr >= 0 && rr < this.rows) {
|
||||
if (this.board[rr][c] >= 0) {
|
||||
if (dirR > 0) {
|
||||
// 向下,push后面
|
||||
group.push({ r: rr, c });
|
||||
} else {
|
||||
// 向上,unshift前面
|
||||
group.unshift({ r: rr, c });
|
||||
}
|
||||
rr += dirR;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (dirC !== 0) {
|
||||
// 水平方向,向前方向查找
|
||||
// 前面方向就是 dirC 方向(正负决定左或右)
|
||||
|
||||
let cc = c + dirC;
|
||||
while (cc >= 0 && cc < this.cols) {
|
||||
if (this.board[r][cc] >= 0) {
|
||||
if (dirC > 0) {
|
||||
// 向右,push后面
|
||||
group.push({ r, c: cc });
|
||||
} else {
|
||||
// 向左,unshift前面
|
||||
group.unshift({ r, c: cc });
|
||||
}
|
||||
cc += dirC;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
/** 计算最多能移动多少格 */
|
||||
countEmptyStepsGroup(
|
||||
group: { r: number; c: number }[],
|
||||
dirR: number,
|
||||
dirC: number,
|
||||
): number {
|
||||
if (group.length === 0) return 0;
|
||||
// 按滑动方向,找整组前方连续空格最小值
|
||||
if (dirR !== 0) {
|
||||
// 纵向滑动,找组中最顶部或最底部行号
|
||||
const rows = group.map((g) => g.r);
|
||||
const col = group[0].c;
|
||||
const boundaryRow = dirR === 1 ? Math.max(...rows) : Math.min(...rows);
|
||||
let count = 0;
|
||||
let checkRow = boundaryRow + dirR;
|
||||
while (
|
||||
checkRow >= 0 &&
|
||||
checkRow < this.rows &&
|
||||
this.board[checkRow][col] === -1
|
||||
) {
|
||||
count++;
|
||||
checkRow += dirR;
|
||||
}
|
||||
return count;
|
||||
} else {
|
||||
// 横向滑动,找组中最左或最右列号
|
||||
const cols = group.map((g) => g.c);
|
||||
const row = group[0].r;
|
||||
const boundaryCol = dirC === 1 ? Math.max(...cols) : Math.min(...cols);
|
||||
let count = 0;
|
||||
let checkCol = boundaryCol + dirC;
|
||||
while (
|
||||
checkCol >= 0 &&
|
||||
checkCol < this.cols &&
|
||||
this.board[row][checkCol] === -1
|
||||
) {
|
||||
count++;
|
||||
checkCol += dirC;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
/** 执行拖动中的偏移 */
|
||||
public applyDragOffset(
|
||||
draggingGroup,
|
||||
maxSteps: number,
|
||||
dirR: number,
|
||||
dirC: number,
|
||||
dy: number,
|
||||
dx: number,
|
||||
) {
|
||||
// 计算偏移量,滑动方向相反时置0
|
||||
let offset = dirR !== 0 ? dy : dx;
|
||||
|
||||
if (
|
||||
(dirR === -1 && offset <= 0) ||
|
||||
(dirR === 1 && offset >= 0) ||
|
||||
(dirC === 1 && offset <= 0) ||
|
||||
(dirC === -1 && offset >= 0)
|
||||
)
|
||||
offset = 0;
|
||||
|
||||
const maxOffset = maxSteps * this.blockSize;
|
||||
if (Math.abs(offset) > maxOffset) offset = maxOffset * Math.sign(offset);
|
||||
|
||||
// 整组方块移动
|
||||
draggingGroup.forEach(({ r, c }) => {
|
||||
const block = this.blockNodes[r][c];
|
||||
if (!block) return;
|
||||
const startPos = this.getPos(r, c);
|
||||
if (dirR !== 0) {
|
||||
block.setPosition(startPos.x, startPos.y + offset, 0);
|
||||
} else {
|
||||
block.setPosition(startPos.x + offset, startPos.y, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getPos(row: number, col: number): Vec3 {
|
||||
const x =
|
||||
col * this.blockSize -
|
||||
(this.cols * this.blockSize) / 2 +
|
||||
this.blockSize / 2;
|
||||
const y =
|
||||
(this.rows * this.blockSize) / 2 -
|
||||
row * this.blockSize -
|
||||
this.blockSize / 2;
|
||||
return new Vec3(x, y, 0);
|
||||
}
|
||||
|
||||
/** 松手:确认移动 or 回弹 */
|
||||
public async settleDrag(
|
||||
blocksInfo: DragCell[],
|
||||
reset: boolean,
|
||||
steps?: number,
|
||||
slidingDir?,
|
||||
) {
|
||||
if (reset) {
|
||||
await this.resetGroup(blocksInfo);
|
||||
} else {
|
||||
await this.applyMove(blocksInfo, steps, slidingDir);
|
||||
}
|
||||
}
|
||||
|
||||
/** 执行动画移动 */
|
||||
private async applyMove(blocksInfo: DragCell[], steps: number, slidingDir) {
|
||||
blocksInfo.forEach(({ r, c, type, node }) => {
|
||||
const tr = r + slidingDir.dirR * steps;
|
||||
const tc = c + slidingDir.dirC * steps;
|
||||
|
||||
this.board[tr][tc] = type;
|
||||
this.blockNodes[tr][tc] = node;
|
||||
if (node) node.setPosition(this.getPos(tr, tc));
|
||||
});
|
||||
}
|
||||
|
||||
/** 回弹动画 */
|
||||
private async resetGroup(blocksInfo) {
|
||||
const promises = blocksInfo.map(({ r, c, type, node }) => {
|
||||
const targetPos = this.getPos(r, c);
|
||||
this.board[r][c] = type;
|
||||
this.blockNodes[r][c] = node;
|
||||
return new Promise<void>((resolve) => {
|
||||
tween(node)
|
||||
.to(0.15, { position: targetPos })
|
||||
.call(() => resolve()) // ✅ 修复
|
||||
.start();
|
||||
});
|
||||
});
|
||||
await Promise.all(promises);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user