From 83b23cf958954b3de4aa1f3ca29a4485bc7a8cfd Mon Sep 17 00:00:00 2001 From: "COMPUTER\\EDY" <249929363@qq.com> Date: Thu, 2 Jul 2026 19:51:52 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=20=E7=A2=B0=E6=92=9E?= =?UTF-8?q?=E6=A3=80=E6=B5=8B=20=EF=BC=8C=E9=81=BF=E5=85=8D=E7=A9=BF?= =?UTF-8?q?=E6=A8=A1=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/Script/Block.ts | 265 +++++++++++++++++++++- assets/Script/module/Config/GameConfig.ts | 2 +- 2 files changed, 258 insertions(+), 9 deletions(-) diff --git a/assets/Script/Block.ts b/assets/Script/Block.ts index 5af29c6..4706ccf 100644 --- a/assets/Script/Block.ts +++ b/assets/Script/Block.ts @@ -125,6 +125,13 @@ export default class Block extends cc.Component { private lastMoveTime = 0; /*最大移动速度 - 限制方块跟随手指的最大距离,防止移动过快*/ private maxSpeed = 300; + /*拖动碰撞缓存 - 仅缓存本次拖动涉及的方块,减少移动热路径中的组件查找和临时对象*/ + private dragGroupNodes: cc.Node[] = []; + private dragObstacleCells: any[] = []; + private lastSafeDragPositions: any[] = []; + /*地图格子间距为120;116与现有边缘碰撞器的有效阻挡距离一致*/ + private readonly dragCellSize: number = 120; + private readonly dragCollisionDistance: number = 116; // ============================================ // Cocos Creator 属性定义 @@ -1556,6 +1563,7 @@ export default class Block extends cc.Component { this.isTouch = true; this.moveCorner = 0; this.relative_Position = cc.v2(this.node.x - local.x, this.node.y - local.y); + this.prepareDragCollisionState(); if (this.block_Info.floor == undefined && this.flowerType != 2) { MapConroler._instance.changeRiseFall(this.color, true); if (this.block_Info.lock != undefined && this.block_Info.lock != null && this.type != BlockType.单色地块) { @@ -1638,6 +1646,7 @@ export default class Block extends cc.Component { touchEnd(event) { MapConroler._instance.touchIng = false; if (MapConroler._instance.gameOver) { + this.clearDragCollisionState(); return; } let Simulate = { @@ -1645,8 +1654,11 @@ export default class Block extends cc.Component { direction: 0, }; if (this.isTouch) { - - + // 松手前重新构建一次障碍缓存。若外部状态在拖动期间变化,仍回退到最后合法位置。 + this.refreshDragObstacleCells(); + if (this.wouldDragGroupOverlap(0, 0)) { + this.restoreLastSafeDragPositions(); + } // //先检测 是否有块在障碍物上,如果有回归位置 let jg = this.resetStartPos(); let otherCanJg = false; @@ -1746,8 +1758,7 @@ export default class Block extends cc.Component { } } } - - + this.clearDragCollisionState(); } // ============================================ @@ -1777,6 +1788,7 @@ export default class Block extends cc.Component { MapConroler._instance.changeRiseFall(this.color, false); MapConroler._instance.removeOneBlock(); this.isTouch = false; + this.clearDragCollisionState(); if (this.type != BlockType.单色地块) this.node.zIndex = this.level; // else this.node.zIndex = 1000; this.hit.active = false; @@ -1831,6 +1843,186 @@ export default class Block extends cc.Component { } } + /** + * 建立一次拖动期间使用的轻量碰撞缓存。 + * 主方块、粘合块、叠加块和可移动地板队伍会被当成一个整体移动。 + */ + private prepareDragCollisionState() { + this.dragGroupNodes = []; + this.addDragGroupNode(this.node); + + if ((this.type === BlockType.叠加块下 || this.type === BlockType.粘合块) && + this.block_Info && this.block_Info.node) { + this.addDragGroupNode(this.block_Info.node); + } + + if (this.moveFloorPd === true && this.teamBlocks && this.teamBlocks.length > 1) { + for (let i = 0; i < this.teamBlocks.length; i++) { + this.addDragGroupNode(this.teamBlocks[i]); + } + } + + this.refreshDragObstacleCells(); + this.saveLastSafeDragPositions(true); + } + + private addDragGroupNode(node: cc.Node) { + if (!node || !cc.isValid(node)) return; + for (let i = 0; i < this.dragGroupNodes.length; i++) { + if (this.dragGroupNodes[i].uuid === node.uuid) return; + } + this.dragGroupNodes.push(node); + } + + /** + * 方块在同一父节点下移动,因此使用本地坐标即可比较。 + * 障碍格中心在拖动开始时展开并缓存,热路径中不再反复getComponent或创建Vec2。 + */ + private refreshDragObstacleCells() { + this.dragObstacleCells = []; + if (!this.node || !this.node.parent) return; + + const groupMap: { [uuid: string]: boolean } = {}; + for (let i = 0; i < this.dragGroupNodes.length; i++) { + const node = this.dragGroupNodes[i]; + if (node && cc.isValid(node)) groupMap[node.uuid] = true; + } + + const children = this.node.parent.children; + for (let i = 0; i < children.length; i++) { + const node = children[i]; + if (!node || !cc.isValid(node) || !node.activeInHierarchy || groupMap[node.uuid]) continue; + + const block = node.getComponent("Block"); + if (!block || block.over || block.type === BlockType.叠加块上 || + !block.allBlocks || block.allBlocks.length === 0) { + continue; + } + + for (let j = 0; j < block.allBlocks.length; j++) { + const cell = block.allBlocks[j]; + this.dragObstacleCells.push({ + x: node.x - 60 + cell.x * this.dragCellSize, + y: node.y + 60 + cell.y * this.dragCellSize, + block: block + }); + } + } + } + + /** 保持“单色地块与同色普通块可互相穿过”的原有规则。 */ + private ignoreDragBlockCollision(movingBlock: any, obstacleBlock: any): boolean { + if (!movingBlock || !obstacleBlock) return true; + const oneIsSingleColor = (movingBlock.type === BlockType.单色地块) !== + (obstacleBlock.type === BlockType.单色地块); + return oneIsSingleColor && movingBlock.color === obstacleBlock.color && + obstacleBlock.block_Info && obstacleBlock.block_Info.floor === undefined; + } + + /** + * 判断整个拖动组合体按指定增量移动后,是否会与其他方块的实体格重叠。 + * 这里只处理方块对方块;墙、门和其他机关继续沿用现有LQ碰撞规则。 + */ + private wouldDragGroupOverlap(offsetX: number, offsetY: number): boolean { + if (!this.dragGroupNodes || this.dragGroupNodes.length === 0) return false; + + const minDistance = this.dragCollisionDistance; + for (let i = 0; i < this.dragGroupNodes.length; i++) { + const node = this.dragGroupNodes[i]; + if (!node || !cc.isValid(node)) continue; + const movingBlock = node.getComponent("Block"); + // 叠加块上层仅负责视觉跟随,原碰撞器也是关闭状态,不作为实体重复计算。 + if (!movingBlock || movingBlock.type === BlockType.叠加块上 || !movingBlock.allBlocks) continue; + + for (let j = 0; j < movingBlock.allBlocks.length; j++) { + const movingCell = movingBlock.allBlocks[j]; + const centerX = node.x + offsetX - 60 + movingCell.x * this.dragCellSize; + const centerY = node.y + offsetY + 60 + movingCell.y * this.dragCellSize; + + for (let k = 0; k < this.dragObstacleCells.length; k++) { + const obstacle = this.dragObstacleCells[k]; + if (this.ignoreDragBlockCollision(movingBlock, obstacle.block)) continue; + if (Math.abs(centerX - obstacle.x) < minDistance && + Math.abs(centerY - obstacle.y) < minDistance) { + return true; + } + } + } + } + return false; + } + + /** + * 当前整步会重叠时,用少量二分检测逼近边界,而不是直接丢弃整步。 + * 只有即将碰撞时才进入该分支,因此正常拖动没有额外开销。 + */ + private getSafeDragAxisOffset(offsetX: number, offsetY: number): number { + const requestedOffset = offsetX !== 0 ? offsetX : offsetY; + if (requestedOffset === 0 || !this.wouldDragGroupOverlap(offsetX, offsetY)) { + return requestedOffset; + } + + let safeRatio = 0; + let blockedRatio = 1; + for (let i = 0; i < 6; i++) { + const ratio = (safeRatio + blockedRatio) * 0.5; + if (this.wouldDragGroupOverlap(offsetX * ratio, offsetY * ratio)) { + blockedRatio = ratio; + } else { + safeRatio = ratio; + } + } + return requestedOffset * safeRatio; + } + + /** 同步组合方块。使用实际位移增量,不改变它们原有的相对位置。 */ + private moveDragGroupBy(offsetX: number, offsetY: number) { + if (offsetX === 0 && offsetY === 0) return; + for (let i = 0; i < this.dragGroupNodes.length; i++) { + const node = this.dragGroupNodes[i]; + if (!node || !cc.isValid(node) || node.uuid === this.node.uuid) continue; + node.x += offsetX; + node.y += offsetY; + } + } + + private saveLastSafeDragPositions(reset: boolean = false) { + if (reset || this.lastSafeDragPositions.length !== this.dragGroupNodes.length) { + this.lastSafeDragPositions = []; + for (let i = 0; i < this.dragGroupNodes.length; i++) { + const node = this.dragGroupNodes[i]; + if (node && cc.isValid(node)) { + this.lastSafeDragPositions.push({ node: node, x: node.x, y: node.y }); + } + } + return; + } + + for (let i = 0; i < this.lastSafeDragPositions.length; i++) { + const info = this.lastSafeDragPositions[i]; + if (info.node && cc.isValid(info.node)) { + info.x = info.node.x; + info.y = info.node.y; + } + } + } + + private restoreLastSafeDragPositions() { + for (let i = 0; i < this.lastSafeDragPositions.length; i++) { + const info = this.lastSafeDragPositions[i]; + if (info.node && cc.isValid(info.node)) { + info.node.x = info.x; + info.node.y = info.y; + } + } + } + + private clearDragCollisionState() { + this.dragGroupNodes = []; + this.dragObstacleCells = []; + this.lastSafeDragPositions = []; + } + // ============================================ // 重置方块起始位置方法 // 功能:检测方块当前位置是否有效,如果无效则需要回归原位 @@ -2992,6 +3184,9 @@ export default class Block extends cc.Component { // ============================================ update(dt: number) { if (this.isTouch && this.touchDelta.mag() > 0) { + if (this.dragGroupNodes.length === 0) { + this.prepareDragCollisionState(); + } //this.moveLeft = this.moveRight = this.moveUp = this.moveDown = true; const delta = this.touchDelta; const newX = this.node.x + delta.x; @@ -3040,8 +3235,11 @@ export default class Block extends cc.Component { for (let index = 0; index < mag; index++) { this.moveCorner = 0; + const previousX = this.node.x; + const previousY = this.node.y; const tempX = this.node.x + stepx; const tempY = this.node.y + stepy; + const preferX = Math.abs(stepx) > Math.abs(stepy); if (!this.checkCollision) { if (this.type !== 8 && this.type !== 10) { @@ -3056,8 +3254,7 @@ export default class Block extends cc.Component { } } } else { - const isXMain = Math.abs(stepx) > Math.abs(stepy); - if (isXMain) { + if (preferX) { if (this.node.x > tempX) { if (this.moveLeft && this.moveX === 0 && this.type !== 8 && this.type !== 10) { if (this.block_Info.vertical == undefined) { @@ -3139,7 +3336,61 @@ export default class Block extends cc.Component { } } } + + // 上面的旧逻辑负责方向、机关和特殊方块限制;这里将结果改为“检测后提交”。 + // X/Y分轴处理,碰到角落时只截断受阻轴,另一轴仍能继续跟随手指滑动。 + const requestedX = this.node.x; + const requestedY = this.node.y; + this.node.x = previousX; + this.node.y = previousY; + + if (preferX) { + const offsetX = requestedX - previousX; + const safeOffsetX = this.getSafeDragAxisOffset(offsetX, 0); + if (safeOffsetX !== 0) { + this.node.x = previousX + safeOffsetX; + this.moveDragGroupBy(safeOffsetX, 0); + } + const offsetY = requestedY - previousY; + const safeOffsetY = this.getSafeDragAxisOffset(0, offsetY); + if (safeOffsetY !== 0) { + this.node.y = previousY + safeOffsetY; + this.moveDragGroupBy(0, safeOffsetY); + } + } else { + const offsetY = requestedY - previousY; + const safeOffsetY = this.getSafeDragAxisOffset(0, offsetY); + if (safeOffsetY !== 0) { + this.node.y = previousY + safeOffsetY; + this.moveDragGroupBy(0, safeOffsetY); + } + const offsetX = requestedX - previousX; + const safeOffsetX = this.getSafeDragAxisOffset(offsetX, 0); + if (safeOffsetX !== 0) { + this.node.x = previousX + safeOffsetX; + this.moveDragGroupBy(safeOffsetX, 0); + } + } + + let movedX = this.node.x - previousX; + let movedY = this.node.y - previousY; LQCollideSystem.update_logic(dt); + + // LQ碰撞在坐标更新后回调。若本步撞到墙/门/机关,只回滚对应轴。 + if ((movedX < 0 && !this.moveLeft) || (movedX > 0 && !this.moveRight)) { + this.node.x -= movedX; + this.moveDragGroupBy(-movedX, 0); + movedX = 0; + } + if ((movedY < 0 && !this.moveDown) || (movedY > 0 && !this.moveUp)) { + this.node.y -= movedY; + this.moveDragGroupBy(0, -movedY); + movedY = 0; + } + + if ((movedX !== 0 || movedY !== 0) && !this.wouldDragGroupOverlap(0, 0)) { + this.saveLastSafeDragPositions(); + } } // 移动完成后重置触摸增量 this.touchDelta = cc.v2(0, 0); @@ -3166,7 +3417,6 @@ export default class Block extends cc.Component { if (this.block_Info.node.getComponent("Block")) { if (this.isTouch == true && this.block_Info.node.getComponent("Block").isTouch == false) { // console.log("队友跟着走"); - LQCollideSystem.update_logic(dt); this.block_Info.node.x = this.node.x - this.adhesive.x; this.block_Info.node.y = this.node.y - this.adhesive.y; } @@ -3184,7 +3434,6 @@ export default class Block extends cc.Component { if (this.teamBlocks[i]) { if (this.teamBlocks[i].getComponent("Block")) { if (this.teamBlocks[i].uuid != this.node.uuid && this.isTouch == true && this.teamBlocks[i].getComponent("Block").isTouch == false) { - LQCollideSystem.update_logic(dt); this.teamBlocks[i].x = this.node.x - this.floorOffset[i].x; this.teamBlocks[i].y = this.node.y - this.floorOffset[i].y; } diff --git a/assets/Script/module/Config/GameConfig.ts b/assets/Script/module/Config/GameConfig.ts index dbd9655..a33a45a 100644 --- a/assets/Script/module/Config/GameConfig.ts +++ b/assets/Script/module/Config/GameConfig.ts @@ -302,7 +302,7 @@ export class GameConfig { vibrateOpen: true, //震动 coinnum: 0, //每局的金币数 paid_user: false, //是否是付费用户 - version: "1.9.92", //版本号 + version: "1.9.93", //版本号 shushu_DistinctId: "", //数数访客ID shushu_AccountId: "", //数数账号ID uid: "", //用户和后端唯一id