优化 碰撞检测 ,避免穿模问题
This commit is contained in:
parent
e614279f1f
commit
83b23cf958
|
|
@ -125,6 +125,13 @@ export default class Block extends cc.Component {
|
||||||
private lastMoveTime = 0;
|
private lastMoveTime = 0;
|
||||||
/*最大移动速度 - 限制方块跟随手指的最大距离,防止移动过快*/
|
/*最大移动速度 - 限制方块跟随手指的最大距离,防止移动过快*/
|
||||||
private maxSpeed = 300;
|
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 属性定义
|
// Cocos Creator 属性定义
|
||||||
|
|
@ -1556,6 +1563,7 @@ export default class Block extends cc.Component {
|
||||||
this.isTouch = true;
|
this.isTouch = true;
|
||||||
this.moveCorner = 0;
|
this.moveCorner = 0;
|
||||||
this.relative_Position = cc.v2(this.node.x - local.x, this.node.y - local.y);
|
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) {
|
if (this.block_Info.floor == undefined && this.flowerType != 2) {
|
||||||
MapConroler._instance.changeRiseFall(this.color, true);
|
MapConroler._instance.changeRiseFall(this.color, true);
|
||||||
if (this.block_Info.lock != undefined && this.block_Info.lock != null && this.type != BlockType.单色地块) {
|
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) {
|
touchEnd(event) {
|
||||||
MapConroler._instance.touchIng = false;
|
MapConroler._instance.touchIng = false;
|
||||||
if (MapConroler._instance.gameOver) {
|
if (MapConroler._instance.gameOver) {
|
||||||
|
this.clearDragCollisionState();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let Simulate = {
|
let Simulate = {
|
||||||
|
|
@ -1645,8 +1654,11 @@ export default class Block extends cc.Component {
|
||||||
direction: 0,
|
direction: 0,
|
||||||
};
|
};
|
||||||
if (this.isTouch) {
|
if (this.isTouch) {
|
||||||
|
// 松手前重新构建一次障碍缓存。若外部状态在拖动期间变化,仍回退到最后合法位置。
|
||||||
|
this.refreshDragObstacleCells();
|
||||||
|
if (this.wouldDragGroupOverlap(0, 0)) {
|
||||||
|
this.restoreLastSafeDragPositions();
|
||||||
|
}
|
||||||
// //先检测 是否有块在障碍物上,如果有回归位置
|
// //先检测 是否有块在障碍物上,如果有回归位置
|
||||||
let jg = this.resetStartPos();
|
let jg = this.resetStartPos();
|
||||||
let otherCanJg = false;
|
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.changeRiseFall(this.color, false);
|
||||||
MapConroler._instance.removeOneBlock();
|
MapConroler._instance.removeOneBlock();
|
||||||
this.isTouch = false;
|
this.isTouch = false;
|
||||||
|
this.clearDragCollisionState();
|
||||||
if (this.type != BlockType.单色地块) this.node.zIndex = this.level;
|
if (this.type != BlockType.单色地块) this.node.zIndex = this.level;
|
||||||
// else this.node.zIndex = 1000;
|
// else this.node.zIndex = 1000;
|
||||||
this.hit.active = false;
|
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) {
|
update(dt: number) {
|
||||||
if (this.isTouch && this.touchDelta.mag() > 0) {
|
if (this.isTouch && this.touchDelta.mag() > 0) {
|
||||||
|
if (this.dragGroupNodes.length === 0) {
|
||||||
|
this.prepareDragCollisionState();
|
||||||
|
}
|
||||||
//this.moveLeft = this.moveRight = this.moveUp = this.moveDown = true;
|
//this.moveLeft = this.moveRight = this.moveUp = this.moveDown = true;
|
||||||
const delta = this.touchDelta;
|
const delta = this.touchDelta;
|
||||||
const newX = this.node.x + delta.x;
|
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++) {
|
for (let index = 0; index < mag; index++) {
|
||||||
this.moveCorner = 0;
|
this.moveCorner = 0;
|
||||||
|
const previousX = this.node.x;
|
||||||
|
const previousY = this.node.y;
|
||||||
const tempX = this.node.x + stepx;
|
const tempX = this.node.x + stepx;
|
||||||
const tempY = this.node.y + stepy;
|
const tempY = this.node.y + stepy;
|
||||||
|
const preferX = Math.abs(stepx) > Math.abs(stepy);
|
||||||
|
|
||||||
if (!this.checkCollision) {
|
if (!this.checkCollision) {
|
||||||
if (this.type !== 8 && this.type !== 10) {
|
if (this.type !== 8 && this.type !== 10) {
|
||||||
|
|
@ -3056,8 +3254,7 @@ export default class Block extends cc.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const isXMain = Math.abs(stepx) > Math.abs(stepy);
|
if (preferX) {
|
||||||
if (isXMain) {
|
|
||||||
if (this.node.x > tempX) {
|
if (this.node.x > tempX) {
|
||||||
if (this.moveLeft && this.moveX === 0 && this.type !== 8 && this.type !== 10) {
|
if (this.moveLeft && this.moveX === 0 && this.type !== 8 && this.type !== 10) {
|
||||||
if (this.block_Info.vertical == undefined) {
|
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);
|
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);
|
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.block_Info.node.getComponent("Block")) {
|
||||||
if (this.isTouch == true && this.block_Info.node.getComponent("Block").isTouch == false) {
|
if (this.isTouch == true && this.block_Info.node.getComponent("Block").isTouch == false) {
|
||||||
// console.log("队友跟着走");
|
// console.log("队友跟着走");
|
||||||
LQCollideSystem.update_logic(dt);
|
|
||||||
this.block_Info.node.x = this.node.x - this.adhesive.x;
|
this.block_Info.node.x = this.node.x - this.adhesive.x;
|
||||||
this.block_Info.node.y = this.node.y - this.adhesive.y;
|
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]) {
|
||||||
if (this.teamBlocks[i].getComponent("Block")) {
|
if (this.teamBlocks[i].getComponent("Block")) {
|
||||||
if (this.teamBlocks[i].uuid != this.node.uuid && this.isTouch == true && this.teamBlocks[i].getComponent("Block").isTouch == false) {
|
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].x = this.node.x - this.floorOffset[i].x;
|
||||||
this.teamBlocks[i].y = this.node.y - this.floorOffset[i].y;
|
this.teamBlocks[i].y = this.node.y - this.floorOffset[i].y;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -302,7 +302,7 @@ export class GameConfig {
|
||||||
vibrateOpen: true, //震动
|
vibrateOpen: true, //震动
|
||||||
coinnum: 0, //每局的金币数
|
coinnum: 0, //每局的金币数
|
||||||
paid_user: false, //是否是付费用户
|
paid_user: false, //是否是付费用户
|
||||||
version: "1.9.92", //版本号
|
version: "1.9.93", //版本号
|
||||||
shushu_DistinctId: "", //数数访客ID
|
shushu_DistinctId: "", //数数访客ID
|
||||||
shushu_AccountId: "", //数数账号ID
|
shushu_AccountId: "", //数数账号ID
|
||||||
uid: "", //用户和后端唯一id
|
uid: "", //用户和后端唯一id
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user