Browse Source

可移动方块

181404010226 5 months ago
parent
commit
c861611820

+ 149 - 24
assets/Scenes/GameLevel.scene

@@ -23,7 +23,7 @@
     "_active": true,
     "_components": [],
     "_prefab": {
-      "__id__": 648
+      "__id__": 656
     },
     "_lpos": {
       "__type__": "cc.Vec3",
@@ -54,7 +54,7 @@
     },
     "autoReleaseAssets": false,
     "_globals": {
-      "__id__": 649
+      "__id__": 657
     },
     "_id": "29694223-a59c-44b3-acb0-80ab92d103f5"
   },
@@ -84,30 +84,33 @@
       },
       {
         "__id__": 641
+      },
+      {
+        "__id__": 643
       }
     ],
     "_active": true,
     "_components": [
       {
-        "__id__": 643
+        "__id__": 651
       },
       {
-        "__id__": 644
+        "__id__": 652
       },
       {
-        "__id__": 645
+        "__id__": 653
       },
       {
-        "__id__": 646
+        "__id__": 654
       },
       {
-        "__id__": 647
+        "__id__": 655
       }
     ],
     "_prefab": null,
     "_lpos": {
       "__type__": "cc.Vec3",
-      "x": 360,
+      "x": 360.00000000000006,
       "y": 667,
       "z": 0
     },
@@ -267,9 +270,6 @@
       {
         "__id__": 415
       },
-      {
-        "__id__": 417
-      },
       {
         "__id__": 404
       },
@@ -278,6 +278,9 @@
       },
       {
         "__id__": 401
+      },
+      {
+        "__id__": 417
       }
     ],
     "_active": true,
@@ -292,7 +295,7 @@
     "_prefab": null,
     "_lpos": {
       "__type__": "cc.Vec3",
-      "x": 0,
+      "x": -5.684341886080802e-14,
       "y": 0,
       "z": 0
     },
@@ -15822,7 +15825,7 @@
     "_id": "2d1KN8EjFKvKM3MqcwEJUg"
   },
   {
-    "__type__": "0872bYuOm1LObhf/0RYZb7C",
+    "__type__": "3a5aep5eGRINo2M/K6jztRS",
     "_name": "",
     "_objFlags": 0,
     "__editorExtras__": {},
@@ -15862,7 +15865,13 @@
     "coinLabelNode": {
       "__id__": 26
     },
-    "_id": "e1lAC2CKRC8IwpDXirQEkn"
+    "bulletPrefab": {
+      "__uuid__": "669f3dcb-acf3-4e72-9593-f6528554cfba",
+      "__expectedType__": "cc.Prefab"
+    },
+    "blockMoveCooldown": 10,
+    "bulletCooldown": 0.5,
+    "_id": "19nrhqXPpAQ7nRPaH27rI/"
   },
   {
     "__type__": "cc.UITransform",
@@ -24633,6 +24642,117 @@
     },
     "_id": "cfRO9s7PRJnazoYDjLgTQ2"
   },
