181404010226 пре 6 месеци
родитељ
комит
b30bce94ef
2 измењених фајлова са 315 додато и 3 уклоњено
  1. 4 0
      assets/Scenes/GameLevel.scene
  2. 311 3
      assets/scripts/BlockManager.ts

+ 4 - 0
assets/Scenes/GameLevel.scene

@@ -14688,6 +14688,10 @@
         "__expectedType__": "cc.Prefab"
       }
     ],
+    "gridContainer": {
+      "__id__": 71
+    },
+    "gridSize": 48,
     "_id": "94jMUxDu9HeomOvBfJwDpA"
   },
   {

+ 311 - 3
assets/scripts/BlockManager.ts

@@ -1,12 +1,30 @@
-import { _decorator, Component, Node, Prefab, instantiate, Vec3, EventTouch, Vec2 } from 'cc';
+import { _decorator, Component, Node, Prefab, instantiate, Vec3, EventTouch, Vec2, UITransform, find } from 'cc';
 const { ccclass, property } = _decorator;
 
+// 格子信息接口
+interface GridInfo {
+    node: Node;
+    position: Vec3;
+    isOccupied: boolean;
+}
+
 @ccclass('BlockManager')
 export class BlockManager extends Component {
     // 预制体数组,存储5个预制体
     @property([Prefab])
     public blockPrefabs: Prefab[] = [];
     
+    // 网格容器节点
+    @property({
+        type: Node,
+        tooltip: '拖拽GridContainer节点到这里'
+    })
+    public gridContainer: Node = null;
+    
+    // 网格大小
+    @property
+    public gridSize: number = 48;
+    
     // 已经生成的块
     private blocks: Node[] = [];
     // 当前拖拽的块
@@ -15,12 +33,46 @@ export class BlockManager extends Component {
     private startPos = new Vec2();
     // 块的起始位置
     private blockStartPos: Vec3 = new Vec3();
+    // 网格信息
+    private grids: GridInfo[] = [];
+    // 已放置的方块占用的格子
+    private occupiedGrids: Set<string> = new Set();
     
     start() {
+        // 初始化网格信息
+        this.initGrids();
         // 生成随机的三个块
         this.generateRandomBlocks();
     }
     
+    // 初始化网格信息
+    initGrids() {
+        if (!this.gridContainer) {
+            this.gridContainer = find('Canvas/GameLevelUI/GameArea/GridContainer');
+            if (!this.gridContainer) {
+                console.error('找不到GridContainer节点');
+                return;
+            }
+        }
+        
+        // 清空网格信息
+        this.grids = [];
+        
+        // 遍历GridContainer的子节点,获取所有格子信息
+        for (let i = 0; i < this.gridContainer.children.length; i++) {
+            const grid = this.gridContainer.children[i];
+            if (grid.name.startsWith('Grid_')) {
+                this.grids.push({
+                    node: grid,
+                    position: grid.position.clone(),
+                    isOccupied: false
+                });
+            }
+        }
+        
+        console.log(`初始化了 ${this.grids.length} 个网格`);
+    }
+    
     generateRandomBlocks() {
         // 清除现有的块
         this.clearBlocks();
@@ -71,6 +123,9 @@ export class BlockManager extends Component {
             
             // 将块置于顶层
             block.setSiblingIndex(this.node.children.length - 1);
+            
+            // 如果方块已经放置在网格中,则移除占用状态
+            this.removeBlockFromGrid(block);
         }, this);
         
         // 添加触摸移动事件
@@ -88,26 +143,279 @@ export class BlockManager extends Component {
                 this.blockStartPos.y + deltaY,
                 this.blockStartPos.z
             );
+            
+            // 显示吸附预览
+            this.showSnapPreview(this.currentDragBlock);
         }, this);
         
         // 添加触摸结束事件
         block.on(Node.EventType.TOUCH_END, () => {
-            this.currentDragBlock = null;
+            if (this.currentDragBlock) {
+                // 尝试将方块吸附到网格
+                this.snapBlockToGrid(this.currentDragBlock);
+                this.currentDragBlock = null;
+            }
         }, this);
         
         // 添加触摸取消事件
         block.on(Node.EventType.TOUCH_CANCEL, () => {
-            this.currentDragBlock = null;
+            if (this.currentDragBlock) {
+                // 尝试将方块吸附到网格
+                this.snapBlockToGrid(this.currentDragBlock);
+                this.currentDragBlock = null;
+            }
         }, this);
     }
     
