|
|
@@ -265,6 +265,7 @@ export class GameBlockSelection extends Component {
|
|
|
private currentDragBlock: Node | null = null;
|
|
|
private startPos = new Vec2();
|
|
|
private blockStartPos: Vec3 = new Vec3();
|
|
|
+ private activeTouchId: number | null = null;
|
|
|
|
|
|
// 调试绘制相关属性
|
|
|
@property({
|
|
|
@@ -382,6 +383,8 @@ export class GameBlockSelection extends Component {
|
|
|
|
|
|
// 监听重置方块选择事件
|
|
|
eventBus.on(GameEvents.RESET_BLOCK_SELECTION, this.onResetBlockSelectionEvent, this);
|
|
|
+ // 监听全局UI重置事件,确保按钮视觉状态恢复
|
|
|
+ eventBus.on(GameEvents.RESET_UI_STATES, this.onResetUIStatesEvent, this);
|
|
|
// 监听游戏开始事件,用于标记可以开始生成方块
|
|
|
eventBus.on(GameEvents.GAME_START, this.onGameStartEvent, this);
|
|
|
|
|
|
@@ -402,6 +405,18 @@ export class GameBlockSelection extends Component {
|
|
|
// 处理重置方块选择事件
|
|
|
private onResetBlockSelectionEvent() {
|
|
|
this.resetSelection();
|
|
|
+ // 恢复按钮颜色与交互状态,并清理颜色缓存,避免跨关卡残留
|
|
|
+ this.applyGuideDisabledVisual(this.addCoinButton, false);
|
|
|
+ this.applyGuideDisabledVisual(this.refreshButton, false);
|
|
|
+ this.originalButtonColors.clear();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理全局UI重置事件(返回主界面或关卡结束时)
|
|
|
+ private onResetUIStatesEvent() {
|
|
|
+ // 恢复按钮颜色与交互状态,并清理颜色缓存,避免跨关卡残留
|
|
|
+ this.applyGuideDisabledVisual(this.addCoinButton, false);
|
|
|
+ this.applyGuideDisabledVisual(this.refreshButton, false);
|
|
|
+ this.originalButtonColors.clear();
|
|
|
}
|
|
|
// 处理游戏开始事件
|
|
|
private onGameStartEvent() {
|
|
|
@@ -980,6 +995,11 @@ export class GameBlockSelection extends Component {
|
|
|
// 设置方块拖拽事件
|
|
|
public setupBlockDragEvents(block: Node) {
|
|
|
block.on(Node.EventType.TOUCH_START, (event: EventTouch) => {
|
|
|
+ // 仅处理首个触点,过滤其他触点事件
|
|
|
+ const touchId = this.getTouchId(event);
|
|
|
+ if (this.activeTouchId !== null && this.activeTouchId !== touchId) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
// 检查游戏是否已开始
|
|
|
if (!this.blockManager.gameStarted) {
|
|
|
return;
|
|
|
@@ -999,6 +1019,8 @@ export class GameBlockSelection extends Component {
|
|
|
|
|
|
// grid区域的方块目前允许自由移动
|
|
|
|
|
|
+ // 绑定当前拖拽手指ID
|
|
|
+ this.activeTouchId = touchId;
|
|
|
this.currentDragBlock = block;
|
|
|
this.startPos = event.getUILocation();
|
|
|
this.blockStartPos.set(block.position);
|
|
|
@@ -1024,6 +1046,11 @@ export class GameBlockSelection extends Component {
|
|
|
}, this);
|
|
|
|
|
|
block.on(Node.EventType.TOUCH_MOVE, (event: EventTouch) => {
|
|
|
+ // 只处理与当前绑定触点一致的移动事件
|
|
|
+ const touchId = this.getTouchId(event);
|
|
|
+ if (this.activeTouchId !== touchId) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
// 检查游戏是否已开始
|
|
|
if (!this.blockManager.gameStarted) {
|
|
|
return;
|
|
|
@@ -1043,14 +1070,48 @@ export class GameBlockSelection extends Component {
|
|
|
const deltaX = location.x - this.startPos.x;
|
|
|
const deltaY = location.y - this.startPos.y;
|
|
|
|
|
|
- this.currentDragBlock.position = new Vec3(
|
|
|
+ // 目标位置(本地坐标)
|
|
|
+ const targetLocal = new Vec3(
|
|
|
this.blockStartPos.x + deltaX,
|
|
|
this.blockStartPos.y + deltaY,
|
|
|
this.blockStartPos.z
|
|
|
);
|
|
|
+
|
|
|
+ const parentTransform = this.currentDragBlock.parent ? this.currentDragBlock.parent.getComponent(UITransform) : null;
|
|
|
+ const targetWorld = parentTransform ? parentTransform.convertToWorldSpaceAR(targetLocal) : targetLocal.clone();
|
|
|
+
|
|
|
+ // GameArea 边界夹紧(仅在目标点位于 GameArea 内部时进行夹紧)
|
|
|
+ const gameAreaNode = find('Canvas/GameLevelUI/GameArea');
|
|
|
+ const gameAreaTransform = gameAreaNode ? gameAreaNode.getComponent(UITransform) : null;
|
|
|
+ if (gameAreaTransform) {
|
|
|
+ const bounds = gameAreaTransform.getBoundingBoxToWorld();
|
|
|
+ const inside = bounds.contains(new Vec2(targetWorld.x, targetWorld.y));
|
|
|
+ if (inside && parentTransform) {
|
|
|
+ const minX = bounds.x;
|
|
|
+ const maxX = bounds.x + bounds.width;
|
|
|
+ const minY = bounds.y;
|
|
|
+ const maxY = bounds.y + bounds.height;
|
|
|
+ const clampedWorld = new Vec3(
|
|
|
+ Math.min(Math.max(targetWorld.x, minX), maxX),
|
|
|
+ Math.min(Math.max(targetWorld.y, minY), maxY),
|
|
|
+ targetWorld.z
|
|
|
+ );
|
|
|
+ const clampedLocal = parentTransform.convertToNodeSpaceAR(clampedWorld);
|
|
|
+ this.currentDragBlock.position = clampedLocal;
|
|
|
+ } else {
|
|
|
+ this.currentDragBlock.position = targetLocal;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.currentDragBlock.position = targetLocal;
|
|
|
+ }
|
|
|
}, this);
|
|
|
|
|
|
block.on(Node.EventType.TOUCH_END, async (event: EventTouch) => {
|
|
|
+ // 只处理与当前绑定触点一致的结束事件
|
|
|
+ const touchId = this.getTouchId(event);
|
|
|
+ if (this.activeTouchId !== null && this.activeTouchId !== touchId) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
// 检查游戏是否已开始
|
|
|
if (!this.blockManager.gameStarted) {
|
|
|
return;
|
|
|
@@ -1083,10 +1144,16 @@ export class GameBlockSelection extends Component {
|
|
|
|
|
|
// 通知BallController方块拖拽结束
|
|
|
EventBus.getInstance().emit(GameEvents.BLOCK_DRAG_END, { block: block });
|
|
|
+ // 释放触点绑定
|
|
|
+ this.activeTouchId = null;
|
|
|
}
|
|
|
}, this);
|
|
|
|
|
|
- block.on(Node.EventType.TOUCH_CANCEL, () => {
|
|
|
+ block.on(Node.EventType.TOUCH_CANCEL, (event: EventTouch) => {
|
|
|
+ const touchId = this.getTouchId(event);
|
|
|
+ if (this.activeTouchId !== null && this.activeTouchId !== touchId) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
if (this.currentDragBlock) {
|
|
|
this.returnBlockToOriginalPosition();
|
|
|
|
|
|
@@ -1100,6 +1167,8 @@ export class GameBlockSelection extends Component {
|
|
|
|
|
|
// 通知BallController方块拖拽结束
|
|
|
EventBus.getInstance().emit(GameEvents.BLOCK_DRAG_END, { block: block });
|
|
|
+ // 释放触点绑定
|
|
|
+ this.activeTouchId = null;
|
|
|
}
|
|
|
}, this);
|
|
|
}
|
|
|
@@ -1164,6 +1233,8 @@ export class GameBlockSelection extends Component {
|
|
|
|
|
|
// 清理拖拽状态
|
|
|
this.currentDragBlock = null;
|
|
|
+ // 释放触点绑定
|
|
|
+ this.activeTouchId = null;
|
|
|
}
|
|
|
|
|
|
// 刷新方块占用情况
|
|
|
@@ -1580,6 +1651,7 @@ export class GameBlockSelection extends Component {
|
|
|
private removeEventListeners() {
|
|
|
const eventBus = EventBus.getInstance();
|
|
|
eventBus.off(GameEvents.RESET_BLOCK_SELECTION, this.onResetBlockSelectionEvent, this);
|
|
|
+ eventBus.off(GameEvents.RESET_UI_STATES, this.onResetUIStatesEvent, this);
|
|
|
eventBus.off(GameEvents.GAME_START, this.onGameStartEvent, this);
|
|
|
eventBus.off(GameEvents.GAME_START, this.updateGuideButtonStates, this);
|
|
|
eventBus.off(GameEvents.ENTER_PLAYING_STATE, this.updateGuideButtonStates, this);
|
|
|
@@ -1618,8 +1690,27 @@ export class GameBlockSelection extends Component {
|
|
|
console.warn('[GameBlockSelection] 强制结束拖拽失败:', e);
|
|
|
} finally {
|
|
|
this.currentDragBlock = null;
|
|
|
+ this.activeTouchId = null;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ // 统一获取触点ID,兼容不同版本API
|
|
|
+ private getTouchId(event: EventTouch): number {
|
|
|
+ try {
|
|
|
+ const anyEvent = event as any;
|
|
|
+ const touch = anyEvent.touch;
|
|
|
+ if (touch && typeof touch.getID === 'function') {
|
|
|
+ return touch.getID();
|
|
|
+ }
|
|
|
+ if (touch && typeof touch._id === 'number') {
|
|
|
+ return touch._id;
|
|
|
+ }
|
|
|
+ if (typeof anyEvent.id === 'number') {
|
|
|
+ return anyEvent.id;
|
|
|
+ }
|
|
|
+ } catch {}
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* 获取方块的原始位置
|