+  {
+    "__type__": "cc.Node",
+    "_objFlags": 0,
+    "_parent": {
+      "__id__": 2
+    },
+    "_prefab": {
+      "__id__": 644
+    },
+    "__editorExtras__": {}
+  },
+  {
+    "__type__": "cc.PrefabInfo",
+    "root": {
+      "__id__": 643
+    },
+    "asset": {
+      "__uuid__": "669f3dcb-acf3-4e72-9593-f6528554cfba",
+      "__expectedType__": "cc.Prefab"
+    },
+    "fileId": "3549ek5TVKYYngJeAEZalg",
+    "instance": {
+      "__id__": 645
+    },
+    "targetOverrides": null,
+    "nestedPrefabInstanceRoots": null
+  },
+  {
+    "__type__": "cc.PrefabInstance",
+    "fileId": "f3xE3iRE1IhI5tqcKGyCoC",
+    "prefabRootNode": null,
+    "mountedChildren": [],
+    "mountedComponents": [],
+    "propertyOverrides": [
+      {
+        "__id__": 646
+      },
+      {
+        "__id__": 648
+      },
+      {
+        "__id__": 649
+      },
+      {
+        "__id__": 650
+      }
+    ],
+    "removedComponents": []
+  },
+  {
+    "__type__": "CCPropertyOverrideInfo",
+    "targetInfo": {
+      "__id__": 647
+    },
+    "propertyPath": [
+      "_lpos"
+    ],
+    "value": {
+      "__type__": "cc.Vec3",
+      "x": 884.4569001250784,
+      "y": -456.2934408172281,
+      "z": 0
+    }
+  },
+  {
+    "__type__": "cc.TargetInfo",
+    "localID": [
+      "3549ek5TVKYYngJeAEZalg"
+    ]
+  },
+  {
+    "__type__": "CCPropertyOverrideInfo",
+    "targetInfo": {
+      "__id__": 647
+    },
+    "propertyPath": [
+      "_name"
+    ],
+    "value": "Bullet"
+  },
+  {
+    "__type__": "CCPropertyOverrideInfo",
+    "targetInfo": {
+      "__id__": 647
+    },
+    "propertyPath": [
+      "_lrot"
+    ],
+    "value": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    }
+  },
+  {
+    "__type__": "CCPropertyOverrideInfo",
+    "targetInfo": {
+      "__id__": 647
+    },
+    "propertyPath": [
+      "_euler"
+    ],
+    "value": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    }
+  },
   {
     "__type__": "cc.UITransform",
     "_name": "",
@@ -24645,7 +24765,7 @@
     "__prefab": null,
     "_contentSize": {
       "__type__": "cc.Size",
-      "width": 720,
+      "width": 720.0000000000001,
       "height": 1334
     },
     "_anchorPoint": {
@@ -24734,33 +24854,38 @@
     "asset": null,
     "fileId": "29694223-a59c-44b3-acb0-80ab92d103f5",
     "instance": null,
-    "targetOverrides": null
+    "targetOverrides": null,
+    "nestedPrefabInstanceRoots": [
+      {
+        "__id__": 643
+      }
+    ]
   },
   {
     "__type__": "cc.SceneGlobals",
     "ambient": {
-      "__id__": 650
+      "__id__": 658
     },
     "shadows": {
-      "__id__": 651
+      "__id__": 659
     },
     "_skybox": {
-      "__id__": 652
+      "__id__": 660
     },
     "fog": {
-      "__id__": 653
+      "__id__": 661
     },
     "octree": {
-      "__id__": 654
+      "__id__": 662
     },
     "skin": {
-      "__id__": 655
+      "__id__": 663
     },
     "lightProbeInfo": {
-      "__id__": 656
+      "__id__": 664
     },
     "postSettings": {
-      "__id__": 657
+      "__id__": 665
     },
     "bakedWithStationaryMainLight": false,
     "bakedWithHighpLightmap": false

+ 1 - 8
assets/scripts/BallController.ts

@@ -175,7 +175,7 @@ export class BallController extends Component {
         const maxX = this.gameBounds.right - ballRadius - 20;
         const minY = this.gameBounds.bottom + ballRadius + 20;
         const maxY = this.gameBounds.top - ballRadius - 20;
-        
+
         // 获取GameArea节点
         const gameArea = find('Canvas/GameLevelUI/GameArea');
         if (!gameArea) {
@@ -728,13 +728,6 @@ export class BallController extends Component {
                 this.direction.y = currentVelocity.y / speed;
             }
             
-            // 检测小球是否卡住
-            this.lastCheckTime += dt;
-            if (this.lastCheckTime >= this.stuckCheckInterval) {
-                this.lastCheckTime = 0;
-                this.checkIfStuck();
-            }
-            
             // 手动检测墙体碰撞
             this.checkWallCollisions();
         }

File diff suppressed because it is too large
+ 360 - 384
assets/scripts/BlockManager.ts


+ 1 - 1
assets/scripts/BlockManager.ts.meta

@@ -2,7 +2,7 @@
   "ver": "4.0.24",
   "importer": "typescript",
   "imported": true,
-  "uuid": "0872b62e-3a6d-4b39-b85f-ff445865bec2",
+  "uuid": "3a5aea79-7864-4836-8d8c-fcaea3ced452",
   "files": [],
   "subMetas": {},
   "userData": {}

+ 932 - 0
assets/scripts/BlockManager_old.ts

@@ -0,0 +1,932 @@
+import { _decorator, Component, Node, Prefab, instantiate, Vec3, EventTouch, Vec2, UITransform, find, Rect, Label, Color, Size, Contact2DType, Collider2D, IPhysics2DContact } from 'cc';
+const { ccclass, property } = _decorator;
+
+@ccclass('BlockManager')
+export class BlockManager extends Component {
+    // 预制体数组,存储5个预制体
+    @property([Prefab])
+    public blockPrefabs: Prefab[] = [];
+    
+    // 网格容器节点
+    @property({
+        type: Node,
+        tooltip: '拖拽GridContainer节点到这里'
+    })
+    public gridContainer: Node = null;
+    
+    // 方块容器节点(kuang)
+    @property({
+        type: Node,
+        tooltip: '拖拽kuang节点到这里'
+    })
+    public kuangContainer: Node = null;
+    
+    // 金币标签节点
+    @property({
+        type: Node,
+        tooltip: '拖拽CoinLabel节点到这里'
+    })
+    public coinLabelNode: Node = null;
+    
+    // 游戏是否已开始
+    public gameStarted: boolean = false;
+    
+    // 方块移动冷却时间(秒)
+    @property({
+        tooltip: '游戏开始后方块移动的冷却时间(秒)'
+    })
+    public blockMoveCooldown: number = 10;
+    
+    // 玩家金币数量
+    private playerCoins: number = 699;
+    
+    // 方块价格标签映射
+    private blockPriceMap: Map<Node, Node> = new Map();
+    
+    // 已经生成的块
+    private blocks: Node[] = [];
+    // 当前拖拽的块
+    private currentDragBlock: Node | null = null;
+    // 拖拽起始位置
+    private startPos = new Vec2();
+    // 块的起始位置
+    private blockStartPos: Vec3 = new Vec3();
+    // 网格占用情况,用于控制台输出
+    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', 'Price'];
+    // 临时保存方块的原始占用格子
+    private tempRemovedOccupiedGrids: { block: Node, occupiedGrids: { row: number, col: number }[] }[] = [];
+    // 方块原始位置(在kuang中的位置)
+    private originalPositions: Map<Node, Vec3> = new Map();
+    // 方块当前所在的区域
+    private blockLocations: Map<Node, string> = new Map();
+    
+    // 方块移动冷却状态管理
+    private blockCooldowns: Map<Node, number> = new Map(); // 存储每个方块的冷却结束时间
+    private globalCooldownEndTime: number = 0; // 全局冷却结束时间
+    
+    // 检查方块是否可以移动(冷却检查)
+    private canMoveBlock(block: Node): boolean {
+        if (!this.gameStarted) {
+            // 游戏未开始(备战阶段),可以自由移动
+            return true;
+        }
+        
+        const currentTime = Date.now() / 1000; // 转换为秒
+        
+        // 检查全局冷却
+        if (currentTime < this.globalCooldownEndTime) {
+            const remainingTime = Math.ceil(this.globalCooldownEndTime - currentTime);
+            console.log(`方块移动冷却中,剩余时间: ${remainingTime}秒`);
+            return false;
+        }
+        
+        return true;
+    }
+    
+    // 设置方块移动冷却
+    private setBlockCooldown(block: Node) {
+        if (!this.gameStarted) {
+            // 游戏未开始,不设置冷却
+            return;
+        }
+        
+        const currentTime = Date.now() / 1000; // 转换为秒
+        const cooldownEndTime = currentTime + this.blockMoveCooldown;
+        
+        // 设置全局冷却
+        this.globalCooldownEndTime = cooldownEndTime;
+        
+        console.log(`方块移动冷却已设置,持续时间: ${this.blockMoveCooldown}秒`);
+    }
+    
+    // 清除所有冷却(游戏重置时调用)
+    public clearAllCooldowns() {
+        this.blockCooldowns.clear();
+        this.globalCooldownEndTime = 0;
+        console.log('所有方块移动冷却已清除');
+    }
+    
+    start() {
+        // 如果没有指定GridContainer,尝试找到它
+        if (!this.gridContainer) {
+            this.gridContainer = find('Canvas/GameLevelUI/GameArea/GridContainer');
+            if (!this.gridContainer) {
+                console.error('找不到GridContainer节点');
+                return;
+            }
+        }
+        
+        // 如果没有指定kuangContainer,尝试找到它
+        if (!this.kuangContainer) {
+            this.kuangContainer = find('Canvas/GameLevelUI/BlockSelectionUI/diban/kuang');
+            if (!this.kuangContainer) {
+                console.error('找不到kuang节点');
+                return;
+            }
+        }
+        
+        // 如果没有指定coinLabelNode,尝试找到它
+        if (!this.coinLabelNode) {
+            this.coinLabelNode = find('Canvas/GameLevelUI/CoinNode/CoinLabel');
+            if (!this.coinLabelNode) {
+                console.error('找不到CoinLabel节点');
+                return;
+            }
+        }
+        
+        // 确保有PlacedBlocks节点用于存放已放置的方块
+        this.ensurePlacedBlocksNode();
+        
+        // 初始化玩家金币显示
+        this.updateCoinDisplay();
+        
+        // 初始化网格信息
+        this.initGridInfo();
+        
+        // 初始化网格占用情况
+        this.initGridOccupationMap();
+        
+        // 在kuang下随机生成三个方块
+        this.generateRandomBlocksInKuang();
+
+        // 注册碰撞回调
+        const collider = this.getComponent(Collider2D);
+        if (collider) {
+            collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
+            console.log('方块碰撞监听器已注册');
+        }
+    }
+    
+    // 确保有PlacedBlocks节点
+    ensurePlacedBlocksNode() {
+        const canvas = find('Canvas');
+        if (!canvas) {
+            console.error('找不到Canvas节点');
+            return;
+        }
+        
+        let placedBlocksNode = find('Canvas/PlacedBlocks');
+        if (!placedBlocksNode) {
+            placedBlocksNode = new Node('PlacedBlocks');
+            canvas.addChild(placedBlocksNode);
+            if (!placedBlocksNode.getComponent(UITransform)) {
+                placedBlocksNode.addComponent(UITransform);
+            }
+            console.log('已创建PlacedBlocks节点');
+        }
+    }
+    
+    // 初始化网格信息
+    initGridInfo() {
+        if (!this.gridContainer || this.gridInitialized) return;
+        
+        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_')) {
+                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;
+                    }
+                }
+            }
+        }
+        
+        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.gridInitialized = true;
+    }
+    
+    // 初始化网格占用情况
+    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);
+        }
+    }
+    
+    // 在kuang下随机生成三个方块
+    private generateRandomBlocksInKuang() {
+        this.clearBlocks();
+        
+        if (this.blockPrefabs.length === 0) {
+            console.error('没有可用的预制体');
+            return;
+        }
+        
+        const kuangNode = this.kuangContainer;
+        if (!kuangNode) {
+            console.error('找不到kuang节点');
+            return;
+        }
+        
+        const offsets = [
+            new Vec3(-200, 0, 0),
+            new Vec3(0, 0, 0),
+            new Vec3(200, 0, 0)
+        ];
+        
+        const dbNodes = [
+            kuangNode.getChildByName('db01'),
+            kuangNode.getChildByName('db02'),
+            kuangNode.getChildByName('db03')
+        ];
+        
+        console.log('开始在kuang容器中生成随机方块');
+        
+        for (let i = 0; i < 3; i++) {
+            const randomIndex = Math.floor(Math.random() * this.blockPrefabs.length);
+            const prefab = this.blockPrefabs[randomIndex];
+            
+            if (!prefab) {
+                console.error(`方块预制体索引 ${randomIndex} 无效`);
+                continue;
+            }
+            
+            const block = instantiate(prefab);
+            kuangNode.addChild(block);
+            
+            block.position = offsets[i];
+            
+            this.originalPositions.set(block, offsets[i].clone());
+            this.blockLocations.set(block, 'kuang');
+            this.blocks.push(block);
+            
+            if (dbNodes[i]) {
+                const priceNode = dbNodes[i].getChildByName('Price');
+                if (priceNode) {
+                    this.blockPriceMap.set(block, priceNode);
+                    priceNode.active = true;
+                }
+                
+                this.associateDbNodeWithBlock(block, dbNodes[i]);
+            }
+            
+            this.setupDragEvents(block);
+            
+            console.log(`生成方块 ${i + 1}/3: ${prefab.name} 在位置 (${offsets[i].x.toFixed(2)}, ${offsets[i].y.toFixed(2)})`);
+        }
+        
+        console.log(`成功在kuang容器中生成了 ${this.blocks.length} 个方块`);
+        this.updateCoinDisplay();
+    }
+    
+    // 将db节点与方块关联
+    associateDbNodeWithBlock(block: Node, dbNode: Node) {
+        block['dbNode'] = dbNode;
+        
+        block.on(Node.EventType.TRANSFORM_CHANGED, () => {
+            if (dbNode && block.parent) {
+                const location = this.blockLocations.get(block);
+                
+                if (location === 'grid') {
+                    dbNode.active = false;
+                    return;
+                }
+                
+                dbNode.active = true;
+                
+                const worldPos = block.parent.getComponent(UITransform).convertToWorldSpaceAR(block.position);
+                const localPos = dbNode.parent.getComponent(UITransform).convertToNodeSpaceAR(worldPos);
+                
+                dbNode.position = new Vec3(localPos.x, localPos.y - 80, localPos.z);
+            }
+        });
+    }
+    
+    // 更新金币显示
+    updateCoinDisplay() {
+        if (this.coinLabelNode) {
+            const label = this.coinLabelNode.getComponent(Label);
+            if (label) {
+                label.string = this.playerCoins.toString();
+            }
+        }
+    }
+    
+    // 获取方块价格
+    getBlockPrice(block: Node): number {
+        const priceNode = this.blockPriceMap.get(block);
+        if (priceNode) {
+            const label = priceNode.getComponent(Label);
+            if (label) {
+                const price = parseInt(label.string);
+                if (!isNaN(price)) {
+                    return price;
+                }
+            }
+        }
+        return 50;
+    }
+    
+    // 隐藏价格标签
+    hidePriceLabel(block: Node) {
+        const priceNode = this.blockPriceMap.get(block);
+        if (priceNode) {
+            priceNode.active = false;
+        }
+    }
+    
+    // 显示价格标签
+    showPriceLabel(block: Node) {
+        const priceNode = this.blockPriceMap.get(block);
+        if (priceNode) {
+            priceNode.active = true;
+        }
+    }
+    
+    // 扣除玩家金币
+    deductPlayerCoins(amount: number): boolean {
+        if (this.playerCoins >= amount) {
+            this.playerCoins -= amount;
+            this.updateCoinDisplay();
+            return true;
+        }
+        return false;
+    }
+    
+    // 归还玩家金币
+    refundPlayerCoins(amount: number) {
+        this.playerCoins += amount;
+        this.updateCoinDisplay();
+    }
+    
+    // 设置拖拽事件
+    setupDragEvents(block: Node) {
+        block.on(Node.EventType.TOUCH_START, (event: EventTouch) => {
+            if (this.gameStarted && this.blockLocations.get(block) === 'grid') {
+                if (!this.canMoveBlock(block)) {
+                    return;
+                }
+            }
+            
+            this.currentDragBlock = block;
+            this.startPos = event.getUILocation();
+            this.blockStartPos.set(block.position);
+            this.currentDragBlock['startLocation'] = this.blockLocations.get(block);
+            
+            block.setSiblingIndex(block.parent.children.length - 1);
+            this.tempStoreBlockOccupiedGrids(block);
+        }, this);
+        
+        block.on(Node.EventType.TOUCH_MOVE, (event: EventTouch) => {
+            if (this.gameStarted && this.blockLocations.get(block) === 'grid') {
+                if (!this.canMoveBlock(block)) {
+                    return;
+                }
+            }
+            
+            if (!this.currentDragBlock) return;
+            
+            const location = event.getUILocation();
+            const deltaX = location.x - this.startPos.x;
+            const deltaY = location.y - this.startPos.y;
+            
+            this.currentDragBlock.position = new Vec3(
+                this.blockStartPos.x + deltaX,
+                this.blockStartPos.y + deltaY,
+                this.blockStartPos.z
+            );
+        }, this);
+        
+        block.on(Node.EventType.TOUCH_END, (event: EventTouch) => {
+            if (this.gameStarted && this.blockLocations.get(block) === 'grid') {
+                if (!this.canMoveBlock(block)) {
+                    return;
+                }
+            }
+            
+            if (this.currentDragBlock) {
+                this.handleBlockDrop(event);
+                
+                // 如果成功移动且游戏已开始,设置冷却
+                if (this.gameStarted && this.blockLocations.get(this.currentDragBlock) === 'grid') {
+                    this.setBlockCooldown(this.currentDragBlock);
+                }
+                
+                this.currentDragBlock = null;
+            }
+        }, this);
+        
+        block.on(Node.EventType.TOUCH_CANCEL, () => {
+            if (this.currentDragBlock) {
+                this.returnBlockToOriginalPosition();
+                this.currentDragBlock = null;
+            }
+        }, this);
+    }
+    
+    // 处理方块放下
+    handleBlockDrop(event: EventTouch) {
+        const touchPos = event.getUILocation();
+        const startLocation = this.currentDragBlock['startLocation'];
+        
+        if (this.isInKuangArea(touchPos)) {
+            this.returnBlockToKuang(startLocation);
+        } else if (this.tryPlaceBlockToGrid(this.currentDragBlock)) {
+            this.handleSuccessfulPlacement(startLocation);
+        } else {
+            this.returnBlockToOriginalPosition();
+        }
+    }
+    
+    // 返回方块到kuang区域
+    returnBlockToKuang(startLocation: string) {
+        const originalPos = this.originalPositions.get(this.currentDragBlock);
+        if (originalPos) {
+            const kuangNode = this.kuangContainer;
+            if (kuangNode && this.currentDragBlock.parent !== kuangNode) {
+                this.currentDragBlock.removeFromParent();
+                kuangNode.addChild(this.currentDragBlock);
+            }
+            
+            this.currentDragBlock.position = originalPos.clone();
+        }
+        
+        this.restoreBlockOccupiedGrids(this.currentDragBlock);
+        this.blockLocations.set(this.currentDragBlock, 'kuang');
+        this.showPriceLabel(this.currentDragBlock);
+        
+        if (startLocation === 'grid') {
+            const price = this.getBlockPrice(this.currentDragBlock);
+            this.refundPlayerCoins(price);
+            this.currentDragBlock['placedBefore'] = false;
+        }
+        
+        const dbNode = this.currentDragBlock['dbNode'];
+        if (dbNode) {
+            dbNode.active = true;
+            this.currentDragBlock.emit(Node.EventType.TRANSFORM_CHANGED);
+        }
+    }
+    
+    // 处理成功放置
+    handleSuccessfulPlacement(startLocation: string) {
+        const price = this.getBlockPrice(this.currentDragBlock);
+        
+        if (startLocation === 'grid') {
+            this.clearTempStoredOccupiedGrids(this.currentDragBlock);
+            this.blockLocations.set(this.currentDragBlock, 'grid');
+            this.hidePriceLabel(this.currentDragBlock);
+            
+            const dbNode = this.currentDragBlock['dbNode'];
+            if (dbNode) {
+                dbNode.active = false;
+            }
+            
+            if (this.gameStarted) {
+                this.moveBlockToPlacedBlocks(this.currentDragBlock);
+            }
+        } else {
+            if (this.deductPlayerCoins(price)) {
+                this.clearTempStoredOccupiedGrids(this.currentDragBlock);
+                this.blockLocations.set(this.currentDragBlock, 'grid');
+                this.hidePriceLabel(this.currentDragBlock);
+                
+                const dbNode = this.currentDragBlock['dbNode'];
+                if (dbNode) {
+                    dbNode.active = false;
+                }
+                
+                this.currentDragBlock['placedBefore'] = true;
+                
+                if (this.gameStarted) {
+                    this.moveBlockToPlacedBlocks(this.currentDragBlock);
+                }
+            } else {
+                this.returnBlockToOriginalPosition();
+            }
+        }
+    }
+    
+    // 返回方块到原位置
+    returnBlockToOriginalPosition() {
+        const currentLocation = this.blockLocations.get(this.currentDragBlock);
+        if (currentLocation === 'kuang') {
+            const originalPos = this.originalPositions.get(this.currentDragBlock);
+            if (originalPos) {
+                this.currentDragBlock.position = originalPos.clone();
+            }
+        } else {
+            this.currentDragBlock.position = this.blockStartPos.clone();
+        }
+        
+        this.restoreBlockOccupiedGrids(this.currentDragBlock);
+        this.showPriceLabel(this.currentDragBlock);
+        
+        const dbNode = this.currentDragBlock['dbNode'];
+        if (dbNode) {
+            dbNode.active = true;
+            this.currentDragBlock.emit(Node.EventType.TRANSFORM_CHANGED);
+        }
+    }
+    
+    // 检查是否在kuang区域内
+    isInKuangArea(touchPos: Vec2): boolean {
+        if (!this.kuangContainer) return false;
+        
+        const kuangTransform = this.kuangContainer.getComponent(UITransform);
+        if (!kuangTransform) return false;
+        
+        const kuangBoundingBox = new Rect(
+            this.kuangContainer.worldPosition.x - kuangTransform.width * kuangTransform.anchorX,
+            this.kuangContainer.worldPosition.y - kuangTransform.height * kuangTransform.anchorY,
+            kuangTransform.width,
+            kuangTransform.height
+        );
+        
+        return kuangBoundingBox.contains(new Vec2(touchPos.x, touchPos.y));
+    }
+    
+    // 临时保存方块占用的网格
+    tempStoreBlockOccupiedGrids(block: Node) {
+        const occupiedGrids = block['occupiedGrids'];
+        if (!occupiedGrids || occupiedGrids.length === 0) return;
+        
+        this.tempRemovedOccupiedGrids.push({
+            block: block,
+            occupiedGrids: [...occupiedGrids]
+        });
+        
+        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['occupiedGrids'] = [];
+    }
+    
+    // 恢复方块原来的占用状态
+    restoreBlockOccupiedGrids(block: Node) {
+        const index = this.tempRemovedOccupiedGrids.findIndex(item => item.block === block);
+        if (index === -1) return;
+        
+        const savedItem = this.tempRemovedOccupiedGrids[index];
+        
+        for (const grid of savedItem.occupiedGrids) {
+            if (grid.row >= 0 && grid.row < this.GRID_ROWS && 
+                grid.col >= 0 && grid.col < this.GRID_COLS) {
+                this.gridOccupationMap[grid.row][grid.col] = 1;
+            }
+        }
+        
+        block['occupiedGrids'] = [...savedItem.occupiedGrids];
+        this.tempRemovedOccupiedGrids.splice(index, 1);
+    }
+    
+    // 清除临时保存的占用状态
+    clearTempStoredOccupiedGrids(block: Node) {
+        const index = this.tempRemovedOccupiedGrids.findIndex(item => item.block === block);
+        if (index === -1) return;
+        
+        this.tempRemovedOccupiedGrids.splice(index, 1);
+    }
+    
+    // 尝试将方块放置到网格中
+    tryPlaceBlockToGrid(block: Node): boolean {
+        if (!this.gridContainer || !this.gridInitialized) return false;
+        
+        let b1Node = block;
+        if (block.name !== 'B1') {
+            b1Node = block.getChildByName('B1');
+            if (!b1Node) {
+                return false;
+            }
+        }
+        
+        const b1WorldPos = b1Node.parent.getComponent(UITransform).convertToWorldSpaceAR(b1Node.position);
+        const gridPos = this.gridContainer.getComponent(UITransform).convertToNodeSpaceAR(b1WorldPos);
+        
+        const gridSize = this.gridContainer.getComponent(UITransform).contentSize;
+        const halfWidth = gridSize.width / 2;
+        const halfHeight = gridSize.height / 2;
+        
+        const tolerance = this.gridSpacing * 0.5;
+        if (gridPos.x < -halfWidth - tolerance || gridPos.x > halfWidth + tolerance || 
+            gridPos.y < -halfHeight - tolerance || gridPos.y > halfHeight + tolerance) {
+            return false;
+        }
+        
+        const nearestGrid = this.findNearestGridNode(gridPos);
+        if (!nearestGrid) {
+            return false;
+        }
+        
+        return this.tryPlaceBlockToSpecificGrid(block, nearestGrid);
+    }
+    
+    // 找到最近的网格节点
+    findNearestGridNode(position: Vec3): Node {
+        if (!this.gridContainer || !this.gridInitialized) return null;
+        
+        let nearestNode: Node = null;
+        let minDistance = Number.MAX_VALUE;
+        
+        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 > this.gridSpacing * 2) {
+            return null;
+        }
+        
+        return nearestNode;
+    }
+    
+    // 尝试将方块放置到指定的网格节点
+    tryPlaceBlockToSpecificGrid(block: Node, targetGrid: Node): boolean {
+        let b1Node = block;
+        if (block.name !== 'B1') {
+            b1Node = block.getChildByName('B1');
+            if (!b1Node) {
+                return false;
+            }
+        }
+        
+        if (!this.canPlaceBlockAt(block, targetGrid)) {
+            return false;
+        }
+        
+        const gridCenterWorldPos = this.gridContainer.getComponent(UITransform).convertToWorldSpaceAR(targetGrid.position);
+        const targetWorldPos = gridCenterWorldPos.clone();
+        
+        const b1LocalPos = b1Node.position.clone();
+        
+        let rootTargetWorldPos;
+        if (b1Node === block) {
+            rootTargetWorldPos = targetWorldPos.clone();
+        } else {
+            rootTargetWorldPos = new Vec3(
+                targetWorldPos.x - b1LocalPos.x,
+                targetWorldPos.y - b1LocalPos.y,
+                targetWorldPos.z
+            );
+        }
+        
+        const rootTargetLocalPos = block.parent.getComponent(UITransform).convertToNodeSpaceAR(rootTargetWorldPos);
+        
+        block.position = rootTargetLocalPos;
+        this.markOccupiedPositions(block, targetGrid);
+        
+        return true;
+    }
+    
+    // 检查方块是否可以放置在指定位置
+    canPlaceBlockAt(block: Node, targetGrid: Node): boolean {
+        if (!this.gridInitialized) return false;
+        
+        const targetRowCol = this.getGridRowCol(targetGrid);
+        if (!targetRowCol) return false;
+        
+        const parts = this.getBlockParts(block);
+        
+        for (const part of parts) {
+            const row = targetRowCol.row - part.y;
+            const col = targetRowCol.col + part.x;
+            
+            if (row < 0 || row >= this.GRID_ROWS || col < 0 || col >= this.GRID_COLS) {
+                return false;
+            }
+            
+            if (this.gridOccupationMap[row][col] === 1) {
+                return false;
+            }
+        }
+        
+        return true;
+    }
+    
+    // 获取网格行列索引
+    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;
+    }
+    
+    // 获取方块的所有部分节点及其相对坐标
+    getBlockParts(block: Node): { node: Node, x: number, y: number }[] {
+        const parts: { node: Node, x: number, y: number }[] = [];
+        
+        parts.push({ node: block, x: 0, y: 0 });
+        this.findBlockParts(block, parts, 0, 0);
+        
+        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.NON_BLOCK_NODES.indexOf(child.name) !== -1) {
+                continue;
+            }
+            
+            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 });
+            } else if (child.name.startsWith('B')) {
+                const relativeX = Math.round(child.position.x / this.gridSpacing);
+                const relativeY = -Math.round(child.position.y / this.gridSpacing);
+                
+                x = parentX + relativeX;
+                y = parentY + relativeY;
+                
+                result.push({ node: child, x, y });
+            }
+            
+            this.findBlockParts(child, result, x, y);
+        }
+    }
+    
+    // 标记方块占用的格子
+    markOccupiedPositions(block: Node, targetGrid: Node) {
+        if (!this.gridInitialized) return;
+        
+        const targetRowCol = this.getGridRowCol(targetGrid);
+        if (!targetRowCol) return;
+        
+        const parts = this.getBlockParts(block);
+        
+        block['occupiedGrids'] = [];
+        
+        for (const part of parts) {
+            const row = targetRowCol.row - part.y;
+            const col = targetRowCol.col + part.x;
+            
+            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 });
+            }
+        }
+    }
+    
+    // 清除方块
+    clearBlocks() {
+        const blocksToRemove = [];
+        
+        for (const block of this.blocks) {
+            if (block.isValid) {
+                const location = this.blockLocations.get(block);
+                if (location === 'kuang') {
+                    blocksToRemove.push(block);
+                }
+            }
+        }
+        
+        for (const block of blocksToRemove) {
+            const dbNode = block['dbNode'];
+            if (dbNode && dbNode.isValid) {
+                block.off(Node.EventType.TRANSFORM_CHANGED);
+                
+                const kuangNode = this.kuangContainer;
+                if (kuangNode) {
+                    const dbName = dbNode.name;
+                    if (!kuangNode.getChildByName(dbName)) {
+                        dbNode.parent = kuangNode;
+                    }
+                }
+            }
+            
+            const index = this.blocks.indexOf(block);
+            if (index !== -1) {
+                this.blocks.splice(index, 1);
+            }
+            
+            this.originalPositions.delete(block);
+            this.blockLocations.delete(block);
+            this.blockPriceMap.delete(block);
+            
+            block.destroy();
+        }
+    }
+    
+    // 游戏开始时调用
+    onGameStart() {
+        this.gameStarted = true;
+        console.log('游戏已开始,已放置的方块将有移动冷却时间');
+        
+        for (const block of this.blocks) {
+            if (block.isValid) {
+                const location = this.blockLocations.get(block);
+                
+                if (location === 'grid') {
+                    this.hidePriceLabel(block);
+                    
+                    const dbNode = block['dbNode'];
+                    if (dbNode) {
+                        dbNode.active = false;
+                    }
+                    
+                    this.moveBlockToPlacedBlocks(block);
+                    this.addLockedVisualHint(block);
+                }
+            }
+        }
+    }
+    
+    // 游戏重置时调用
+    onGameReset() {
+        this.gameStarted = false;
+        this.clearAllCooldowns();
+        console.log('游戏已重置,方块可以自由移动');
+    }
+    
+    // 添加视觉提示,表明方块已锁定
+    addLockedVisualHint(block: Node) {
+        const children = block.children;
+        for (let i = 0; i < children.length; i++) {
+            const child = children[i];
+            if (this.NON_BLOCK_NODES.indexOf(child.name) !== -1) {
+                continue;
+            }
+            
+            child.setScale(new Vec3(0.95, 0.95, 1));
+        }
+        
+        console.log(`已为方块 ${block.name} 添加锁定视觉提示`);
+    }
+    
+    // 将方块移动到PlacedBlocks节点下
+    moveBlockToPlacedBlocks(block: Node) {
+        const placedBlocksNode = find('Canvas/PlacedBlocks');
+        if (!placedBlocksNode) {
+            console.error('找不到PlacedBlocks节点');
+            return;
+        }
+        
+        const worldPosition = new Vec3();
+        block.getWorldPosition(worldPosition);
+        
+        block.removeFromParent();
+        placedBlocksNode.addChild(block);
+        block.setWorldPosition(worldPosition);
+        
+        console.log(`已将方块 ${block.name} 移动到PlacedBlocks节点下`);
+    }
+
+    // 碰撞回调
+    onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
+        console.log('方块碰到了:', otherCollider.node.name);
+        if (otherCollider.node.name === 'Ball') {
+            console.log('方块被球击中!');
+        }
+    }
+}

+ 9 - 0
assets/scripts/BlockManager_old.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "f9710fd2-b600-48b9-9f3d-f23ffa21f789",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 9 - 0
assets/scripts/BlockManager_temp.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "9bbe0dda-d48c-46c2-9b51-d7ac0c11f47c",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 1 - 1
assets/scripts/GameManager.ts

@@ -1,6 +1,6 @@
 import { _decorator, Component, Node, Prefab, instantiate, Vec3, find, director, Canvas, UITransform, Button, Label } from 'cc';
+import { BlockManager } from './BlockManager';
 const { ccclass, property } = _decorator;
-
 @ccclass('GameManager')
 export class GameManager extends Component {
     @property({

Some files were not shown because too many files changed in this diff