+    // 显示吸附预览
+    showSnapPreview(block: Node) {
+        // 找到B1节点(吸附点)
+        const b1Node = this.findB1Node(block);
+        if (!b1Node) return;
+        
+        // 计算B1节点在世界坐标系中的位置
+        const blockWorldPos = this.node.getComponent(UITransform).convertToWorldSpaceAR(block.position);
+        const b1LocalPos = b1Node.position;
+        const b1WorldPos = new Vec3(
+            blockWorldPos.x + b1LocalPos.x,
+            blockWorldPos.y + b1LocalPos.y,
+            blockWorldPos.z + b1LocalPos.z
+        );
+        
+        // 将B1节点的世界坐标转换为网格容器的本地坐标
+        const gridContainerPos = this.gridContainer.getComponent(UITransform).convertToNodeSpaceAR(b1WorldPos);
+        
+        // 找到最近的网格
+        const nearestGrid = this.findNearestGrid(gridContainerPos);
+        if (nearestGrid && this.canPlaceBlockAt(block, nearestGrid)) {
+            // 可以显示预览效果,例如高亮网格等
+        }
+    }
+    
+    // 将方块吸附到网格
+    snapBlockToGrid(block: Node) {
+        // 找到B1节点(吸附点)
+        const b1Node = this.findB1Node(block);
+        if (!b1Node) return;
+        
+        // 计算B1节点在世界坐标系中的位置
+        const blockWorldPos = this.node.getComponent(UITransform).convertToWorldSpaceAR(block.position);
+        const b1LocalPos = b1Node.position;
+        const b1WorldPos = new Vec3(
+            blockWorldPos.x + b1LocalPos.x,
+            blockWorldPos.y + b1LocalPos.y,
+            blockWorldPos.z + b1LocalPos.z
+        );
+        
+        // 将B1节点的世界坐标转换为网格容器的本地坐标
+        const gridContainerPos = this.gridContainer.getComponent(UITransform).convertToNodeSpaceAR(b1WorldPos);
+        
+        // 找到最近的网格
+        const nearestGrid = this.findNearestGrid(gridContainerPos);
+        if (!nearestGrid) return;
+        
+        // 检查是否可以放置
+        if (!this.canPlaceBlockAt(block, nearestGrid)) {
+            // 不能放置,恢复到原始位置
+            block.position = this.blockStartPos.clone();
+            return;
+        }
+        
+        // 计算方块应该移动到的位置
+        const targetWorldPos = this.gridContainer.getComponent(UITransform).convertToWorldSpaceAR(nearestGrid.position);
+        const targetNodePos = this.node.getComponent(UITransform).convertToNodeSpaceAR(targetWorldPos);
+        
+        // 设置方块位置,使B1节点对齐到网格
+        block.position = new Vec3(
+            targetNodePos.x - b1LocalPos.x,
+            targetNodePos.y - b1LocalPos.y,
+            block.position.z
+        );
+        
+        // 标记占用的格子
+        this.markOccupiedGrids(block, nearestGrid);
+    }
+    
+    // 找到B1节点
+    findB1Node(block: Node): Node {
+        // 遍历子节点,查找名为B1的节点
+        for (let i = 0; i < block.children.length; i++) {
+            const child = block.children[i];
+            if (child.name === 'B1') {
+                return child;
+            }
+        }
+        return null;
+    }
+    
+    // 找到最近的网格
+    findNearestGrid(position: Vec3): GridInfo {
+        let nearestGrid: GridInfo = null;
+        let minDistance = Number.MAX_VALUE;
+        
+        for (const grid of this.grids) {
+            const distance = Vec3.distance(position, grid.position);
+            if (distance < minDistance && !grid.isOccupied) {
+                minDistance = distance;
+                nearestGrid = grid;
+            }
+        }
+        
+        // 如果距离太远,不吸附
+        if (minDistance > this.gridSize / 2) {
+            return null;
+        }
+        
+        return nearestGrid;
+    }
+    
+    // 检查方块是否可以放置在指定网格
+    canPlaceBlockAt(block: Node, grid: GridInfo): boolean {
+        // 获取方块的所有子节点(B1, B2, B3...)
+        const blockParts = this.getBlockParts(block);
+        
+        // 假设B1已经对齐到目标网格,计算其他部分的位置
+        const b1Node = this.findB1Node(block);
+        if (!b1Node) return false;
+        
+        // 计算方块应该移动到的位置
+        const targetWorldPos = this.gridContainer.getComponent(UITransform).convertToWorldSpaceAR(grid.position);
+        const targetNodePos = this.node.getComponent(UITransform).convertToNodeSpaceAR(targetWorldPos);
+        
+        // 计算方块的新位置
+        const newBlockPos = new Vec3(
+            targetNodePos.x - b1Node.position.x,
+            targetNodePos.y - b1Node.position.y,
+            block.position.z
+        );
+        
+        // 检查每个部分是否会与已占用的格子重叠
+        for (const part of blockParts) {
+            if (part === b1Node) continue; // B1已经对齐到目标网格
+            
+            // 计算部分在新位置下的世界坐标
+            const partWorldPos = new Vec3(
+                newBlockPos.x + part.position.x,
+                newBlockPos.y + part.position.y,
+                newBlockPos.z + part.position.z
+            );
+            const partWorldPosAR = this.node.getComponent(UITransform).convertToWorldSpaceAR(partWorldPos);
+            const gridContainerPos = this.gridContainer.getComponent(UITransform).convertToNodeSpaceAR(partWorldPosAR);
+            
+            // 找到该部分对应的网格
+            const partGrid = this.findExactGrid(gridContainerPos);
+            if (!partGrid) {
+                // 超出网格范围
+                return false;
+            }
+            
+            // 检查该网格是否已被占用
+            if (partGrid.isOccupied) {
+                return false;
+            }
+        }
+        
+        return true;
+    }
+    
+    // 找到精确匹配的网格
+    findExactGrid(position: Vec3): GridInfo {
+        for (const grid of this.grids) {
+            const distance = Vec3.distance(position, grid.position);
+            if (distance < this.gridSize / 2) {
+                return grid;
+            }
+        }
+        return null;
+    }
+    
+    // 获取方块的所有部分(B1, B2, B3...)
+    getBlockParts(block: Node): Node[] {
+        const parts: Node[] = [];
+        
+        // 遍历子节点,查找名称以B开头的节点
+        for (let i = 0; i < block.children.length; i++) {
+            const child = block.children[i];
+            if (child.name.startsWith('B') && child.name.length > 1) {
+                parts.push(child);
+            }
+        }
+        
+        return parts;
+    }
+    
+    // 标记方块占用的格子
+    markOccupiedGrids(block: Node, mainGrid: GridInfo) {
+        // 获取方块的所有部分
+        const blockParts = this.getBlockParts(block);
+        
+        // 为每个部分找到对应的网格并标记为已占用
+        for (const part of blockParts) {
+            // 计算部分在世界坐标系中的位置
+            const blockWorldPos = this.node.getComponent(UITransform).convertToWorldSpaceAR(block.position);
+            const partLocalPos = part.position;
+            const partWorldPos = new Vec3(
+                blockWorldPos.x + partLocalPos.x,
+                blockWorldPos.y + partLocalPos.y,
+                blockWorldPos.z + partLocalPos.z
+            );
+            
+            // 将部分的世界坐标转换为网格容器的本地坐标
+            const gridContainerPos = this.gridContainer.getComponent(UITransform).convertToNodeSpaceAR(partWorldPos);
+            
+            // 找到该部分对应的网格
+            const grid = this.findExactGrid(gridContainerPos);
+            if (grid) {
+                grid.isOccupied = true;
+                // 记录占用信息,格式为"blockID:gridID"
+                this.occupiedGrids.add(`${block.uuid}:${grid.node.uuid}`);
+            }
+        }
+    }
+    
+    // 移除方块占用的格子
+    removeBlockFromGrid(block: Node) {
+        // 遍历所有占用记录,找到与当前方块相关的记录
+        const toRemove: string[] = [];
+        
+        this.occupiedGrids.forEach(record => {
+            if (record.startsWith(`${block.uuid}:`)) {
+                const gridId = record.split(':')[1];
+                
+                // 找到对应的网格并标记为未占用
+                for (const grid of this.grids) {
+                    if (grid.node.uuid === gridId) {
+                        grid.isOccupied = false;
+                        break;
+                    }
+                }
+                
+                toRemove.push(record);
+            }
+        });
+        
+        // 移除记录
+        toRemove.forEach(record => {
+            this.occupiedGrids.delete(record);
+        });
+    }
+    
     clearBlocks() {
         // 移除所有已经生成的块
         for (const block of this.blocks) {
             if (block.isValid) {
+                // 移除占用的格子
+                this.removeBlockFromGrid(block);
+                // 销毁方块
                 block.destroy();
             }
         }
         this.blocks = [];
+        
+        // 重置所有网格状态
+        for (const grid of this.grids) {
+            grid.isOccupied = false;
+        }
+        this.occupiedGrids.clear();
     }
 }