| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698 |
- import { _decorator, BoxCollider, Color, Component, Graphics, instantiate, Label, Node, Prefab, sp, Sprite, SpriteFrame, tween, v3, Vec3 } from 'cc';
- import { Block } from './Block';
- import { BlockUtil } from './BlockUitl';
- import { blockMap } from './blockMap';
- import { LvDir } from '../../LvData/LvData';
- const { ccclass, property } = _decorator;
- @ccclass('BlockLink')
- export class BlockLink extends Component {
- mapConfig: blockMap = new blockMap();
- // 记录选择的两个方块
- public selectedBlocks: Node[] = [];
- @property(Graphics)
- lineGraphics: Graphics | null = null; // 绘制连线的Graphics组件
- lineNode//连线节点
- @property(sp.Skeleton)
- lianSkeleton: sp.Skeleton | null = null;//绘制连线的骨骼
- @property(Prefab)
- lineSegmentPrefab: Prefab | null = null; // 线段骨骼预制
- @property({ type: sp.SkeletonData })
- spineData: sp.SkeletonData | null = null;
- spineRefLength: number = 70; // 骨骼动画原始长度
- // 存储所有方块节点
- static blockArry: (Node | null)[][] = [];
- //当前选择的方块
- public sleeBlock: Node = null;
- public static totalBlocks: number = 0;
- public static remainingBlocks: number = 0;
- // 匹配锁定
- public isMatching: boolean = false;
- public isMoving: boolean = false;
- static inti: BlockLink
- start() {
-
- BlockLink.inti = this;
- this.node.getChildByName("line").active = false
- this.isMoving = false
- this.isMatching = false;
- }
- isConnected(block1: Node, block2: Node, isSearch = false): boolean {
- if (!this.node.isValid) return;
- //debugger
- this.selectedBlocks = [block1, block2];
- // 直连(最快)
- const isLineConnected = this.isLineConnected(block1, block2);
- console.log(`是否直连: ${isLineConnected}`);
- if (isLineConnected) {
- if (!this.node.isValid) return;
- if (!isSearch) {
- const block1Comp = block1.getComponent(Block);
- const block2Comp = block2.getComponent(Block);
- if (block1Comp && block2Comp) {
- this.drawDirectLine(block2, block1);
- block1Comp.handleMatchSuccess(block2Comp);
- }
- }
- return true;
- }
- // 再检查一个拐点
- const isOneLinkcrease = this.isOneLinkcrease(block1, block2);
- console.log(`是否一个拐点连接: ${isOneLinkcrease}`);
- if (isOneLinkcrease) {
- if (!this.node.isValid) return;
- if (!isSearch) {
- const block1Comp = block1.getComponent(Block);
- const block2Comp = block2.getComponent(Block);
- if (block1Comp && block2Comp) {
- // 获取拐点世界坐标
- const cornerPos = this.getLinkCorner(block1, block2);
- if (cornerPos) {
-
- this.drawPathWithCorner(block2, cornerPos, block1);
- // 绘制路径时使用:起点 -> cornerPos -> 终点
- } else {
- console.log("没有找到有效拐点路径");
- }
- block1Comp.handleMatchSuccess(block2Comp);
- }
- }
- return true;
- }
- // 两个拐点(最慢)
- const istwoLinkcrease = this.istwoLinkcrease(block1, block2);
- console.log(`是否两个拐点连接: ${istwoLinkcrease}`);
- if (istwoLinkcrease) {
- if (!this.node.isValid) return;
- if (!isSearch) {
- const block1Comp = block1.getComponent(Block);
- const block2Comp = block2.getComponent(Block);
- if (block1Comp && block2Comp) {
- // 新增:获取两个拐点坐标
- const start = this.getBlockPosition(block1);
- const end = this.getBlockPosition(block2);
- const corners = BlockUtil.getTwoLinkCorners(
- start.row, start.col,
- end.row, end.col,
- this.mapConfig.rows, this.mapConfig.cols,
- (row, col) => this.canPass(row, col)
- );
- if (corners) {
- // 将行列坐标转换为世界坐标
- const corner1Pos = v3(
- this.mapConfig.gridOrigin.x + corners[0].j * this.mapConfig.spacing,
- this.mapConfig.gridOrigin.y - corners[0].i * this.mapConfig.spacing,
- 0
- );
- const corner2Pos = v3(
- this.mapConfig.gridOrigin.x + corners[1].j * this.mapConfig.spacing,
- this.mapConfig.gridOrigin.y - corners[1].i * this.mapConfig.spacing,
- 0
- );
- // 绘制双拐点路径(需先实现 drawPathWithTwoCorners 方法)
- this.drawPathWithTwoCorners(block2, corner2Pos, corner1Pos, block1);
- }
- block1Comp.handleMatchSuccess(block2Comp);
- }
- }
- return true;
- }
- }
- isLineConnected(block1: Node, block2: Node): boolean {
- if (!this.node.isValid) return;
- //debugger
- console.log("直线")
- const start = this.getBlockPosition(block1)
- const end = this.getBlockPosition(block2)
- return BlockUtil.isLineConnectedByIndex(
- start.row, start.col, end.row, end.col,
- (row, col) => this.canPass(row, col)
- );
- }
- isOneLinkcrease(block1: Node, block2: Node): boolean {
- if (!this.node.isValid) return;
- //debugger
- console.log("1个折角")
- const start = this.getBlockPosition(block1)
- const end = this.getBlockPosition(block2)
- return BlockUtil.isOneLink(
- start.row, start.col, end.row, end.col,
- (row, col) => this.canPass(row, col)
- );
- }
- istwoLinkcrease(block1: Node, block2: Node): boolean {
- if (!this.node.isValid) return;
- //debugger
- console.log("两个折角")
- const start = this.getBlockPosition(block1)
- const end = this.getBlockPosition(block2)
- return BlockUtil.isTwoLink(
- start.row, start.col, end.row, end.col,
- this.mapConfig.rows, this.mapConfig.cols,
- (row, col) => this.canPass(row, col)
- );
- }
- canPass(_row: number, _col: number): boolean {
- //debugger;
- // 检查边界外的位置
- if (_row < 0 || _row >= this.mapConfig.rows || _col < 0 || _col >= this.mapConfig.cols) {
- //console.log(`位置 (${_row}, ${_col}) 超出边界`);
- return true;
- }
- // 明确区分起点终点检查
- const isStart = this.isSameBlock(_row, _col, this.selectedBlocks[0]);
- const isEnd = this.isSameBlock(_row, _col, this.selectedBlocks[1]);
- if (isStart) {
- return true;
- }
- if (isEnd) {
- return true;
- }
- // 检查空位
- const isEmpty = BlockLink.blockArry[_row][_col] === null;
- if (!isEmpty) {
- // console.log(`位置 (${_row}, ${_col}) 已被占用。`);
- return false;
- }
- //console.log(`位置 (${_row}, ${_col}) 可以通过。`);
- return true;
- }
- // 判断指定行列位置是否是某个方块
- private isSameBlock(_row: number, _col: number, block: Node): boolean {
- //debugger
- if (!block) return false;
- const pos = this.getBlockPosition(block);
- return pos.row === _row && pos.col === _col;
- }
- //获取行列
- public getRowCol(pos: Vec3): { i: number, j: number } {
- // debugger
- const offsetX = pos.x - this.mapConfig.gridOrigin.x;
- const offsetY = this.mapConfig.gridOrigin.y - pos.y;
- const j = Math.round(offsetX / this.mapConfig.spacing);
- const i = Math.round(offsetY / this.mapConfig.spacing);
- if (i < 0 || i >= this.mapConfig.rows || j < 0 || j >= this.mapConfig.cols) {
- console.log(`坐标转换: (${pos.x}, ${pos.y}) -> (${i}, ${j})`);
- }
- console.log(`getRowCol行: ${i}, 列: ${j}`)
- return { i, j };
- }
- getBlockPosition(blockNode: Node) {
- for (let row = 0; row < this.mapConfig.rows; row++) {
- for (let col = 0; col < this.mapConfig.cols; col++) {
- if (BlockLink.blockArry[row][col] === blockNode) {
- return { row, col }; // 正确返回行列
- }
- }
- }
- return null;
- }
- getLinkCorner(block1: Node, block2: Node): Vec3 | null {
- const start = this.getBlockPosition(block1);
- const end = this.getBlockPosition(block2);
- const corner = BlockUtil.getOneLinkCorner(
- start.row, start.col,
- end.row, end.col,
- (row, col) => this.canPass(row, col)
- );
- if (!corner) return null;
- // 将行列坐标转换为世界坐标
- return v3(
- this.mapConfig.gridOrigin.x + corner.j * this.mapConfig.spacing,
- this.mapConfig.gridOrigin.y - corner.i * this.mapConfig.spacing,
- 0
- );
- }
- /**
- * 绘制两个方块的直连路径
- * @param startNode 起点方块节点
- * @param endNode 终点方块节点
- */
- private drawDirectLine(startNode: Node, endNode: Node): void {
- const graphics = this.node.getChildByName("Graphics").getComponent(Graphics);
- graphics.node.setSiblingIndex(graphics.node.parent.children.length - 1); // 置顶
- graphics.clear();
- // graphics.fillColor.fromHEX('#0000FF');
- // graphics.fillColor.fromHEX('#ff0000');
- // graphics.fillColor = new Color().fromHEX('#0000ff');
- let fillColor = new Color().fromHEX('#3562ff')
- graphics.strokeColor = fillColor
- graphics.lineWidth = 12;
- const startPos = startNode.position;
- const endPos = endNode.position;
- // 绘制直线路径
- graphics.moveTo(startPos.x, startPos.y);
- graphics.lineTo(endPos.x, endPos.y);
- graphics.stroke();
- this.scheduleOnce(() => {
- graphics.clear();
- console.log("路径已清除");
- }, 0.35);
- }
- /**
- * 绘制从起点到拐点再到终点的折线
- * @param startNode 起点方块节点
- * @param cornerPos 拐点世界坐标
- * @param endNode 终点方块节点
- */
- private drawPathWithCorner(startNode: Node, cornerPos: Vec3, endNode: Node): void {
- const graphics = this.node.getChildByName("Graphics").getComponent(Graphics);
- graphics.node.setSiblingIndex(graphics.node.parent.children.length - 1); // 置顶
- graphics.clear();
- //graphics.strokeColor = Color.BLUE;
- // graphics.fillColor.fromHEX('#0000FF')
- //graphics.fillColor = new Color().fromHEX('#0000ff');
- let fillColor = new Color().fromHEX('#3562ff')
- graphics.strokeColor = fillColor
- graphics.lineWidth = 12;
- // 增强调试输出
- const startPos = startNode.position;
- const endPos = endNode.position;
- const cornerWorldPos = cornerPos.clone(); // 已经是世界坐标
- // 绘制路径
- graphics.moveTo(startPos.x, startPos.y);
- graphics.lineTo(cornerWorldPos.x, cornerWorldPos.y); // 直接到拐点
- graphics.lineTo(endPos.x, endPos.y); // 再到终点
- graphics.stroke();
- this.scheduleOnce(() => {
- graphics.clear();
- console.log("路径已清除");
- }, 0.5);
- }
- /**
- * 绘制带两个拐点的路径
- * @param startNode 起点节点
- * @param corner1Pos 第一个拐点世界坐标
- * @param corner2Pos 第二个拐点世界坐标
- * @param endNode 终点节点
- */
- private drawPathWithTwoCorners(
- startNode: Node,
- corner1Pos: Vec3,
- corner2Pos: Vec3,
- endNode: Node
- ): void {
- const graphics = this.node.getChildByName("Graphics").getComponent(Graphics);
- graphics.node.setSiblingIndex(graphics.node.parent.children.length - 1); // 置顶
- graphics.clear();
- //graphics.fillColor.fromHEX('#0000FF');
- graphics.lineWidth = 12;
- // graphics.color = Color.BLUE;
- let fillColor = new Color().fromHEX('#3562ff')
- graphics.strokeColor = fillColor
- const startPos = startNode.position;
- const endPos = endNode.position;
- // 绘制路径
- graphics.moveTo(startPos.x, startPos.y);
- graphics.lineTo(corner1Pos.x, corner1Pos.y);
- graphics.lineTo(corner2Pos.x, corner2Pos.y);
- graphics.lineTo(endPos.x, endPos.y);
- graphics.stroke();
- this.scheduleOnce(() => {
- graphics.clear();
- console.log("路径已清除");
- }, 0.5);
- }
- // /**方块移动*/
- // BlockLink.ts
- public moveByLevelDirection(lvDir: LvDir): void {
- switch (lvDir) {
- case LvDir.left:
- this.moveAllLeft();
- break;
- case LvDir.right:
- this.moveAllRight();
- break;
- case LvDir.up:
- this.moveAllUp();
- break;
- case LvDir.down:
- this.moveAllDown();
- break;
- case LvDir.xCenter:
- this.moveToCenter(true);
- break;
- case LvDir.xOut:
- this.moveFromCenter(false);
- break;
- case LvDir.yCenter:
- this.moveToCenter(false);
- break;
- case LvDir.yOut:
- this.moveFromCenter(true);
- break;
- }
- }
- private moveAllLeft() {
- this.isMoving = true;
- for (let row = 0; row < this.mapConfig.rows; row++) {
- const originalRow = [...BlockLink.blockArry[row]];
- const rowBlocks = originalRow.filter(block => block !== null);
- const newRow = new Array(this.mapConfig.cols).fill(null);
- for (let i = 0; i < rowBlocks.length; i++) {
- newRow[i] = rowBlocks[i];
- }
- BlockLink.blockArry[row] = newRow;
- for (let col = 0; col < this.mapConfig.cols; col++) {
- const block = BlockLink.blockArry[row][col];
- if (block) {
- const newX = this.mapConfig.gridOrigin.x + col * this.mapConfig.spacing;
- const newY = this.mapConfig.gridOrigin.y - row * this.mapConfig.spacing;
- tween(block)
- .to(0.2, { position: v3(newX, newY, 0) })
- .call(() => {
- this.isMoving = false;
- })
- .start();
- }
- }
- }
- }
- private moveAllRight() {
- this.isMoving = true;
- for (let row = 0; row < this.mapConfig.rows; row++) {
- const originalRow = [...BlockLink.blockArry[row]];
- const blocksInRow = originalRow.filter(block => block !== null);
- const startCol = this.mapConfig.cols - blocksInRow.length;
- const newRow = new Array(this.mapConfig.cols).fill(null);
- for (let i = 0; i < blocksInRow.length; i++) {
- newRow[startCol + i] = blocksInRow[i];
- }
- BlockLink.blockArry[row] = newRow;
- for (let col = 0; col < this.mapConfig.cols; col++) {
- const block = BlockLink.blockArry[row][col];
- if (block) {
- const newX = this.mapConfig.gridOrigin.x + col * this.mapConfig.spacing;
- const newY = this.mapConfig.gridOrigin.y - row * this.mapConfig.spacing;
- tween(block)
- .to(0.2, { position: v3(newX, newY, 0) })
- .call(() => {
- this.isMoving = false;
- })
- .start();
- }
- }
- }
- }
- /**上移 */
- private moveAllUp() {
- this.isMoving = true;
- for (let col = 0; col < this.mapConfig.cols; col++) {
- const blocksInCol = BlockLink.blockArry.map(row => row[col]).filter(block => block !== null);
- BlockLink.blockArry.forEach(row => row[col] = null);
- const startRow = 0;
- for (let row = 0; row < blocksInCol.length; row++) {
- const block = blocksInCol[row];
- BlockLink.blockArry[startRow + row][col] = block;
- const newX = this.mapConfig.gridOrigin.x + col * this.mapConfig.spacing;
- const newY = this.mapConfig.gridOrigin.y - (startRow + row) * this.mapConfig.spacing;
- tween(block)
- .to(0.2, { position: v3(newX, newY, 0) })
- .call(() => {
- this.isMoving = false;
- })
- .start();
- }
- }
- }
- /**下移 */
- private moveAllDown() {
- this.isMoving = true;
- for (let col = 0; col < this.mapConfig.cols; col++) {
- const blocksInCol = BlockLink.blockArry.map(row => row[col]).filter(block => block !== null);
- BlockLink.blockArry.forEach(row => row[col] = null);
- const startRow = this.mapConfig.rows - blocksInCol.length;
- for (let row = 0; row < blocksInCol.length; row++) {
- const block = blocksInCol[row];
- BlockLink.blockArry[startRow + row][col] = block;
- const newX = this.mapConfig.gridOrigin.x + col * this.mapConfig.spacing;
- const newY = this.mapConfig.gridOrigin.y - (startRow + row) * this.mapConfig.spacing;
- tween(block)
- .to(0.2, { position: v3(newX, newY, 0) })
- .call(() => {
- this.isMoving = false;
- })
- .start();
- }
- }
- }
- /** 移动到中心 */
- private moveToCenter(isHorizontal: boolean) {
- this.isMoving = true;
- if (isHorizontal) {
- for (let row = 0; row < this.mapConfig.rows; row++) {
- const blocks = BlockLink.blockArry[row].filter(b => b !== null);
- const startCol = Math.floor((this.mapConfig.cols - blocks.length) / 2);
- BlockLink.blockArry[row].fill(null);
- blocks.forEach((block, idx) => {
- const targetCol = startCol + idx;
- BlockLink.blockArry[row][targetCol] = block;
- const newX = this.mapConfig.gridOrigin.x + targetCol * this.mapConfig.spacing;
- const newY = this.mapConfig.gridOrigin.y - row * this.mapConfig.spacing;
- tween(block)
- .to(0.2, { position: v3(newX, newY, 0) })
- .call(() => {
- this.isMoving = false;
- })
- .start();
- });
- }
- } else {
- for (let col = 0; col < this.mapConfig.cols; col++) {
- const blocks = BlockLink.blockArry.map(row => row[col]).filter(b => b !== null);
- const startRow = Math.floor((this.mapConfig.rows - blocks.length) / 2);
- BlockLink.blockArry.forEach(row => row[col] = null);
- blocks.forEach((block, idx) => {
- const targetRow = startRow + idx;
- BlockLink.blockArry[targetRow][col] = block;
- const newX = this.mapConfig.gridOrigin.x + col * this.mapConfig.spacing;
- const newY = this.mapConfig.gridOrigin.y - targetRow * this.mapConfig.spacing;
- tween(block)
- .to(0.2, { position: v3(newX, newY, 0) })
- .call(() => {
- this.isMoving = false;
- })
- .start();
- });
- }
- }
- }
- /** 从中心移出 */
- private moveFromCenter(isHorizontal: boolean) {
- this.isMoving = true;
- if (isHorizontal) {
- for (let row = 0; row < this.mapConfig.rows; row++) {
- const leftBlocks = [];
- const rightBlocks = [];
- const centerCol = Math.floor(this.mapConfig.cols / 2);
- for (let col = 0; col < centerCol; col++) {
- if (BlockLink.blockArry[row][col]) {
- leftBlocks.push({ block: BlockLink.blockArry[row][col], originalCol: col });
- }
- }
- for (let col = centerCol; col < this.mapConfig.cols; col++) {
- if (BlockLink.blockArry[row][col]) {
- rightBlocks.push({ block: BlockLink.blockArry[row][col], originalCol: col });
- }
- }
- BlockLink.blockArry[row].fill(null);
- leftBlocks.sort((a, b) => a.originalCol - b.originalCol);
- for (let i = 0; i < leftBlocks.length; i++) {
- const block = leftBlocks[i].block;
- const targetCol = i;
- BlockLink.blockArry[row][targetCol] = block;
- const newX = this.mapConfig.gridOrigin.x + targetCol * this.mapConfig.spacing;
- const newY = this.mapConfig.gridOrigin.y - row * this.mapConfig.spacing;
- tween(block)
- .to(0.2, { position: v3(newX, newY, 0) })
- .call(() => {
- this.isMoving = false;
- })
- .start();
- }
- rightBlocks.sort((a, b) => b.originalCol - a.originalCol);
- for (let i = 0; i < rightBlocks.length; i++) {
- const block = rightBlocks[i].block;
- const targetCol = this.mapConfig.cols - 1 - i;
- BlockLink.blockArry[row][targetCol] = block;
- const newX = this.mapConfig.gridOrigin.x + targetCol * this.mapConfig.spacing;
- const newY = this.mapConfig.gridOrigin.y - row * this.mapConfig.spacing;
- tween(block)
- .to(0.2, { position: v3(newX, newY, 0) })
- .call(() => {
- this.isMoving = false;
- })
- .start();
- }
- }
- } else {
- for (let col = 0; col < this.mapConfig.cols; col++) {
- const topBlocks = [];
- const bottomBlocks = [];
- for (let row = 0; row < 5; row++) {
- if (BlockLink.blockArry[row][col]) {
- topBlocks.push({ block: BlockLink.blockArry[row][col], originalRow: row });
- }
- }
- for (let row = 5; row < this.mapConfig.rows; row++) {
- if (BlockLink.blockArry[row][col]) {
- bottomBlocks.push({ block: BlockLink.blockArry[row][col], originalRow: row });
- }
- }
- BlockLink.blockArry.forEach(row => row[col] = null);
- topBlocks.sort((a, b) => a.originalRow - b.originalRow);
- for (let i = 0; i < topBlocks.length; i++) {
- const block = topBlocks[i].block;
- const targetRow = i;
- BlockLink.blockArry[targetRow][col] = block;
- const newX = this.mapConfig.gridOrigin.x + col * this.mapConfig.spacing;
- const newY = this.mapConfig.gridOrigin.y - targetRow * this.mapConfig.spacing;
- tween(block)
- .to(0.2, { position: v3(newX, newY, 0) })
- .call(() => {
- this.isMoving = false;
- })
- .start();
- }
- bottomBlocks.sort((a, b) => b.originalRow - a.originalRow);
- for (let i = 0; i < bottomBlocks.length; i++) {
- const block = bottomBlocks[i].block;
- const targetRow = this.mapConfig.rows - 1 - i;
- BlockLink.blockArry[targetRow][col] = block;
- const newX = this.mapConfig.gridOrigin.x + col * this.mapConfig.spacing;
- const newY = this.mapConfig.gridOrigin.y - targetRow * this.mapConfig.spacing;
- tween(block)
- .to(0.2, { position: v3(newX, newY, 0) })
- .call(() => {
- this.isMoving = false;
- })
- .start();
- }
- }
- }
- }
- }
|