|
|
@@ -1,4 +1,4 @@
|
|
|
-import { _decorator, Component, Node, Prefab, instantiate, Vec3, EventTouch, Vec2, UITransform, find, BoxCollider2D, Collider2D, Contact2DType, IPhysics2DContact, Intersection2D, Rect, PhysicsSystem2D } from 'cc';
|
|
|
+import { _decorator, Component, Node, Prefab, instantiate, Vec3, EventTouch, Vec2, UITransform, find } from 'cc';
|
|
|
const { ccclass, property } = _decorator;
|
|
|
|
|
|
@ccclass('BlockManager')
|
|
|
@@ -14,12 +14,6 @@ export class BlockManager extends Component {
|
|
|
})
|
|
|
public gridContainer: Node = null;
|
|
|
|
|
|
- // 是否启用物理碰撞检测
|
|
|
- @property({
|
|
|
- tooltip: '是否启用物理碰撞检测'
|
|
|
- })
|
|
|
- public usePhysicsCollision: boolean = true;
|
|
|
-
|
|
|
// 已经生成的块
|
|
|
private blocks: Node[] = [];
|
|
|
// 当前拖拽的块
|
|
|
@@ -28,8 +22,24 @@ export class BlockManager extends Component {
|
|
|
private startPos = new Vec2();
|
|
|
// 块的起始位置
|
|
|
private blockStartPos: Vec3 = new Vec3();
|
|
|
- // 已占用的网格位置
|
|
|
- private occupiedPositions: Set<string> = new Set();
|
|
|
+ // 网格占用情况,用于控制台输出
|
|
|
+ private gridOccupationMap: number[][] = [];
|
|
|
+ // 网格行数和列数
|
|
|
+ private readonly GRID_ROWS = 6;
|
|
|
+ private readonly GRID_COLS = 11;
|
|
|
+ // 是否已初始化网格信息
|
|
|
+ private gridInitialized = false;
|
|
|
+ // 存储网格节点信息
|
|
|
+ private gridNodes: Node[][] = [];
|
|
|
+ // 网格间距
|
|
|
+ private gridSpacing = 54;
|
|
|
+ // 不参与占用的节点名称列表
|
|
|
+ private readonly NON_BLOCK_NODES: string[] = ['Weapon'];
|
|
|
+ // 调试模式
|
|
|
+ private readonly DEBUG_MODE = true;
|
|
|
+ // 网格偏移修正
|
|
|
+ private readonly GRID_OFFSET_X = 0;
|
|
|
+ private readonly GRID_OFFSET_Y = 0;
|
|
|
|
|
|
start() {
|
|
|
// 如果没有指定GridContainer,尝试找到它
|
|
|
@@ -37,18 +47,115 @@ export class BlockManager extends Component {
|
|
|
this.gridContainer = find('Canvas/GameLevelUI/GameArea/GridContainer');
|
|
|
if (!this.gridContainer) {
|
|
|
console.error('找不到GridContainer节点');
|
|
|
+ return;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 启用物理系统
|
|
|
- if (this.usePhysicsCollision) {
|
|
|
- PhysicsSystem2D.instance.enable = true;
|
|
|
- }
|
|
|
+ // 初始化网格信息
|
|
|
+ this.initGridInfo();
|
|
|
+
|
|
|
+ // 初始化网格占用情况
|
|
|
+ this.initGridOccupationMap();
|
|
|
|
|
|
// 生成随机的三个块
|
|
|
this.generateRandomBlocks();
|
|
|
}
|
|
|
|
|
|
+ // 调试日志
|
|
|
+ logDebug(message: string) {
|
|
|
+ if (this.DEBUG_MODE) {
|
|
|
+ console.log(message);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 初始化网格信息
|
|
|
+ initGridInfo() {
|
|
|
+ if (!this.gridContainer || this.gridInitialized) return;
|
|
|
+
|
|
|
+ this.logDebug('初始化网格信息...');
|
|
|
+
|
|
|
+ // 创建二维数组存储网格节点
|
|
|
+ this.gridNodes = [];
|
|
|
+ for (let row = 0; row < this.GRID_ROWS; row++) {
|
|
|
+ this.gridNodes[row] = [];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 遍历所有网格节点,将它们放入二维数组
|
|
|
+ for (let i = 0; i < this.gridContainer.children.length; i++) {
|
|
|
+ const grid = this.gridContainer.children[i];
|
|
|
+ if (grid.name.startsWith('Grid_')) {
|
|
|
+ // 从节点名称解析行列信息,例如Grid_2_3表示第2行第3列
|
|
|
+ const parts = grid.name.split('_');
|
|
|
+ if (parts.length === 3) {
|
|
|
+ const row = parseInt(parts[1]);
|
|
|
+ const col = parseInt(parts[2]);
|
|
|
+
|
|
|
+ if (row >= 0 && row < this.GRID_ROWS && col >= 0 && col < this.GRID_COLS) {
|
|
|
+ this.gridNodes[row][col] = grid;
|
|
|
+
|
|
|
+ // 输出网格节点的世界坐标和锚点信息
|
|
|
+ const gridWorldPos = this.gridContainer.getComponent(UITransform).convertToWorldSpaceAR(grid.position);
|
|
|
+ const gridTransform = grid.getComponent(UITransform);
|
|
|
+ this.logDebug(`网格节点 ${grid.name} 世界坐标: (${gridWorldPos.x}, ${gridWorldPos.y}), 锚点: (${gridTransform.anchorX}, ${gridTransform.anchorY}), 大小: ${gridTransform.width}x${gridTransform.height}`);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算网格间距
|
|
|
+ if (this.GRID_ROWS > 1 && this.GRID_COLS > 0) {
|
|
|
+ if (this.gridNodes[0][0] && this.gridNodes[1][0]) {
|
|
|
+ const pos1 = this.gridNodes[0][0].position;
|
|
|
+ const pos2 = this.gridNodes[1][0].position;
|
|
|
+ this.gridSpacing = Math.abs(pos2.y - pos1.y);
|
|
|
+ this.logDebug(`计算得到网格间距: ${this.gridSpacing}`);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ this.gridInitialized = true;
|
|
|
+ this.logDebug('网格信息初始化完成');
|
|
|
+
|
|
|
+ // 输出GridContainer信息
|
|
|
+ const containerTransform = this.gridContainer.getComponent(UITransform);
|
|
|
+ console.log(`GridContainer信息 - 大小: ${containerTransform.width}x${containerTransform.height}, 锚点: (${containerTransform.anchorX}, ${containerTransform.anchorY})`);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 初始化网格占用情况
|
|
|
+ initGridOccupationMap() {
|
|
|
+ this.gridOccupationMap = [];
|
|
|
+ for (let row = 0; row < this.GRID_ROWS; row++) {
|
|
|
+ const rowArray: number[] = [];
|
|
|
+ for (let col = 0; col < this.GRID_COLS; col++) {
|
|
|
+ rowArray.push(0);
|
|
|
+ }
|
|
|
+ this.gridOccupationMap.push(rowArray);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 打印网格占用情况
|
|
|
+ printGridOccupation() {
|
|
|
+ console.log('网格占用情况 (1=占用, 0=空闲):');
|
|
|
+
|
|
|
+ // 打印列索引
|
|
|
+ let colHeader = ' ';
|
|
|
+ for (let col = 0; col < this.GRID_COLS; col++) {
|
|
|
+ colHeader += ` ${col} `;
|
|
|
+ }
|
|
|
+ console.log(colHeader);
|
|
|
+
|
|
|
+ // 打印分隔线
|
|
|
+ console.log(' ' + '-'.repeat(this.GRID_COLS * 3));
|
|
|
+
|
|
|
+ // 打印每一行
|
|
|
+ for (let row = 0; row < this.GRID_ROWS; row++) {
|
|
|
+ let rowStr = ` ${row} |`;
|
|
|
+ for (let col = 0; col < this.GRID_COLS; col++) {
|
|
|
+ rowStr += ` ${this.gridOccupationMap[row][col]} `;
|
|
|
+ }
|
|
|
+ console.log(rowStr);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
generateRandomBlocks() {
|
|
|
// 清除现有的块
|
|
|
this.clearBlocks();
|
|
|
@@ -82,70 +189,16 @@ export class BlockManager extends Component {
|
|
|
// 添加到块数组
|
|
|
this.blocks.push(block);
|
|
|
|
|
|
- // 添加碰撞组件
|
|
|
- if (this.usePhysicsCollision) {
|
|
|
- this.addColliders(block);
|
|
|
- }
|
|
|
-
|
|
|
// 添加触摸事件
|
|
|
this.setupDragEvents(block);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 为方块的B1、B2、B3等节点添加碰撞组件
|
|
|
- addColliders(block: Node) {
|
|
|
- const blockParts = this.getBlockParts(block);
|
|
|
-
|
|
|
- for (const part of blockParts) {
|
|
|
- // 检查是否已有碰撞组件
|
|
|
- let collider = part.getComponent(BoxCollider2D);
|
|
|
- if (!collider) {
|
|
|
- collider = part.addComponent(BoxCollider2D);
|
|
|
- }
|
|
|
|
|
|
- // 设置碰撞组件属性
|
|
|
- const uiTransform = part.getComponent(UITransform);
|
|
|
- if (uiTransform) {
|
|
|
- collider.size.width = uiTransform.contentSize.width * 0.8; // 稍微小一点,避免边缘碰撞
|
|
|
- collider.size.height = uiTransform.contentSize.height * 0.8;
|
|
|
- } else {
|
|
|
- collider.size.width = 40; // 默认大小
|
|
|
- collider.size.height = 40;
|
|
|
- }
|
|
|
-
|
|
|
- // 设置碰撞组和掩码
|
|
|
- collider.group = 1 << 0; // 默认组
|
|
|
- collider.sensor = true; // 设为传感器,不影响物理行为
|
|
|
-
|
|
|
- // 添加碰撞回调
|
|
|
- collider.on(Contact2DType.BEGIN_CONTACT, this.onCollisionEnter, this);
|
|
|
+ // 输出方块B1节点(根节点)的世界坐标和锚点信息
|
|
|
+ const blockWorldPos = block.parent.getComponent(UITransform).convertToWorldSpaceAR(block.position);
|
|
|
+ const blockTransform = block.getComponent(UITransform);
|
|
|
+ console.log(`方块 ${block.name} B1节点(根节点)世界坐标: (${blockWorldPos.x}, ${blockWorldPos.y}), 锚点: (${blockTransform.anchorX}, ${blockTransform.anchorY}), 大小: ${blockTransform.width}x${blockTransform.height}`);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 碰撞开始回调
|
|
|
- onCollisionEnter(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
|
|
|
- // 如果当前正在拖拽方块,标记碰撞状态
|
|
|
- if (this.currentDragBlock) {
|
|
|
- const block = this.findBlockByPart(selfCollider.node);
|
|
|
- if (block === this.currentDragBlock) {
|
|
|
- block['isColliding'] = true;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 根据部件节点找到所属的方块
|
|
|
- findBlockByPart(partNode: Node): Node | null {
|
|
|
- for (const block of this.blocks) {
|
|
|
- const blockParts = this.getBlockParts(block);
|
|
|
- for (const part of blockParts) {
|
|
|
- if (part === partNode) {
|
|
|
- return block;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
setupDragEvents(block: Node) {
|
|
|
// 添加触摸开始事件
|
|
|
block.on(Node.EventType.TOUCH_START, (event: EventTouch) => {
|
|
|
@@ -162,8 +215,12 @@ export class BlockManager extends Component {
|
|
|
// 如果方块已经放置在网格中,移除占用状态
|
|
|
this.removeBlockFromGrid(block);
|
|
|
|
|
|
- // 重置碰撞状态
|
|
|
- block['isColliding'] = false;
|
|
|
+ // 更新并打印网格占用情况
|
|
|
+ this.printGridOccupation();
|
|
|
+
|
|
|
+ // 输出方块B1节点(根节点)的世界坐标
|
|
|
+ const blockWorldPos = block.parent.getComponent(UITransform).convertToWorldSpaceAR(block.position);
|
|
|
+ console.log(`拖拽开始 - 方块 ${block.name} B1节点(根节点)世界坐标: (${blockWorldPos.x}, ${blockWorldPos.y})`);
|
|
|
}, this);
|
|
|
|
|
|
// 添加触摸移动事件
|
|
|
@@ -186,17 +243,18 @@ export class BlockManager extends Component {
|
|
|
// 添加触摸结束事件
|
|
|
block.on(Node.EventType.TOUCH_END, (event: EventTouch) => {
|
|
|
if (this.currentDragBlock) {
|
|
|
- // 检查是否有碰撞
|
|
|
- if (this.usePhysicsCollision && this.currentDragBlock['isColliding']) {
|
|
|
- // 有碰撞,返回原位
|
|
|
+ // 输出拖拽结束时方块B1节点(根节点)的世界坐标
|
|
|
+ const blockWorldPos = this.currentDragBlock.parent.getComponent(UITransform).convertToWorldSpaceAR(this.currentDragBlock.position);
|
|
|
+ console.log(`拖拽结束 - 方块 ${this.currentDragBlock.name} B1节点(根节点)世界坐标: (${blockWorldPos.x}, ${blockWorldPos.y})`);
|
|
|
+
|
|
|
+ // 尝试将方块放置到网格中
|
|
|
+ if (!this.tryPlaceBlockToGrid(this.currentDragBlock)) {
|
|
|
+ // 放置失败,返回原位
|
|
|
this.currentDragBlock.position = this.blockStartPos.clone();
|
|
|
- console.log('方块放置失败:与其他方块碰撞');
|
|
|
+ console.log('方块放置失败,返回原位');
|
|
|
} else {
|
|
|
- // 尝试将方块放置到网格中
|
|
|
- if (!this.tryPlaceBlockToGrid(this.currentDragBlock)) {
|
|
|
- // 放置失败,返回原位
|
|
|
- this.currentDragBlock.position = this.blockStartPos.clone();
|
|
|
- }
|
|
|
+ // 更新并打印网格占用情况
|
|
|
+ this.printGridOccupation();
|
|
|
}
|
|
|
this.currentDragBlock = null;
|
|
|
}
|
|
|
@@ -212,21 +270,48 @@ export class BlockManager extends Component {
|
|
|
}, this);
|
|
|
}
|
|
|
|
|
|
+ // 获取网格行列索引
|
|
|
+ getGridRowCol(gridNode: Node): { row: number, col: number } | null {
|
|
|
+ if (!gridNode || !gridNode.name.startsWith('Grid_')) return null;
|
|
|
+
|
|
|
+ const parts = gridNode.name.split('_');
|
|
|
+ if (parts.length === 3) {
|
|
|
+ const row = parseInt(parts[1]);
|
|
|
+ const col = parseInt(parts[2]);
|
|
|
+
|
|
|
+ if (row >= 0 && row < this.GRID_ROWS && col >= 0 && col < this.GRID_COLS) {
|
|
|
+ return { row, col };
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
// 尝试将方块放置到网格中
|
|
|
tryPlaceBlockToGrid(block: Node): boolean {
|
|
|
- if (!this.gridContainer) return false;
|
|
|
+ if (!this.gridContainer || !this.gridInitialized) return false;
|
|
|
+
|
|
|
+ // 获取方块信息
|
|
|
+ const blockTransform = block.getComponent(UITransform);
|
|
|
+ console.log(`方块 ${block.name} 信息 - 大小: ${blockTransform.width}x${blockTransform.height}, 锚点: (${blockTransform.anchorX}, ${blockTransform.anchorY})`);
|
|
|
+
|
|
|
+ // 获取B1节点(在这个情况下,B1就是block自身,因为预制体的根节点就是B1)
|
|
|
+ // 如果B1不是根节点,而是子节点,则需要查找B1节点
|
|
|
+ let b1Node = block;
|
|
|
+ if (block.name !== 'B1') {
|
|
|
+ // 查找B1节点
|
|
|
+ b1Node = block.getChildByName('B1');
|
|
|
+ if (!b1Node) {
|
|
|
+ console.error(`找不到B1节点,无法放置方块`);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- // 找到B1节点(吸附点)
|
|
|
- const b1Node = this.findB1Node(block);
|
|
|
- if (!b1Node) return false;
|
|
|
+ console.log(`B1节点名称: ${b1Node.name}`);
|
|
|
|
|
|
- // 获取B1节点在世界坐标中的位置
|
|
|
- const blockWorldPos = block.parent.getComponent(UITransform).convertToWorldSpaceAR(block.position);
|
|
|
- const b1WorldPos = new Vec3(
|
|
|
- blockWorldPos.x + b1Node.position.x,
|
|
|
- blockWorldPos.y + b1Node.position.y,
|
|
|
- blockWorldPos.z
|
|
|
- );
|
|
|
+ // 获取方块B1节点在世界坐标中的位置
|
|
|
+ const b1WorldPos = b1Node.parent.getComponent(UITransform).convertToWorldSpaceAR(b1Node.position);
|
|
|
+ console.log(`放置前 - B1节点世界坐标: (${b1WorldPos.x}, ${b1WorldPos.y})`);
|
|
|
|
|
|
// 将B1节点的世界坐标转换为GridContainer的本地坐标
|
|
|
const gridPos = this.gridContainer.getComponent(UITransform).convertToNodeSpaceAR(b1WorldPos);
|
|
|
@@ -249,22 +334,56 @@ export class BlockManager extends Component {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+ // 获取网格节点信息
|
|
|
+ const gridTransform = nearestGrid.getComponent(UITransform);
|
|
|
+ console.log(`网格节点 ${nearestGrid.name} 信息 - 大小: ${gridTransform.width}x${gridTransform.height}, 锚点: (${gridTransform.anchorX}, ${gridTransform.anchorY})`);
|
|
|
+
|
|
|
+ // 获取网格节点的中心点世界坐标
|
|
|
+ const gridCenterWorldPos = this.gridContainer.getComponent(UITransform).convertToWorldSpaceAR(nearestGrid.position);
|
|
|
+ console.log(`最近网格节点 ${nearestGrid.name} 中心点世界坐标: (${gridCenterWorldPos.x}, ${gridCenterWorldPos.y})`);
|
|
|
+
|
|
|
// 检查方块的所有部分是否会与已占用的格子重叠
|
|
|
if (!this.canPlaceBlockAt(block, nearestGrid)) {
|
|
|
console.log('方块放置位置已被占用或超出边界');
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- // 计算方块应该移动到的位置,使B1对齐到网格
|
|
|
- const targetWorldPos = this.gridContainer.getComponent(UITransform).convertToWorldSpaceAR(nearestGrid.position);
|
|
|
- const targetPos = block.parent.getComponent(UITransform).convertToNodeSpaceAR(targetWorldPos);
|
|
|
+ // 计算B1节点应该移动到的位置
|
|
|
+ const targetWorldPos = gridCenterWorldPos.clone();
|
|
|
+
|
|
|
+ // 计算根节点需要移动的位置
|
|
|
+ // 1. 先计算B1节点相对于根节点的偏移
|
|
|
+ const b1LocalPos = b1Node.position.clone();
|
|
|
+ console.log(`B1节点相对于根节点的偏移: (${b1LocalPos.x}, ${b1LocalPos.y}, ${b1LocalPos.z})`);
|
|
|
+
|
|
|
+ // 2. 计算根节点的目标世界坐标
|
|
|
+ // 如果B1是根节点,则直接使用网格中心点
|
|
|
+ let rootTargetWorldPos;
|
|
|
+ if (b1Node === block) {
|
|
|
+ rootTargetWorldPos = targetWorldPos.clone();
|
|
|
+ } else {
|
|
|
+ // 如果B1是子节点,需要计算根节点应该在的位置,使B1对准网格中心
|
|
|
+ // 根节点位置 = 网格中心位置 - B1相对于根节点的偏移
|
|
|
+ rootTargetWorldPos = new Vec3(
|
|
|
+ targetWorldPos.x - b1LocalPos.x,
|
|
|
+ targetWorldPos.y - b1LocalPos.y,
|
|
|
+ targetWorldPos.z
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 将世界坐标转换为根节点父节点的本地坐标
|
|
|
+ const rootTargetLocalPos = block.parent.getComponent(UITransform).convertToNodeSpaceAR(rootTargetWorldPos);
|
|
|
|
|
|
- // 设置方块位置
|
|
|
- block.position = new Vec3(
|
|
|
- targetPos.x - b1Node.position.x,
|
|
|
- targetPos.y - b1Node.position.y,
|
|
|
- block.position.z
|
|
|
- );
|
|
|
+ // 设置方块位置,确保B1节点的中心与网格节点的中心对齐
|
|
|
+ block.position = rootTargetLocalPos;
|
|
|
+
|
|
|
+ // 输出放置后B1节点的世界坐标
|
|
|
+ const placedB1WorldPos = b1Node.parent.getComponent(UITransform).convertToWorldSpaceAR(b1Node.position);
|
|
|
+ console.log(`放置后 - B1节点世界坐标: (${placedB1WorldPos.x}, ${placedB1WorldPos.y})`);
|
|
|
+
|
|
|
+ // 输出对比信息,查看是否完全对齐
|
|
|
+ console.log(`对齐检查 - 网格中心点: (${gridCenterWorldPos.x}, ${gridCenterWorldPos.y}), B1节点中心点: (${placedB1WorldPos.x}, ${placedB1WorldPos.y})`);
|
|
|
+ console.log(`对齐差值 - X: ${placedB1WorldPos.x - gridCenterWorldPos.x}, Y: ${placedB1WorldPos.y - gridCenterWorldPos.y}`);
|
|
|
|
|
|
// 标记占用的格子
|
|
|
this.markOccupiedPositions(block, nearestGrid);
|
|
|
@@ -273,193 +392,176 @@ export class BlockManager extends Component {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- // 检查两个方块是否碰撞(使用几何碰撞检测)
|
|
|
- checkBlocksCollision(block1: Node, block2: Node): boolean {
|
|
|
- if (block1 === block2) return false;
|
|
|
-
|
|
|
- const parts1 = this.getBlockParts(block1);
|
|
|
- const parts2 = this.getBlockParts(block2);
|
|
|
-
|
|
|
- // 检查每个部分之间的碰撞
|
|
|
- for (const part1 of parts1) {
|
|
|
- const rect1 = this.getNodeRect(part1);
|
|
|
-
|
|
|
- for (const part2 of parts2) {
|
|
|
- const rect2 = this.getNodeRect(part2);
|
|
|
-
|
|
|
- // 检查矩形是否相交
|
|
|
- if (Intersection2D.rectRect(rect1, rect2)) {
|
|
|
- return true;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- // 获取节点的世界矩形
|
|
|
- getNodeRect(node: Node): Rect {
|
|
|
- const uiTransform = node.getComponent(UITransform);
|
|
|
- if (!uiTransform) {
|
|
|
- return new Rect(0, 0, 0, 0);
|
|
|
- }
|
|
|
-
|
|
|
- const size = uiTransform.contentSize;
|
|
|
- const worldPos = node.parent.getComponent(UITransform).convertToWorldSpaceAR(node.position);
|
|
|
-
|
|
|
- return new Rect(
|
|
|
- worldPos.x - size.width * 0.5,
|
|
|
- worldPos.y - size.height * 0.5,
|
|
|
- size.width,
|
|
|
- size.height
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- // 找到B1节点
|
|
|
- findB1Node(block: Node): Node {
|
|
|
- for (let i = 0; i < block.children.length; i++) {
|
|
|
- const child = block.children[i];
|
|
|
- if (child.name === 'B1') {
|
|
|
- return child;
|
|
|
- }
|
|
|
- }
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
// 找到最近的网格节点
|
|
|
findNearestGridNode(position: Vec3): Node {
|
|
|
- if (!this.gridContainer) return null;
|
|
|
+ if (!this.gridContainer || !this.gridInitialized) return null;
|
|
|
|
|
|
let nearestNode: Node = null;
|
|
|
let minDistance = Number.MAX_VALUE;
|
|
|
|
|
|
// 遍历所有网格节点
|
|
|
- for (let i = 0; i < this.gridContainer.children.length; i++) {
|
|
|
- const grid = this.gridContainer.children[i];
|
|
|
- if (grid.name.startsWith('Grid_')) {
|
|
|
- const distance = Vec3.distance(position, grid.position);
|
|
|
- if (distance < minDistance) {
|
|
|
- minDistance = distance;
|
|
|
- nearestNode = grid;
|
|
|
+ for (let row = 0; row < this.GRID_ROWS; row++) {
|
|
|
+ for (let col = 0; col < this.GRID_COLS; col++) {
|
|
|
+ const grid = this.gridNodes[row][col];
|
|
|
+ if (grid) {
|
|
|
+ const distance = Vec3.distance(position, grid.position);
|
|
|
+ if (distance < minDistance) {
|
|
|
+ minDistance = distance;
|
|
|
+ nearestNode = grid;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // 如果距离太远(超过网格大小的一半),不吸附
|
|
|
- if (minDistance > 24) { // 假设网格大小为48x48
|
|
|
+ // 如果距离太远,不吸附
|
|
|
+ if (minDistance > this.gridSpacing / 2) {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
return nearestNode;
|
|
|
}
|
|
|
|
|
|
- // 检查方块是否可以放置在指定位置
|
|
|
- canPlaceBlockAt(block: Node, targetGrid: Node): boolean {
|
|
|
- // 获取方块的所有部分(B1, B2, B3...)
|
|
|
- const blockParts = this.getBlockParts(block);
|
|
|
+ // 获取方块的所有部分节点及其相对坐标
|
|
|
+ getBlockParts(block: Node): { node: Node, x: number, y: number }[] {
|
|
|
+ const parts: { node: Node, x: number, y: number }[] = [];
|
|
|
|
|
|
- // 找到B1节点
|
|
|
- const b1Node = this.findB1Node(block);
|
|
|
- if (!b1Node) return false;
|
|
|
+ // 添加B1节点本身(根节点)
|
|
|
+ parts.push({ node: block, x: 0, y: 0 });
|
|
|
|
|
|
- // 计算B1与目标网格的偏移
|
|
|
- const offsetX = targetGrid.position.x - b1Node.position.x;
|
|
|
- const offsetY = targetGrid.position.y - b1Node.position.y;
|
|
|
+ // 递归查找所有子节点
|
|
|
+ this.findBlockParts(block, parts, 0, 0);
|
|
|
|
|
|
- // 检查每个部分是否与已占用的格子重叠
|
|
|
- for (const part of blockParts) {
|
|
|
- // 计算部分在网格中的位置
|
|
|
- const gridX = Math.round(offsetX + part.position.x);
|
|
|
- const gridY = Math.round(offsetY + part.position.y);
|
|
|
- const posKey = `${gridX},${gridY}`;
|
|
|
+ return parts;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 递归查找方块的所有部分
|
|
|
+ findBlockParts(node: Node, result: { node: Node, x: number, y: number }[], parentX: number, parentY: number) {
|
|
|
+ // 遍历所有子节点
|
|
|
+ for (let i = 0; i < node.children.length; i++) {
|
|
|
+ const child = node.children[i];
|
|
|
|
|
|
- // 检查该位置是否已被占用
|
|
|
- if (this.occupiedPositions.has(posKey)) {
|
|
|
- return false;
|
|
|
+ // 跳过不参与占用的节点
|
|
|
+ if (this.NON_BLOCK_NODES.indexOf(child.name) !== -1) {
|
|
|
+ continue;
|
|
|
}
|
|
|
|
|
|
- // 检查是否超出GridContainer边界
|
|
|
- const gridNode = this.findGridAtPosition(gridX, gridY);
|
|
|
- if (!gridNode) {
|
|
|
- return false;
|
|
|
+ let x = parentX;
|
|
|
+ let y = parentY;
|
|
|
+
|
|
|
+ // 尝试从节点名称中解析坐标
|
|
|
+ const match = child.name.match(/^\((-?\d+),(-?\d+)\)$/);
|
|
|
+ if (match) {
|
|
|
+ // 如果节点名称是坐标格式,直接使用
|
|
|
+ x = parseInt(match[1]);
|
|
|
+ y = parseInt(match[2]);
|
|
|
+ result.push({ node: child, x, y });
|
|
|
+ this.logDebug(`找到坐标节点: ${child.name}, x=${x}, y=${y}`);
|
|
|
+ } else if (child.name.startsWith('B')) {
|
|
|
+ // 如果是B开头的节点,使用其相对位置
|
|
|
+ // 计算相对于父节点的位置,并转换为网格单位
|
|
|
+ const relativeX = Math.round(child.position.x / this.gridSpacing);
|
|
|
+ const relativeY = -Math.round(child.position.y / this.gridSpacing); // Y轴向下为正
|
|
|
+
|
|
|
+ x = parentX + relativeX;
|
|
|
+ y = parentY + relativeY;
|
|
|
+
|
|
|
+ result.push({ node: child, x, y });
|
|
|
+ this.logDebug(`找到B节点: ${child.name}, 相对位置: (${relativeX}, ${relativeY}), 累计位置: (${x}, ${y})`);
|
|
|
}
|
|
|
+
|
|
|
+ // 递归处理子节点
|
|
|
+ this.findBlockParts(child, result, x, y);
|
|
|
}
|
|
|
-
|
|
|
- return true;
|
|
|
}
|
|
|
|
|
|
- // 根据坐标找到网格节点
|
|
|
- findGridAtPosition(x: number, y: number): Node {
|
|
|
- if (!this.gridContainer) return null;
|
|
|
+ // 检查方块是否可以放置在指定位置
|
|
|
+ canPlaceBlockAt(block: Node, targetGrid: Node): boolean {
|
|
|
+ if (!this.gridInitialized) return false;
|
|
|
|
|
|
- for (let i = 0; i < this.gridContainer.children.length; i++) {
|
|
|
- const grid = this.gridContainer.children[i];
|
|
|
- if (grid.name.startsWith('Grid_')) {
|
|
|
- if (Math.abs(grid.position.x - x) < 1 && Math.abs(grid.position.y - y) < 1) {
|
|
|
- return grid;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+ // 获取目标网格的行列索引
|
|
|
+ const targetRowCol = this.getGridRowCol(targetGrid);
|
|
|
+ if (!targetRowCol) return false;
|
|
|
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
- // 获取方块的所有部分(B1, B2, B3...)
|
|
|
- getBlockParts(block: Node): Node[] {
|
|
|
- const parts: Node[] = [];
|
|
|
-
|
|
|
- for (let i = 0; i < block.children.length; i++) {
|
|
|
- const child = block.children[i];
|
|
|
- if (child.name.startsWith('B') && /^B\d+$/.test(child.name)) {
|
|
|
- parts.push(child);
|
|
|
+ // 获取方块的所有部分
|
|
|
+ const parts = this.getBlockParts(block);
|
|
|
+ console.log(`方块有 ${parts.length} 个部分`);
|
|
|
+
|
|
|
+ // 检查每个部分是否与已占用的格子重叠
|
|
|
+ for (const part of parts) {
|
|
|
+ // 计算在网格中的行列位置
|
|
|
+ const row = targetRowCol.row - part.y; // Y轴向下为正,所以是减法
|
|
|
+ const col = targetRowCol.col + part.x; // X轴向右为正
|
|
|
+
|
|
|
+ this.logDebug(`检查部分 ${part.node.name} 在位置 (${part.x}, ${part.y}) 对应网格位置: 行=${row}, 列=${col}`);
|
|
|
+
|
|
|
+ // 检查是否超出网格范围
|
|
|
+ if (row < 0 || row >= this.GRID_ROWS || col < 0 || col >= this.GRID_COLS) {
|
|
|
+ console.log(`部分 ${part.node.name} 超出网格范围`);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查该位置是否已被占用
|
|
|
+ if (this.gridOccupationMap[row][col] === 1) {
|
|
|
+ console.log(`部分 ${part.node.name} 对应的网格位置已被占用: 行=${row}, 列=${col}`);
|
|
|
+ return false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return parts;
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
// 标记方块占用的格子
|
|
|
markOccupiedPositions(block: Node, targetGrid: Node) {
|
|
|
- // 获取方块的所有部分
|
|
|
- const blockParts = this.getBlockParts(block);
|
|
|
+ if (!this.gridInitialized) return;
|
|
|
|
|
|
- // 找到B1节点
|
|
|
- const b1Node = this.findB1Node(block);
|
|
|
- if (!b1Node) return;
|
|
|
+ // 获取目标网格的行列索引
|
|
|
+ const targetRowCol = this.getGridRowCol(targetGrid);
|
|
|
+ if (!targetRowCol) return;
|
|
|
|
|
|
- // 计算B1与目标网格的偏移
|
|
|
- const offsetX = targetGrid.position.x - b1Node.position.x;
|
|
|
- const offsetY = targetGrid.position.y - b1Node.position.y;
|
|
|
+ // 获取方块的所有部分
|
|
|
+ const parts = this.getBlockParts(block);
|
|
|
+
|
|
|
+ // 清除之前的占用记录
|
|
|
+ block['occupiedGrids'] = [];
|
|
|
|
|
|
// 为每个部分标记占用位置
|
|
|
- for (const part of blockParts) {
|
|
|
- // 计算部分在网格中的位置
|
|
|
- const gridX = Math.round(offsetX + part.position.x);
|
|
|
- const gridY = Math.round(offsetY + part.position.y);
|
|
|
- const posKey = `${gridX},${gridY}`;
|
|
|
-
|
|
|
- // 记录占用信息
|
|
|
- this.occupiedPositions.add(posKey);
|
|
|
+ for (const part of parts) {
|
|
|
+ // 计算在网格中的行列位置
|
|
|
+ const row = targetRowCol.row - part.y; // Y轴向下为正,所以是减法
|
|
|
+ const col = targetRowCol.col + part.x; // X轴向右为正
|
|
|
|
|
|
- // 存储方块与位置的关联
|
|
|
- block['occupiedPositions'] = block['occupiedPositions'] || [];
|
|
|
- block['occupiedPositions'].push(posKey);
|
|
|
+ // 检查是否在有效范围内
|
|
|
+ if (row >= 0 && row < this.GRID_ROWS && col >= 0 && col < this.GRID_COLS) {
|
|
|
+ // 更新网格占用情况
|
|
|
+ this.gridOccupationMap[row][col] = 1;
|
|
|
+
|
|
|
+ // 存储方块与网格的关联
|
|
|
+ block['occupiedGrids'] = block['occupiedGrids'] || [];
|
|
|
+ block['occupiedGrids'].push({ row, col });
|
|
|
+
|
|
|
+ this.logDebug(`标记占用: 部分=${part.node.name}, 位置=(${part.x}, ${part.y}), 行=${row}, 列=${col}`);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 移除方块占用的格子
|
|
|
removeBlockFromGrid(block: Node) {
|
|
|
- // 获取方块占用的位置
|
|
|
- const occupiedPositions = block['occupiedPositions'];
|
|
|
- if (!occupiedPositions) return;
|
|
|
+ // 获取方块占用的网格
|
|
|
+ const occupiedGrids = block['occupiedGrids'];
|
|
|
+ if (!occupiedGrids) return;
|
|
|
+
|
|
|
+ console.log(`移除占用: 方块=${block.name}, 占用网格数=${occupiedGrids.length}`);
|
|
|
|
|
|
// 移除占用标记
|
|
|
- for (const posKey of occupiedPositions) {
|
|
|
- this.occupiedPositions.delete(posKey);
|
|
|
+ for (const grid of occupiedGrids) {
|
|
|
+ if (grid.row >= 0 && grid.row < this.GRID_ROWS &&
|
|
|
+ grid.col >= 0 && grid.col < this.GRID_COLS) {
|
|
|
+ this.gridOccupationMap[grid.row][grid.col] = 0;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// 清空方块的占用记录
|
|
|
- block['occupiedPositions'] = [];
|
|
|
+ block['occupiedGrids'] = [];
|
|
|
}
|
|
|
|
|
|
clearBlocks() {
|
|
|
@@ -474,7 +576,10 @@ export class BlockManager extends Component {
|
|
|
}
|
|
|
this.blocks = [];
|
|
|
|
|
|
- // 清空占用位置
|
|
|
- this.occupiedPositions.clear();
|
|
|
+ // 重置网格占用情况
|
|
|
+ this.initGridOccupationMap();
|
|
|
+
|
|
|
+ // 打印网格占用情况
|
|
|
+ this.printGridOccupation();
|
|
|
}
|
|
|
}
|